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.
Related
I know that starting with iOS5 and the new UIViewController containment methods, you are supposed to call these methods together with addChildViewController:, removeFromParentViewController: and the transition method. I also know the proper order of calling them in the three scenarios. What I don't know is what exactly these methods do?
If these were merely override points for subclasses of UIViewController I guess we wouldn't be required to call super when overriding. What can/will go wrong if I don't call willMoveToParentViewController: nil before removing a view controller or didMoveToParentViewController: self?
In addition to what has been said, they do call some delegate methods:
addChildViewController calls [child willMoveToParentViewController:self]
and removeFromParentViewController: calls [child didMoveToParentViewController:nil]
Also, they modify the childViewControllers property, which holds an array of child view controllers.
There are many answers to this:
They are there and you are supposed to call them where applicable to always uphold the pattern. That way, if you change superclasses from UIViewController to your own view controller, you won't have to worry about where you followed the entire pattern.
They are better places to hook into than telling everyone to override addChildViewController:. As you say, mis-managing willMoveToParentViewController: sounds like it's less dangerous than mis-manging addChildViewController:, especially if you forget to call super.
UIViewController probably depends on you upholding the pattern. Maybe it will deem the state inconsistent if it knows that it has received addChildViewController: but never gets the other two messages. Whether this happens due to UIViewController doing book-keeping to lure you into upholding the full pattern or whether you really do mess up its internal state is a fun guessing game, but also something that may change in any iOS release. Things may break badly. That's why the pattern is there, for Apple to tell you that as long as you do this, we will keep things working no matter what.
Questioning a pattern is good, but there are many potential negatives that come with trying to cut your conformance of a pattern to the bone. Unless the pattern is ridiculously involved, it's usually just easier to conform to it.
Check the GitHub project for this article.
A notification is sent by prepareForReuse method of the custom cell(JKCallbacksTableViewCell class) to the table(RootViewController class) which is observed by the tableViewCellIsPreparingForReuse method. This method resets the association key and the imageview of the cell.
So, why does author preferred to send it through a notification instead of resetting them after getting a non-nil cell from dequeueReusableCellWithIdentifier method of the table?
According to the documentation of UITableViewCell, prepareForReuse is called just before dequeueReusableCellWithIdentifier.
If a UITableViewCell object is reusable—that is, it has a reuse identifier—this method is invoked just before the object is returned from the UITableView method dequeueReusableCellWithIdentifier:.
I have tested it that when dequeueReusableCellWithIdentifier returns a non-nill value it's coupled with a call to prepareForReuse.
Author commented in the JKCallbacksTableViewCell.h about application logic separation but i think that is a kind of overkill; optimizing performance with async dispatch but sending those slow notifications to reset some properties... Or am i missing something about GCD?
Most programming problems have a near-infinite number of solutions. I didn’t have any particular reason to choose notifications other than the fact that they’re loosely coupled.
Regarding your comment about the speed of the notification: the thing that makes the app slow is loading the images, so we’re trying to optimize that. Notifications aren’t slow enough to make a difference in the use of the app otherwise, so to use something else for pure performance reasons is unwarranted here.
That said, it’s in GitHub, so feel free to send a pull request that doesn’t use notifications. If I like it better, I’ll use it.
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'm new to Mac programming and I'm working on a document-based application.
My NSDocument subclass creates a NSWindowController subclass. This window controller creates two NSViewController subclasses as well.
Sometimes, a change in one of the views of a NSViewController needs to notify the NSDocument and/or the main model class. Also, a change in the model needs to be notified to every/some view(s).
My question is: what is the best approach so that there is no (or minimum) coupling? I know there are several choices, but I'm not sure which one suits best for my application as I'm newbie not to programming but to Cocoa and especially NSDocument:
KVO. Looks nice and easy to implement, but I don't like the idea of not explicitly notifying the observer(s) about a change (AFAIK, self.someProperty = newValue does automagically notify observers), and don't like the fact that you have to register to property names which could change in time.
Notifications. I know what they are and I've used them for iOS. But I've read somewhere that they are not guaranteed to be sent immediately to observers. Is it true? If not, do you see them as a good approach for a document-based app?
Delegates. Yes, under normal conditions (or what I've usually seen), a class has one delegate. But creating an array of delegates works as well (just tested it). The problem I see here is that every time I need to notify the delegates I have to loop through them, make sure they respond to a method, and call that method.
Are there any other alternatives I'm missing?
KVO by a controller class is the most common way to do coupling between a model and its view(s). In fact, Cocoa Bindings, which are intended to mostly eliminate code in the controller layer, are based on KVO. It is true that KVO/KVC relies on property names, and that if those change, you'll have to change the bindings or KVO setup connecting your view. However, it's not usually feasible to make your views completely unaware of the underlying model specifics, so I don't see this as a problem.
My recommendation would be to use Cocoa Binding where you can, as they eliminate a lot of glue code. In places where they can't be used, your controllers (the middle layer in MVC) should use KVO to observe model changes and update the appropriate views. Changes in the views can be passed back to the model via property accessors and/or KVC by the controllers.
Yes, under normal conditions (or what I've usually seen), a class has
one delegate. But creating an array of delegates works as well (just
tested it).
Delegates are often used to modify the behavior of the delegating object. An application delegate is a good example: NSApplication by itself isn't very interesting; it relies on its delegate to define the interesting behavior of the application. Having multiple delegates all trying to modify the behavior of a single object could be a problem if the various delegates conflict with each other. What do you do if the delegates disagree?
There are some cases in Cocoa where a class uses more than one delegate, but each one has a separate role. For example, NSTableView has both a delegate and a data source, but both are really delegates of a sort.
The problem I see here is that every time I need to notify the
delegates I have to loop through them, make sure they respond to a
method, and call that method.
That's not hard to solve. For example, you could create an NSInvocation to encapsulate the call, and then send the invocation to each "delegate." However, if you do that you'll have nearly reinvented the notification system. If you need the one-to-many communication that you'd get with your multiple delegates proposal, you'll probably be better off using notifications or KVO.
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.