I am a beginner developer in Objective-C/iOS and I have this simple question.
My program interact with a server side and I use GCDAsyncSocket for asynchronous communication.
I wonder, suppose the use is opening my status view controller which causes a request for server, but before the response arrives he has already moved to a different view!
What is the right way the handle this situation??
Thank you!
Ideally you should not move to the next view controller until you get the response in didReceiveData callback, because your GCDAsyncSocket delegate will have to be set to some controller, and probably you would have by default set it to the status view controller.
So you have to wait for the callBack response and upon receiving it you can move to the next view controller.
While the delegate can be set to the next view controller, you can skip it for now as you a beginner in iOS.
This is key.
asynchronous
You're using an asynchronous request to get your data. You'll have to use callbacks to let the view controllers know that the request has ended. I've never used that library but a quick glance at the readme says:
Classic delegate-style support.
All of the following result in calls to your delegate method: connections, accepts, read completions, write completions, progress,
https://github.com/robbiehanson/CocoaAsyncSocket/blob/master/README.markdown
https://github.com/robbiehanson/CocoaAsyncSocket/wiki/Reference_GCDAsyncSocket
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.
I am developing one navigation based application. All data required for each screen are getting downladed from webserver. I am starting downloading in viewDidLoad method. ALl downloadinh is happening asynchroniously and respective viewcontroller will receive data through delegate pattern. Now my question is in case new viewcontroller is getting pushed on navigation stack or current view controller is getting popped off so fast before data will get received, how we will handle this situation? We do not want to block UI so user can move back or forward. I used notification mechanism to detect particular view controller (one who receive data ) is alive or not , but it seems like not a concrete solution. So basically I want to detect receiver is appropriate for receiving downloaded data before I make a call to its delegate method.
Any pointer related to it is highly appreciable.
Thanks!
Nilesh
I think the dataSource pattern is more appropriate.
1) Create a datasource (singleton or attached in your app delegate)
2) Implement a method dataWithPredicate: (or just data)
3) Notify your viewController (with NSNotificationCenter) when a data is updated
4) Reload data from the controller (with dataWithPredicate: call)
Another way is to use core data for that. CoreData generate all the notification and do the job for you.
I am using TabBarKit, and I want to execute a request to pull a new peice of content from a webservice each time a user goes back to a tab.
I can't put the request code in viewDidLoad as its not fired when coming back to the tab. With that said, I've noticed viewWillAppear / viewDidAppear are called multiple times when returning back to a tabs view controller.
If I put the requesting code in there, it is fired multiple times resulting in the webservice being pinged needlessly.
How can I solve this problem? Which method should I place my HTTP request call in so it executes once per view?
You could try setting/checking a downloadInProgress flag before submitting the asynchronous download, then resetting that flag when the request completes.
If you're using something like the ASIHTTPRequest, that calls a delegate method when the request completes or fails, which is the point where you could reset the flag. It allows you to tag each request individually so you can track the success or failure of each one, so this wouldn't restrict you from running one background request at a time.
Turn's out there was an extra call to viewWillAppear in the controller code. If you're interested in following the changes, there is a thread on the issues section of the Git project.
I am using three20 and implement the model like the example of TTRemoteExamples. Now problem is: when I click and open a page, the TTURLRequest sent out, during fetch data from remote, I click to open another page. But the previous network request is still there messed my loaded data. So I want to know the way to cancel previous network request when I switch to another page. Or when I click button to do a new request in the same page.
Thanks~
To cancel a TTURLRequest, keep a reference to it (typically in an instance variable) then send it a "cancel" message. Like so:
[self.myRequest cancel];
If you don't want the delegate to be notified of the request being cancelled, do:
// I'm assuming self is the delegate here, that may not be true
[[self.myRequest delegates] removeObject:self];
[self.myRequest cancel];
You'll typically also want to do this in your view controller dealloc method. If a request continues after the viewController has been deallocated, it will try to send delegate messages to it, and you'll get a bad access crash.
As for the timing of when you cancel it, that's up to you. If you need it to stop when a user leaves your view controller, then implement UIViewController's viewWillDisappear: or viewDidDisappear: methods (don't forget to call super!).
I'm currently developing an iPhone app communicating via REST with a web server.
Each time the app starts it checks for remote data updates. If the data has not been loaded I start an async request in the app delegates applicationDidBecomeActive and show a modal progress view while the request is running. Some of my view controllers also need a data update which should be handled while the same progress view is visible and after the first request has finished.
What is the best approach to handle this scenario? Post a notification to the view controllers after the first request has finished and call back the delegate to dismiss the progress view?
Or is this considered a bad solution?
Best Regards
Carsten
Posting a notification should be used if the sender does not know anything about (should not depend on) the observers. For example, data object posts notification when it changes, so the visual objects connected to it could update themselves.
In your case you need to have a root object, the owner of your view controllers. It may be your Application Delegate or a subclass of a Navigation Controller. Since the owner knows about the view controllers, it can directly tell them to update when the request finishes.
Generally, do not send notifications between the owner and its dependants. Owners can directly call dependants' methods. Dependants can have weak links to their owners and let them know when they update. If you need to make dependants independent on the owner's class, define a delegate protocol.