I have a view controller that creates ObjectA. ObjectA then creates ObjectB. ObjectB needs to get some values from the view controller (i need values that can change after creation of the objects).
I’m trying to figure out the best way to retrieve the values. My first thought was with protocols. I have only created protocols within an object so far:
#import <UIKit/UIKit.h>
@protocol AnalysisTypeTableDelegate;
@interface AnalysisTypeTableViewController : UITableViewController
@property (weak, nonatomic) id <AnalysisTypeTableDelegate> delegate;
@property (strong, nonatomic) NSArray *dataSource;
@property (nonatomic) BOOL allowRefresh;
@end
@protocol AnalysisTypeTableDelegate <NSObject>
-(void)returnAnalysisType:(NSString *)type;
@end
how can i create protocol class (such as create new file, objective-c protocol)?
Then how do I link them together? ObjectA has a protocol, do i do something like:
// View controller and objectB both conform to myProtocol
// view controller creates objectA
myObjectA.delegate = self
// when objectA creates objectB
myObjectB.delegate = self.delegate
Or is there a better way to retrieve the values i need?
EDIT:
I think I’ll need to do something like this:
objectA’s protocol:
@protocol objectADelegate
-(NSDictionary)requestViewController;
@end
objectB’s protocols:
@protocol objectBDelegate
-(NSDictionary *)requestObjectA;
-(void)updateList:(NSSarray *)list;
@end
in myObjectB
-(NSDictionary *)requestObjectA {
NSDictionary *extents = [self.delegate requestObjectA];
}
-(void)serverCall {
// make server call, get list
...
// update myObjectA with new list
[self.delegate updateList:newList];
in myObjectA
-(NSDictionary *)requestObjectA {
return [self.delegate requestViewController];
}
-(void)updateList:(NSArray)list {
// updates list
}
in view controller
-(NSDictionary *)requestViewController;
return self.mapkit.exents;
}
I assume you’re saying that this is called from your view controller:
And that you’re calling the following line from object A:
Technically, you can do that, though I find that construct a little confusing. And it’s even a little problematic, because you don’t provide any mechanism for the view controller to say “ok, I don’t want to be a
delegateanymore”, because it presumably only knows aboutmyObjectA. You don’t have any mechanism for the view controller to tellmyObjectBthat it doesn’t want to be itsdelegateany more, because presumably the view controller doesn’t even know ofB‘s existence.Use Model-View-Controller pattern
The notion of
delegateis one of “I want to tell mydelegatesomething, or make some request of it”. If your goal, on the other hand, is to share data amongst them, I’d be inclined to shift away from the delegate-protocol pattern, and to a model-view-controller (MVC) pattern, and we’ll focus on the “model” portion:Create a
Modelclass to holds the model data;Have the view controller instantiate a
Modelclass object;Pass pointers to the
Modelobject from one view controller or object to the next (or otherwise make this model object accessible to other classes, via, for example, a singleton pattern, an app delegate property, etc.);Make sure your
Modelclass has properties associated with data being maintained (that way, other classes can use the accessor methods thatModelwill synthesize for you).This is conceptually very similar to what you’ve outlined with your
delegatepointers, but doesn’t carry the implications thatdelegatedoes, namely that you’re not only accessing data, but rather you can tell the controller to do something. In a delegate-protocol pattern, the delegate should generally have the ability to opt out of being adelegateat any point.Different approaches to handling changes in model data
There are several approaches for reflecting the change to a model object in other objects (e.g. to tell the view controller that model data has changed and it must reflect that change). These include:
Use delegates. This is probably the worst of the approaches that I’m listing here because if you want to tell multiple objects about the change in the model data, you have to have multiple delegates (or an array of them). This is a poor use of delegates.
Reload upon
viewDidAppear. If you’re only dealing with making sure that view controllers update their views to reflect data that changed on another view controller, you can just refresh the view when it appears again. This is the most primitive solution, and only works if you’re dealing with view controllers that are reappearing after, for example, a modal view that altered the data has been dismissed. This is, in those simple cases, often the easiest solution.Register for notifications through the
NSNotificationCenter. This has the beauty that multiple objects can add themselves as an observer to the same notification. For example, define a key for your notification in your .m file:Then, define an external reference to that key in your .h file:
Then, the object that wants to be notified of the change can register for that notification:
Obviously, you have to write that “handler” method:
Finally, whatever updates that model field can post the notification, e.g.:
If you do this, you just need to make sure that when the object that registered for the notification is going out of scope, it must also unregister for that notification:
Use key value observing. Again, multiple objects can register to be an observer of your model’s properties. Let’s assume that you have defined three properties (via
@property) for yourModelobject. Any object that wants to be notified of changes can add themselves as an observer of those properties, e.g.:You then just need to write an
observeValueForKeyPathmethod:The only thing that’s tricky here is that if one of the objects is a collection (e.g. a
NSMutableArray), you have to write collection accessors. See that document for more examples. For example, though, I have a model that has a property that is an array of pet names,NSMutableArray *petNames. Thus, I had to write the following two methods for my model:And instead of ever calling
[self.model.petNames addObject:aPetName], I called[self.model insertObject:aPetName inPetNamesAtIndex:0];instead (and by doing that, the notifications take place automatically).In short, if you have multiple objects that have to be notified of a change in your model data, I think that key-value-observing is the most elegant approach, but it takes a little time to get your arms around it if dealing with collections. I think that just posting notification is a relatively simple alternative.
References: