i've to pass data from the third viewController to the rootViewController in a navigationController.
I think to do in this way:
A = rootViewController and B = lastViewController
In B i insert a method like this:
-(void)load:(A father)f
{
self.father = f; // where father is a retain property
}
then when i alloc B in A, before push it i will call load method.
Will it work?
Other way to this operation? (also global variables and singleton, i don't want these 2 because i've a lot of data in memory).
Thanks for any help.
Some say singletons are evil, but I think they fill a purpose - but in your case I would go with delegation. Thats IMO the best way to handle data between controllers and models.
Long and more appropriate way: Protocol and delegation
your rootViewController B will have to implement a protocol, then in your lastViewController you will have to declare a delegate of that protocol, then call something like lastViewController.myDelegate = myParent;
this is useful if you want to modularize your components, but based on experience, some classes are very specific with its function and creating a protocol just prolongs the process of doing this basic need of transferring data. In this case, I suggest you use #2.
Short Way: What you said
...but I prefer to pass the parent class on the initialization. I.e. initWithParent: [myParent], but that's just me. Also DO NOT retain the parent from a child classes. Only parent class are allowed to retain its child, else you'll have a memory management problem. Disadvantage of this approach is that if your controllers get complicated, it will be very hard to separate their logic later just in case you need to separate them, like re-using one component in another project.
Related
Following the MVC pattern stressed in various Objective-C programming guides, when I use Model with Controller, I should set the Controller as the delegate of the given Model. Now I have a huge Data object that's very expensive to create, and there're a few Controllers that need to work with this Data object. As long as the delegate property is set to the right Controller the Data object will work fine for THAT controller. Is there a way to share this model among these controllers?
I've brainstormed for a while, but haven't thought of any especially good solutions. A few things that I've come up
use notification center (but it seems expensive to set up such a relationship just for this specific case)
make each method of the Data object take a delegate argument: this is what I'm currently using now, but it is clunky and is reaching its limit
Edit
Thanks for people who have suggested to me using an NSArray. I think I forget to include this subtlty:
For my case say one of the delegates, A, wants to query the Data object by using one of its specific methods. The result would be correct if the delegate field of the Data object is set to A. But from what I understand using an array and calling the method on every delegate wouldn't give me the answer I want.
In fact since my Data object couldn't know which delegate is calling it, it can't give back the correct result even if it knows about all the delegates it should be associated with
Any thought on this?
You could make an NSArray with delegates and then just call the method on every delegate in your array. (Watch out for retain cycles).
If you don't want to use notifications you can try using a multicast delegate approach. In this you would keep an NSMutableArray of delegates instead of a single one. So instead of setting the delegate you would add and remove delegates from your delegate array. When calling a delegate you would then call that delegate method on each delegate in the array, checking each one if it response to that particular callback.
You can also control the order the delegates are called in if you so wish since you create and manage the delegate array yourself.
What I ended up doing is setting up another level of indirection - each Controller will be communicating with a 'middleware' object, which in turn communicates with the Data object. In this way, the common delegate-delegatee approach is preserved while the Data object only needs to be created once - at the expense of added 'middleman' object for each Controller.
In my example, the 'middleware' object will have a Controller set as its delegate property, and when that Controller wants to know information about the Data object, the 'middleware' object will then use its delegate property to query information from the Data object.
Is it ok to have two objects as delgates of each other..? My scenario is that I have a view which is shown in two modes.. first: Create mode and second: Edit mode
In Create Mode all the fields are empty and I take data from the view which is filled in by the user and I update my data model.
And In View Mode I fill up the view from my data model.
This is being done using a spilt view controller(because of this I am forced to use delegation). I wish I could explain this better but this is the best I can do. As of now I am using delegation to communicate from A to B and Notification from B to A.
Would this work fine if I use delegation in both ways... or are there any complexities involved which I can't foresee?
There are a few problems that could occur, but if you take the necessary precautions, it will be fine:
Ensure both delegates are weak referenced. This means using #property (weak) on ARC or #property (assign). This will prevent retain cycles from occurring.
Ensure you don't get into a situation where a delegate method calls the delegate method of the other controller, which calls the same delegate method in the first controller and so on. You could easily get an infinite loop if you are not careful.
A discussion or debate on whether or not this is the best design pattern in this situation is not really something that belongs on SO. But doing it this way is possible if you are careful, which is the answer to your question.
OK I alllmost get it. I've done a bunch of reading in objective-c and I really want to understand delegation because it seems super important for cocoa-touch and I want to design an iPhone app.
So, a delegate is an object that can be given a certain task. It is said to follow a 'protocol' if it implements certain functions. So a view-controller, for example, can say "hey, I'm not sure where to get this data from..or hey, I'm not sure how to format this thing...can you do it for me?" and the delegate is like "sure I got you covered".
OK that makes sense to me. What doesn't make sense to me is how I get the delegate to return stuff to a view controller. Like say my delegate can go to a URL and read a sports score or something. So I say "delegate get me this score" ...how do I get the view controller to say "got it, here it is" and then have it inside the view controller. There might be a gap in my understanding here. Would I have to instantiate the view controller inside the delegate? That doesn't make sense to me...because then I'd have two view controllers...Feel free to change my analogy if you can make it clearer.
Thanks!
I think you're confused because a similar pattern is used for (but is not limited to!) two common tasks, both of which apply to your situation.
The patterns
Having an external object provide data for you (this is usually called a data source). See, for example, the UITableViewDataSource protocol.
This is implemented by a return value from the method: such as - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
The object implementing the protocol returns some value (in this case, a cell) to the caller.
The thing I'll mention about data sources: the data source itself (the object implementing the protocol) usually contains more of your application's custom logic, while the controller which requires a data source can be more generic. For example, UITableView is a generic view controller that displays a table view, while a class implementing the UITableViewDataSource protocol needs to know the details of your application's database.
(However, to be thorough, you do often subclass UITableView for custom logic, but this is most often presentation logic and not business logic.)
These methods call in to your application logic, and are expected to return immediately.
Providing callbacks once you've finished loading data.
For example, the NSURLConnection class has the corresponding NSURLConnectionDelegate protocol. The most common use pattern is:
Your object creates a NSURLConnection, with itself as the delegate.
You configure and start the connection.
You receive progress and data via the delegate methods you implement.
In this case the object which requires a delegate is an auxiliary object that knows how to load data from a URL in the background. The delegate methods are callbacks to your application logic, and are called at any time after the object is told to start loading data (or whatever it's designed to do).
Delegation is also used for other things on iOS, such as the UI-related tasks performed by objects conforming to UITableViewDelegate.
Your situation
This all depends on what your application is, and what your view controller is responsible for — but it sounds like you want the view controller to delegate the loading of data — basically, it needs a data source. (You should also consider if the built-in UITableView & UITableViewDataSource might suit your needs.) But if your data source is going to asynchronously load data from the internet, it might need to implement some data-loading callbacks via something such as NSURLConnection.
These two methods don't necessarily go together well, because the view controller will expect its data source to immediately return data, but the data source might need to wait for data to load.
This is why UITableView has a method -reloadData, so the object which serves as the data source can tell it when data is available. You might want to use a pattern like this in your application.
(But again, in all likelihood you won't need to implement a fully custom stack — either you can combine some classes to reduce your use of delegation, or you can use more built-in classes to suit your needs.)
Define your protocol's methods with return values.
That said, getting a URL is a bad example, since waiting for a delegate to return the results would block the calling thread. In this case, you would have to have a way for the delegate to call back with the results when done. This can be achieved either by passing a delegate to the delegate, or passing one or more Objective-C blocks to the delegate (onSuccess, onError, …).
On that subject, blocks are much easier to code than delegates and protocols, and are gradually supplanting them in Apple's and third-party APIs.
I’d like to wrap a procedural event C API into Objective-C. The procedural API revolves around some opaque pointer, say EventRef. There are several kinds of events that can be represented by this type – mouse events, keyboard events, etc. You can get the kind of the event by calling some function, say EventGetType(event).
It seems very natural to represent the different event kinds by different classes. In other words, have an Event class and subclasses like MouseEvent or KeyboardEvent. My question is how to create instances given some EventRef?
I can’t simply have a public initializer that takes the EventRef, as the callers would have to find the correct class before initializing. This feels clumsy:
EventType type = EventGetType(event);
switch (type) {
case EventTypeMouse:
…[[MouseEvent alloc] initWithEvent:event]…
case EventTypeKeyboard:
…[[KeyboardEvent alloc] initWithEvent:event]…
I could do some magic in the Event initializer so that it would pick the right class for the called:
#implementation Event
- (id) initWithEvent: (EventRef) event {
// pick correct subclass, initialize and return that
}
One of the downsides is that this makes subclassing the event types harder. And I don’t like the magic in the initializer. I could also write some kind of registry, but that already feels too complex. How would you go about this? (Please note that the event API is just an example to have something more concrete to reason about.)
The scheme you describe with your magic initializer is a factory pattern. I think it's indeed that way to go, however I wouldn't do it that way but rather:
#interface EventFactory
- (id) eventForEventRef:(EventRef)event;
#end
That is, move the factory to its own class. That way you don't have to mess with the superclass once you add a new subclass.
I have trouble understanding Cocoa Bindings. Can someone explain me what this is all about, in an way that is humanly perceivable?
Bindings is a system for connecting your views to your controllers without writing a lot of glue code to make them explicitly talk to each other. All you have to do is set up properties in both classes* and hook up the binding in IB.
The traditional approach is that the view has one or more outlets to talk to the controller (the most generic examples being delegate and target) and the controller has outlets to talk to the views. When the controller updates the model, it sends (for example) [view modelChange:newModelObject]. When the view wants to update the model, it sends some delegate message to its delegate (the controller), such as NSText's textDidChange:.
With Bindings, all you have to do in code is implement properties on the view and properties on the controller, then expose one or more properties of the view as bindings*. Then you only need to hook up the binding. If it's a Cocoa class, this is cake: just set it up in IB. If it's a custom class of your own, you'll probably write the bind:toObject:withKeyPath:options: message yourself (not much harder).
Let me restate that: With Bindings, your entire glue code (most of the time) is [view bind:#"viewProperty" toObject:self withKeyPath:#"controllerProperty.modelProperty" options:options]; in the controller. Everything else is handled by the Bindings and KVO systems behind the scenes, and by your properties' accessors.
The disadvantage is that you must strictly conform to Cocoa Bindings' requirements. These are simple, but a lot of older applications are designed in a way that doesn't fit Cocoa Bindings.
You must create real model objects, not just pass primitive objects (e.g., arrays of dictionaries) around. If you're using Core Data, this is easy: your managed objects are model objects.
You must either write your accessors correctly or synthesize the correct accessors. For example, an NSString property should always be #property(copy), never #property(retain) (because otherwise, you will find yourself retaining someone else's mutable string, which they will then mutate while you're holding it).
You must only change properties of your model objects by their properties (model.foo = bar) or by accessor messages ([model setFoo:bar]), never by direct instance variable access. (Obvious exception for accessor methods themselves, if you've written your own, because they must access the instance variable directly.)
There are two advantages:
You can write a brand new view class without having to rip out a lot of glue code. The most you'll have to delete is some bind:::: messages for the old view's properties. If, a couple of years down the road, you decide that your current view just can't scale to your application's forthcoming capabilities, this gives you the flexibility to rip it out and start afresh with the minimum of pain.
More importantly, the less code you have to read, the easier it is to read it.
*And, according to the documentation, implement a KVO observation method in the view class, but I've never actually had to do this. I filed a documentation bug.
Added 2009-03-07: Ah, found a citation. “NSView subclasses can expose additional key-value-coding/key-value-observing compliant properties as bindings by calling the class method exposeBinding: for each of the properties.” —NSKeyValueBindingCreation So you shouldn't need to implement a KVO observation method.
Previous answer is very comperhensive and good, I'd just thought I'd add an answer explains what it is at its core without involving Cocoa or Objective-C specifically. That is because the concept itself is language agnostic although dynamic languages like Objective-C makes it a lot easier than more static language like C++.
Example
Say you have two objects M and V. M has methods:
setX(int x);
setY(int y);
int getX();
int getY();
While V has methods:
setA(int x);
setB(int y);
int getA();
int getB();
One way of looking at this is that M has properties x and y and V has properties a and b. You want a change of property x to cause a change in property b and a change in y to cause a change in a.
By change in property x we mean e.g.:
M.setX(10)
where previously
M.getX() != 10
So we want a call of setX on M to cause a call to setA on V.
What bindings allow you to say is that property b on object V is bound to property x on object M. And then this updating is handled automatically. You as a coder don't have to write code that checks if x is changed and then call setB on V. Bindings takes care of this automatically.
Summary
Bindings allows you to bind two properties together that exist on two different objects, so that changing the value of one of the properties causes the dependant property in the other object to change to the same value.