Delegates and Notifications in Objective-C - iphone

In my AppDelegate, I download some data from a JSON feed. I am downloading a now/next/later schedule for a few channels. I have three different view controllers for each now, next and later. In each view controller, a user can add/remove the channels so when that happens, the newly added channel data has to be downloaded again.
Since the data is downloaded in the AppDelegate and stored there, how would I pass it to the three view controllers? Should I implement three separate delegates? Keep in mind that when adding a new channel, its data has to be downloaded again (which I am doing outside the AppDelegate now).
Any help please?
Thanks

This is basically a matter of style and your approach isn't invalid as such.
I'd do it another way, though - the AppDelegate is not meant to be used as a workhorse and having several AppDelegates at the same time is simply impossible.
Here are some thoughts about how this could be done (though it's of course not the only proper way):
First, I'd employ Core Data or some other sort of storage which is available from anywhere within your app.
Then maybe I'd introduce some sort of "data controller" class (maybe a singleton). This class should handle both download of data and the distribution of that data to your viewcontrollers as requested.
By having one central controller for that purpose, you'd ensure that data gets downloaded only once because the controller knows exactly which data is already in stock.
Your viewcontrollers would neither be responsible for managing downloads anymore nor would they access the data on disk by themselves. They'd just make a request to your data controller and get a callback when the requested data is available - no matter if it was on disk already or has been downloaded for the occasion.
This keeps your VCs slim and focused and reduces the pain of making changes to your interface.

Toastor's answer is correct and as he says, there are several ways to do this. One is to call a data access class and change the values OR listen for changes on the values. For the later, the Key-Value Observing Programming Guide says the following:
KVO is particularly useful for communication between model and
controller layers in an application.
A controller object typically observes properties of model
objects, and a view object observes properties of model objects
through a controller.
In addition, however, a model object may observe other model
objects (usually to determine when a dependent value changes) or even
itself (again to determine when a dependent value changes).
Another is to make the dependency explicit, maybe passing a data access class saved in your app delegate. See Object-oriented design question, iPhone.

Related

Open UIManagedDocument take too much time

Recently, I'm working with a timetable app in iOS, and i get trouble with Core Data.
My app has a main user interface kind of like the original calendar app created by Apple, and i save all my events data in the Core Data database.
I create a UIManagedDocument in order to fetch data from database by using its NSManagedObjectContext, and everything works just fine.
However, i need to use the NSManagedObjectContext to fetch data several times in several different view controllers during the runtime. And every time i do this, i need to reopen the UIManagedDocument, but open the document take too much time(it may take 2 seconds or even more, i have to display a spinner in view).
So here are my questions:
What's the right way to open a managedDocument?(I mean like open it during the lunch image time?)
Is there a way to only open the managedDocument once and keep it open during runtime?(So i can use its context all the time)
Does data store in the managedDocument i create?(I found that if i delete the document, data was gone)
Thanks.
You will get lots of different opinions on how to do this but basically you should only have to open the document once. This is done by some object that does the work and stores it so it can return it again when asked by a different view controller.
Many people create singleton's for this or put it in the App Delegate. I have implemented a protocol that lets me put it where ever it is convenient for a particular application without my other code having to know anything about the object that returns the information. As long as it responds to the protocol it can be the App Delegate, a singleton class, or any other object type.
See importing AppDelegate
The protocol that I put in the above example just returns information about where the database is. In my actual implementation I have an openDatabase method with a call back to let me know when it is done plus automatic initialization and updating methods.
You can also improve your performance by having the open operation happen off the main thread. This keeps your UI responsive but does not show the data any faster and you have to be carefull about managed object contexts and the threads they are in.
Good luck...

iOS Asynchronous NSURLConnection triggering behaviors on different views than the one that call it

Me and my team are currently rookie developers in Objective-C (less than 3 months in) working on the development of a simple tab based app with network capabilities that contains a navigator controller with a table view and a corresponding detailed view in each tab. The target is iOS 4 sdk.
On the networking side, we have a single class that functions as a Singleton that processes the NSURLConnection for each one of the views in order to retrieve the data we need for each of the table views.
The functionality works fine and we can retrieve the data correctly but only if the user doesn't change views until the petition is over or the button of the same petition (example: Login button) is pressed on again. Otherwise, different mistakes can happen. For example, an error message that should only be displayed on the root view of one of the navigation controllers appears on the detailed view and vice versa.
We suspect that the issue is that we are currently handling only a single delegate on the Singleton for the "active view" and that we should change it to support a behavior based on the native Mail app in which you can change views while the data that was asked for in each one of the views keeps loading and updating correctly separately.
We have looked over stackoverflow and other websites and we haven't found a proper methodology to follow. We were considering using an NSOperationQueue and wrapping the NSURLConnections on an NSOperation, but we are not sure if that's the proper approach.
Does anyone have any suggestions on the proper way to handle multiple asynchronous NSURLConnections to update multiple views, both parent and child, almost simultaneously at the whim of the user's interaction? Ideally, we don't want to block the UI or disable the buttons as we have been recommended.
Thank you for your time!
Edit - forgot to add, one of the project restrictions set by our client is that we can only use the native iOS sdk network framework and not the ASIHTTPRequest framework or similar. At the same time, we also forgot to add that we are not uploading any information, we are only retrieving it from the WS.
One suggestion is to use NSOperations and a NSOperationsQueue. The nice thing about this arrangement is you can quickly cancel any in-process or queued work (if say the user hits the back button.
There is a project on github, NSOperation-WebFetches-MadeEasy that makes this about as painless as it can be. You incorporate one class in your classes - OperationsRunner - which comes with a "how-to-use-me" in OperationsRunner.h, and two skeleton NSOperations classes, one the subclass of another, with the subclass showing how to fetch an image.
I'm sure others will post of other solutions - its almost a problem getting started as there are a huge number of libraries and projects doing this. That said, OperationsRunner is a bit over 100 lines of code, and the operations about the same, so this is really easy to read, understand, use, and modify.
You say that your singleton has a delegate. Delegation is inappropriate when multiple objects are interested in the result. If you wish to continue using a singleton for fetching data, you must switch your pattern to be based on notifications. Your singleton will have responsibility for determining which connection corresponds to which task, and choosing an appropriate notification to be posted.
If you still need help with this, let me know, I'll try to post some sample code.

How does the ViewModel get notified on data item's property change?

The ViewModel can notify the View about property change by raising property change event. If the underlying data (for example, a Plain class which do not implement IPropertyChange) changes, how can ViewModel get notified?
If the underlying data (for example, a Plain class which do not implement IPropertyChange) changes, how can ViewModel get notified?
It cannot, there has to be a mechanism in place to do the notification. The most likely cause is a POCO that is used in one region (or module) of the application is also being used in another, i.e. a loosely coupled master-detail situation. If you are "sharing" the same instance of a POCO like this, then it is unlikely that you haven't also implemented change notification in it. If you have implemented change notification, then a change in one module of the application will automatically be visible to the other module (they are both looking at the same object) and anything that watches for that change notification (like a binding subsystem) will do its thing and pick up the changes.
If you have two separate instances of the same data and one gets updated, the other will not know about it. This also happens when your VM requests data via the Model, and the Model retrieves the data from a disconnected data source like a database or a web service. You don't know when the underlying data has been changed, once again you need to implement a change notification system. You can also take another aproach with this - let the user change the data, then do a fresh grab of the data before saving the user's changes, and if the underlying data has changed while the user was working then you can notify the user and take the appropriate action (or let the user choose the appropriate thing to do).
Does this answer your question? Or do you care to elaborate more about what you are wanting to know?

Should I have all my web service code in my view controller

I have noticed that with iPhone programming you kind of need to retrieve your data from within the ViewController because of the way the data is retrieved.
e.g.: ViewDidLoad is called. You start retrieving the data and then when its finished a message is sent to your viewcontroller e.g. requestFinished and this is where you configure/refresh your UI.
The problem that I have with this approach is that I have a bunch of web service code and XML building and parsing all in my view controller.
Does anyone know if this is the correct approach or is there a better way to do this.
In .NET I would have classes specifically for retrieving data from webservices and I would simply call the web service to fetch the data and I could use the same web service at various places inside my app.
There is no reason to do that different in Objective-C/Cocoa. You should create a class that handles the web service and notifies the view controller when data is available.
No, it absolutely isn't the correct approach. The key to this is the MVC paradigm, - model, view, controller - your data classes are perfectly suited to being the M = model so put all your data handling code inside a dedicated model class.
Because the url handling is hopefully asynchronous, your model will still need to inform your view controller when various events have taken place. You have a couple of choices here but the most appropriate is probably to use a delegate pattern so that the model can basically initiate a call back to the view controller when it has data that needs displaying etc.
(The other approach would be to use notifications which is less tightly coupled, and perfectly viable in this scenario, but delegates would be more appropriate).
Well you could create a parse that will parse your XML in a seprate class, and even your http request can be in a seprate class.
There is no need to do every thing in the the on viewcontroller.
Just be sure to create delegate or use the notification center if you are using threads. Set the delegate on either the request or parse to nil if the view controller get unloaded.

How does one communicate between view controllers in a UINavigation type application?

I have a UINavigation based application that gathers information on various screens and eventually makes a web service request using all the parameters collected.
So I have A,B,C,D view controllers. A gets the name & number, it then pushes B onto the screen with some basic info ETC ETC until it gets to D where I actually fire off the web service.
The poor method I have been using is to duplicate class fields from A onwards. Meaning if I collect name, and number, then I make those the fields of B, which then adds a few fields, and then C has class fields of both A & B which seems like a poor programing practice.
What can I do to get access to class A's fields in class D? I have gotten certain ideas but not sure how valid they are.
1). Use NSNotification (Is this overkill?) If so how do I pass fields?
2). DO I just retain all 5 view controllers and just get the info at the end? (seems very inefficient)
3). Should I just instantiate a NSObject class called Payload and just set its fields every time I bounce from one view controller to the next? (If so do I create it in class A? What if user navigates back to class A, will it then get reset ETC ETC)
As you can tell I have tried to find a solution and I am fairly new to it. Some detailed suggestions would be highly appreciated.
Depending on situation, there are several ways that seem appropriate.
Get to know MVC Design Pattern
Classes are not data storage. If class doesn't have interface to interact with represented object, excluding accessors, you're doing it wrong.
3.
I have a UINavigation based
application that gathers information
on various screens and eventually
makes a web service request using all
the parameters collected.
So, your web request is based on parameters gathered from various views. Why not create an
model of said request? MyRequest or something like that :) Or several more specific variants, sharing common parent class? This generator holds logic, gathers data and parameters as you advance trough views and provides NSUrlRequest at the end to WebView or maybe different kind of object which is NSURLRequest delegate and conforms to UITableViewDataSource/Delegate protocols to be used to display downloaded data.
I'd go for 3) and yes you should create it at the beginning (Class A).
But maybe user go back to Class A to change the value on purpose so resetting it doesn't seem to be a problem.
Why not use a singleton object and pass it around?
The advantages of this method are:
There's only one instance whose
reference is being passed around
between viewcontrollers
Changes you
make are reflected the next time you
access this object from another view
controller
And to answer one of your questions, NSNotification allows us to pass objects along....
Here's a good example on singleton objects in iOS by Matt Galloway. It's the one I always refer to:
http://www.galloway.me.uk/tutorials/singleton-classes/