2009-07-14 28 views
23

Ứng dụng của tôi là một ứng dụng thanh tab, với bộ điều khiển chế độ xem riêng biệt cho mỗi tab.Làm thế nào để chia sẻ một đối tượng giữa UIViewControllers trên iPhone?

Tôi có một đối tượng trong bộ điều khiển xem đầu tiên (A) chứa tất cả dữ liệu ứng dụng đã lưu trữ của tôi (Vui lòng bỏ qua NSUserDefaults cho điều này) cần truy cập bằng bộ điều khiển xem thứ hai (B) khi tôi nhấn một nút trên đó . Làm thế nào tôi có thể đạt được điều này theo cách tốt nhất?

+0

Câu hỏi này rất giống với một câu hỏi mà tôi hỏi: http://stackoverflow.com/questions/1053704/organizing -instance-variables-in-a-view-hierarchy – titaniumdecoy

+2

Đúng. Bạn không thể đổ lỗi cho tôi vì không tìm thấy nó mặc dù. Nó được diễn đạt hoàn toàn khác. –

Trả lời

32

Một tùy chọn bạn có là khai báo mô hình ngày của bạn dưới dạng biến mẫu của đại biểu ứng dụng của bạn (như được đề cập bởi những người nhận xét khác).

Thay vì tham chiếu ứng dụng đại biểu theo đề xuất của nevan, thay thế là thêm thuộc tính vào các lớp trình điều khiển chế độ xem (A và B) cho mô hình dữ liệu của bạn.

Giả sử bạn muốn chia sẻ một đối tượng mô hình dữ liệu giữa các bộ điều khiển xem của bạn, bạn có thể thêm một tài sản với nhau:

@interface AViewController : UIViewController { 
    MyDataModel *model; 
} 

@property (nonatomic, retain) MyDataModel *model; 

@end 

@interface BViewController : UIViewController { 
    MyDataModel *model; 
} 

@property (nonatomic, retain) MyDataModel *model; 

@end 

Khi bạn khởi khiển tầm nhìn của bạn sau đó bạn có thể thiết lập thuộc tính này với bối cảnh đối tượng được khởi tạo trước đó .

Bạn đã đề cập đến bộ điều khiển thanh tab. Nếu bộ điều khiển xem của bạn đang có dây thông qua IB tất cả các bạn phải làm là để thiết lập các thông số trong phương pháp ứng dụng đại biểu applicationDidFinishLaunching: của bạn, trước khi điều khiển thanh tab được hiển thị:

@interface MyAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> 
{ 

    MyDataModel *model; 
    AViewController *aViewController; 
    BViewController *bViewController; 
    ... 
} 

@property (retain) IBOutlet AViewController *aViewController; 
@property (retain) IBOutlet BViewController *aViewController; 

@end 

@implementation MyAppDelegate 

... 

- (void)applicationDidFinishLaunching:(UIApplication *)application 
{ 
... 

    aViewController.model = model; 

    bViewController.model = model; 

    [window addSubview:tabBarController.view]; 
    [window makeKeyAndVisible]; 
} 

Đừng quên để phát hành các mô hình trong bạn xem phương pháp dealloc của bộ điều khiển.


Cách khác là sử dụng đối tượng đơn lẻ. Một ví dụ đơn giản singleton:

@interface MyDataModel : NSObject 
{ 
} 

+ (MyDataModel *) sharedDataModel; 

@end 

@implementation MyDataModel 

static MyDataModel *sharedDataModel = nil; 

+ (MyDataModel *) sharedDataModel 
{ 

    @synchronized(self) 
    { 
     if (sharedDataModel == nil) 
     { 
      sharedDataModel = [[MyDataModel alloc] init]; 
     } 
    } 
    return sharedDataModel; 
} 

@end 

Bạn có thể truy cập vào mô hình dữ liệu này từ tất cả các bộ điều khiển xem của bạn với một cái gì đó tương tự như sau:

MyDataModel *model = [MyDataModel sharedDataModel]; 

Xem thêm this chồng thảo luận tràn về độc thân.

+1

Tôi thực sự thích câu trả lời này. Sử dụng con trỏ để tham khảo mô hình dữ liệu từ AppDelegate có vẻ sạch hơn rất nhiều so với sử dụng Singleton. Phương pháp này cũng có vẻ giữ cho khớp nối ở mức tối thiểu. Cảm ơn. –

+0

Xem ngay bây giờ tôi đã sử dụng một trong hai phương pháp này. Nhưng chỉ để gây nhầm lẫn cho tôi, Bài giảng số 7 của Đại học Stanford cho biết cả hai đều không có gì! Hãy xem: http://deimos3.apple.com/WebObjects/Core.woa/Feed/itunes.stanford.edu.3124430053.03124430055 sau khoảng 30 phút.Dù sao, tôi sẽ sử dụng một singleton: P – jowie

+0

Sau khi xem bài giảng 7 mà bạn đang đề cập đến, tôi tin rằng anh ấy (Josh Shaffer) đang ủng hộ cách tiếp cận đầu tiên ở đây. Bạn chắc chắn đúng rằng anh ấy không khuyên bạn nên sử dụng singleton vì nó chỉ là một loại trạng thái toàn cầu khác. Khi ông đề nghị không sử dụng ứng dụng đại biểu, tôi nghĩ rằng ông đã đề cập đến việc truy cập ứng dụng ủy nhiệm tĩnh và nhận dữ liệu của bạn thông qua đó. Ví dụ của ông về cách thực hiện nó, tôi nghĩ rất gần với cách tiếp cận đầu tiên của szzsolt ở trên. Chỉ cần vượt qua chính xác những gì bộ điều khiển xem của bạn cần. – greggian

0

Cả hai bộ điều khiển chế độ xem nên tham chiếu đối tượng thứ ba (C) làm nguồn dữ liệu của chúng; đối tượng này (C) có chứa tất cả các dữ liệu ứng dụng được lưu trữ.

C sẽ là, trong trường hợp này, M trong MVC.

Thêm vào mỗi ViewControllers bạn tờ khai sau:

// SomeViewController.h 
// Before @interface 

@class MyDataSource; 

// In the interface 

IBOutlet MyDataSource *datasource; 
@property(retain) IBOutlet MyDataSource *datasource; 
+0

Chính xác. Vì vậy, làm thế nào để tôi làm điều đó? Tôi nên lưu trữ mô hình dữ liệu của mình ở đâu và làm cách nào tôi có thể truy cập theo đúng cách để tuân thủ MVC từ cả hai ViewControllers. –

8

Cách phổ biến nhất mà tôi đã thấy điều này là để thiết lập điều bạn muốn truy cập vào các đại biểu ứng dụng và tham khảo nó ở những nơi khác như thế này:

MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate]; 
myStuff = appDelegate.stuff; 

Trong ứng dụng, hãy thiết lập biến số và sử dụng @property và @synthesize như thường lệ.

Một số người nói rằng đó không phải là một cách tiếp cận tốt, vì nó giống như sử dụng các biến toàn cầu, nhưng nó rất phổ biến.

+1

Sử dụng singleton cũng là một cách tiếp cận phổ biến. – titaniumdecoy

+0

Tôi không hiểu tại sao câu trả lời được chấp nhận lại tốt hơn. Tôi đã sử dụng rộng rãi một cách tiếp cận tương tự trước đây nhưng nó chỉ cho tôi một sự phức tạp thêm. Vượt qua các đối tượng qua lại chỉ là một cơn đau đầu. +1 – Tibidabo

+1

@Tibidabo: vì việc giữ dữ liệu trong 'appDelegate' được coi là thực tế không tốt (từ điểm OOP & mã có thể sử dụng lại được). Khác: như một giải pháp nhanh chóng và dơ bẩn, câu trả lời này là hoàn hảo o.k. –

5

Tôi thích tạo lớp Mô hình cấp cao nhất là một singleton và chứa tất cả các yếu tố tôi có thể cần. Bạn cũng có thể cung cấp cho nó phương thức tải ở mức cao nhất để điền các đối tượng chỉ bằng các khóa db, sử dụng mẫu hydrate/dehydrate chung trong các ví dụ của Apple.

Điển hình sử dụng trong các đại biểu ứng dụng sẽ là cách đơn giản,

[[MyModel sharedModel] load]; 

Và sau đó trong một bộ điều khiển xem:

NSArray *myThing1s = [[MyModel sharedModel] thing1s]; 
NSArray *myThing2s = [[MyModel sharedModel] thing2s]; 

Sau đó bạn có thể duyệt qua thing1s và thing2s của bạn và khi bạn cần chi tiết, bạn chỉ có thể gọi

[myThing1 hydrate]; 

sẽ điền đối tượng.

Tất nhiên, bạn có thể muốn sử dụng CoreData để quản lý sự kiên trì từ 3.0 trở đi.

+0

Bạn có thể đăng một ví dụ đơn trong Mục tiêu-C mà tôi có thể sử dụng không? Tôi đang nghiêng về phía này, có vẻ tốt hơn một chút so với quyền truy cập của Đại biểu. –

3

Tôi luôn tạo một đối tượng đặc biệt được gọi là DataModel và sử dụng nó là singleton sharedInstance.

Và đối tượng này sau đó giữ tất cả dữ liệu liên quan đến ứng dụng. Không cần truy cập sợ hãiappDelegate.

DataModel.h

#import <Foundation/Foundation.h> 

@class MyClass1, MyClass2; 

@interface DataModel : NSObject 

@property (copy, nonatomic) NSString *aString; 
@property (assign) BOOL aBool; 

@property (strong) MyClass1 *myObject1; 
@property (strong) MyClass2 *myObject2; 

+ (DataModel *)sharedModel; 

@end 

DataModel.m

#import "DataModel.h" 
#import "Class1.h" 
#import "Class2.h" 

@implementation DataModel 

- (id) init 
{ 
    self = [super init]; 
    if (self) 
    { 
     _myObject1 = [[MyClass1 alloc] init]; 
     _myObject2 = [[MyClass2 alloc] init]; 
     aBool = NO; 
     aString = nil; 
    } 
    return self; 
} 

+ (DataModel *)sharedModel 
{ 
    static DataModel *_sharedModel = nil; 
    static dispatch_once_t onceSecurePredicate; 
    dispatch_once(&onceSecurePredicate,^ 
        { 
         _sharedModel = [[self alloc] init]; 
        }); 

    return _sharedModel; 
} 

@end 

Và (bacause tôi là lười biếng) tôi đặt DataModel.h trong application-prefix.pch.

Bằng cách đó tôi có thể truy cập vào dữ liệu của tôi từ bất cứ nơi nào trong ứng dụng chỉ đơn giản bằng cách gọi

[DataModel sharedModel] 
+1

Tôi đã sử dụng phương pháp này với thành công lớn. –

Các vấn đề liên quan