My Rootviewcontroller uses NSURLConnection to get data from a server, and then, based on this data, loads a bunch (like 7) of smaller UIViewControllers that each also use their own NSURLConnection to get some more specific data from the server. But, the problem is, only the RooTViewController is recieving callbacks from:
- (void)connectionDidFinishLoading:(NSURLConnection *)theConnection
the other UIViewControllers never get callbacks...
You should really work with the assumption that only one view controller is active at the time. So if you want the other view controllers to do work, even when they are not visible on the screen, then you should move that logic into some singleton object that does all the network communication. The viewcontroller, when they appear, will simply ask this object for the data.
For the iPhone it is a really bad design to let inactive view controllers do stuff in the background. The only thing they do is manage the view that you currently see on the screen.
#St3fan is correct about good patterns for UIViewController. Many a developer has been burned thinking his UIViewController always has a non-nil view (it doesn't).... Even so, I'll discuss here what may be going wrong.
There are two likely causes: you're not setting the UIViewControllers as the delegates of their NSURLConnections, or you're not actually starting the NSURLConnections. The most likely cause of the latter is that you're using NIBs and expecting them to load at the beginning of the program, when they actually only load when needed.
As #deanWombourne notes, you can have all the NSURLConnections you want (**). Walk through your code in the debugger. Make sure you're not sending messages to nil. When "nothing happens" it almost always means you're sending messages to nil.
(**) Don't get crazy with connections on iPhone. Network connections are expensive to create (in both time and battery). If you can get all the data you need over a single connection, there are some advantages to doing so. This doesn't mean you should bend over backwards to avoid connections; just be careful of letting them get out of control.
Related
Here's the scenario:
-A UIViewController (A) is pushed onto the navigation stack
-On viewDidLoad an async GET is called using AFNetworking (a singleton AFHTTPClient shared throughout the application) to populate various user elements on the view (say a UILabel).
-The user presses the back button before the request returns
-Assume other active view controllers may be making requests so you can't cancel all open operations
So question #1 is, should you track the open requests made by UIViewController A and cancel the outstanding ones when the user leaves that view, or should you let them finish up and ignore them? Since AFNetworking uses blocks, the user elements being updated are retained inside the block and therefore won't cause a crash when the success/fail block is executed after the view has been popped. However the downside to ignoring them seems to be unnecessary network traffic.
Question #2 is, where would you execute the code to cancel the operations made by UIViewController A? viewDidDisappear doesn't seem right because the user may have gone forward (pushed a new view onto the stack) instead of back (popped the current view), in which case you don't want to cancel the open requests because the user may come back to the current view and it won't load again. However, I don't think dealloc or viewDidUnload will be called while the request is executing since the block will keep a retain on the user elements so I don't think it can go there.
Would appreciate thoughts on this. What do you think is best practice?
Generally speaking, you don't really need to cancel requests when a user leaves a view controller. In terms of memory management, a reference to block self will prevent any crashes caused by sending messages to deallocated instances, so no worries there.
As far as user experience, I would say that you shouldn't really worry about it until it's a problem (we developers have a knack for guessing completely wrong on what will be slow in our applications). If you are making large GET requests, though, and it's creating noticeable sluggishness, my suggestion would be to have the controller do HTTPClient -cancelAllHTTPOperationsWithMethod:path: in -viewDidUnload: (any other callback would be premature).
Maybe you could have a singleton which manages all the network stuff, and just set its delegate to the current vc (in viewDidLoad) so you get any incoming data, and send it a cancel message when the vc disappears (or else let a different vc become its delegate). Or the singleton could keep the data for access by any vc at some later stage. I tend not to put async code into my VCs for this reason.
What is the need of delegation in iphone/ipad development or objective C?
I read so many articles on it. All were telling how to implement the concept, but no one was telling why we need to implement that, in which case we should implement it.
Suppose you want to implement Login functionality in your app ... now you won't show Login screen every time you run your app.. only when it is first started and you don't have a login and password...
So in this case..
Your app starts :
View 1 loads (default view )
You check no Login name is there..
You load a new view..(Login View ) .
User enter his details..you get your login and password...
now you want to go back to default view and load the main app with
the names the user entered in Login View....
Now you will use delegate to pass these information(login details) back to default View..so that it knows..its details. now there are many different ways to do these things...like notification and singleton classes.. but when you want to sent more than 3-4 sets of data.. it is best to use delegates
Think of all the components that iOS and Cocoa provide you with. TableViews, TextFields, PopOvers...etc.
When the developers wrote these components, they couldn't possibly know all the various implementations that us developers were going to create using these components. But we need somehow to communicate with them in a generic way.
These components use delegates. The delegate is an implementation independent way of describing some behaviour that your component can conform to.
When UITableView need to find out what is the height of the rows, the UITableView only needs to know about UITableViewDelegate. It doesn't need to know about MyTableViewController, JohnsTableViewController, BobsTableViewController... etc.
So the delegate is decoupling the component from the implementation and the type.
Decoupling is a good thing. It makes maintaing and changing code a lot easier, and makes code reusable.
Delegation is a simple and powerful pattern in which one object in a
program acts on behalf of, or in coordination with, another object.
The delegating object keeps a reference to the other object—the
delegate—and at the appropriate time sends a message to it. The
message informs the delegate of an event that the delegating object is
about to handle or has just handled. The delegate may respond to the
message by updating the appearance or state of itself or other objects
in the application, and in some cases it can return a value that
affects how an impending event is handled. The main value of
delegation is that it allows you to easily customize the behavior of
several objects in one central object.
SOURCE
Use a delegate if you want to talk to only one object. For example, a
tableView has a delegate - only one object should be responsible for
dealing with it.
Use notifications if you want to tell everyone that something has
happened. For example in low memory situations a notification is sent
telling your app that there has been a memory warning. Because lots of
objects in your app might want to lower their memory usage it's a
notification.
this was an answer posted to my question here
There are two key benefits of delegation: customizing objects without subclassing, and improving encapsulation.
Customization without subclassing is a benefit you get from many of the Cocoa and Cocoa-Touch APIs using the delegate pattern. If they didn't do so, you might have to subclass a UITableView every time you wanted to change its behavior by using different types of cells or a different data source. Instead, you just set the table view's delegate and data source to customize its behavior.
As for encapsulation, the delegate pattern helps you keep the different components of your code separate. For example, if your custom View needs to have some data, it would be bad practice to simply give it access to your Model, or even full access to your Controller. Instead, you'd probably set up some kind of delegate protocol for your View that your Controller would implement. That way your classes know no more about each other than they need to, so that changes in one part would be less likely to break others.
I have an app that has many web services and notifications going on. I need a logout feature. I wish there was a way simply to kill the app and restart it but there is not. Does anyone have some recommended guidelines on creating a logout function (it will take the user back to the login screen). The problem is there are notifs that should be unsubscribed from, views that should be removed, view controllers that I want to be released, then everything to reinitialize. That seems like a lot of work for a simple task. Any thoughts?
The first thing to make sure when terminating all requests is to change all delegates that are supposed to receive responses to nil. After you've taken care of this, you should indeed remove all irrelevant view controller's views from your root view (and release them if they are retained anywhere), and of course flush any existing data you don't need. If you design your MVC elegantly, you can achieve these actions without a lot of fuss, for example a ScreenManager Singleton class that manages all your view controllers should have no problem taking you back to the login screen while releasing any other view. A DataManager Singleton class that holds various data collections should have no problem removing any unneeded data entities and so on...
I have developed an application that uses UINavigationController to handle multiple instances of the same UIViewController, and it is working great. The UIViewControllers that I am using, however, are using a lot of images in a sometimes very big UITableView as loaded from the server, so I am beginning to be more conscience of performance and memory.
What happens to a UIViewController that isn't at the top of the stack? If I drill down through a few views, that all have images, whenever I return to the view, the UINavigationController presents the view without any loading, so I'm wondering if those views on the stack are in any way potentially hogging lots of valuable resources? Such as memory?
What is the best way to handle that situation? Is there anything I should know about that I apparently don't?
Thanks!
This is, actually, explained in the documentation for iOS. Check XCode>Organiser>Documentation>iOS, there is a nice drawing explaining how the UINavigationController stack works, that should be better than words.
However, in a nutshell, you have viewDidLoad and viewWillAppear (and their opposites) methods that serve to alleviate your fears. They should be used to create/delete any "memory hogging" parts of your code that you don't need "right now". However, as far as I know, you don't have control over what iOS will decide is necessary to flush or not, if it's controlled directly by UINavigationController.
I'm having problems with my application receiving low memory warnings while the user is deep within a navigation controller stack of views. After the user browses through a bunch of hierarchical options in subsequent UITableViews, he can open a PDF document in a UIWebView (in a different view controller).
Everything works fine, the PDF loads and the user can flip through the pages. However, when the document is a bit large, or has several pages, and the user taps on the "Back" button in the navigation controller, he app crashes as the previous view controller in the navigation controller stack has been deallocated.
After searching around for ways to deal with low memory warnings, and dealing with this type of problem, I found several posts that just advise people to release the objects that can be released, and then lazy-load them later on when the user tries to load a view that has been deallocated. One of these posts is Craig Hockenberry's Dealing with memory loss: the cleanup post.
While that's a bit helpful, it doesn't give me much information to work from.
Can someone provide a simple guide on how to deal with low memory warnings, and how to implement "lazy loading" of objects?
When memory is low, the system sends out a series of memory-related messages. Any instantiated view controllers will get the -didReceiveMemoryWarning message. If you don't implement this, the default action (assuming the view controller is not front-most) is to release the controller's view member. If you've got hooks into it, or perhaps into its subviews, that could cause issues when your controller gets returned to the top of the stack.
Your first task is to figure out what exactly is causing the problem. Which object is being deallocated? Usually, fixing this is simply a matter of making sure the object is retained properly.
I suggest you use NSZombiesEnabled to try and track down the object you're having trouble with. Once you have that, you can make sure you're retaining it properly.