Managment of download in objective-c - objective-c

I have to do a view update in parts of my application. I've a view with a view controller to manage the graphic parts -- two sliders and other objects.
I also have another class, with the methods of NSURLConnectionDelegate. In this class, when I receive some data, I want to update the objects of the view -- how can i do this?
The options I thought of are: to pass the view controller to NSURLConnection at creation, or to send a notification from NSURLConnection each time data arrives. NSURLConnection is anynchronous by default, right?
What do you think is better?
Thanks.

Create a progress delegate protocol for your loader class and have your VC implement the protocol
Send progress notifications from the loader class, and have your VC listen to the notifications
Use a library for downloads, people around here seem to like ASIHTTPRequest http://allseeing-i.com/ASIHTTPRequest/ but I've always found plain NSURLConnection satisfactory.

Related

iOS model view controller design with XML

I am making a tabbed bar application that has a section for Quizzes (which are written in XML). I am trying to conform to the MVC paradigm so I created a parser-delegate class, and a class for a quiz object which contains an array of questions and an array of their associated answers. My problem is that my parsing method has no way of sending it's quiz objects back to the view controller. Do I need to set up a delegate for the view controller to communicate with the Parser? Or should I just set the view controller to be the delegate for the parser and not have a separate class for the parser delegate.
Note: I am using NSXMLParser..
Any input as to the best way to do this is much appreciated.
Is your problem that you UIViewController is already created when then parsing finishes, I would usually use NSNotifications for this. And then the UIViewController can wait for the NSNotification or your app delegate can and then pass it onto your ViewController. Alternatively you can use a delegate callback or a callback blocks if you are supporting iOS4+. Hope this answers your questions.

iOS Airplay viewcontroller data sychronisation

I've built an iOS 5 iPad app which makes use of a second screen. We have an admin view (on the iPad) and an external view through an HDMI enabled TV connected via the Apple DVI adapter. Both the iPad view and the TV view get the same data updates from a service call which is made every few seconds. We then present the data received as a series of charts; the charted data is presented very differently for the TV and iPad views - but the core dictionary of data is the same. I'm wondering about an elegant way to architect this solution. At the moment I have one of the view controllers (the admin iPad VC) doing the service calls using GCD and then dispatching NSNotifications which update the data (charts) properties on the other (TV) view controller. I'm considering moving the service calls away from the VC and creating a singleton which is initialized in the app controller. I then (somehow) set the two VCs as delegates and they get updated using a simple protocol. I'm not entirely sure if this is a good approach or if I should consider something else? Can I even set both VCs as the delegates of another class or is it typically only one delegate per class instance?
Thanks for any input.
Ben
Why not abstract the chart data into its own model class, which you can share in both view controllers? The model class can be responsible for fetching the new data. To make the controllers aware of updates, they can either use KVO on the model object, or they can observe notifications sent from the model object when an update occurs, or you can have an array of delegates for the model object and each view controller can be a delegate.
There doesn't seem to be any compelling reason to make it a singleton, although you can if you really want.

ASIHTTPRequest popViewControllerAnimated: => delegate EXEC_BAD_ACCESS

I set the view controller to be the delegate of a local variable ASIHTTPFormDataRequest request.
But, tapping "Back" before the request has finished, pops and deallocates the view controller. So, when the request completes and sends the message -requestDidFinish: to the now nonexistent delegate, the app crashes with an EXEC_BAD_ACECESS exception.
How do I fix this crash?
One way I could think of solving this is to set the delegate to nil immediately after the navigation controller pops it. But, if that's the solution, how do I do that? (ARC's weak references would be sweet right now.)
Another way I can think of is to make request an instance variable of the view controller and call [request clearDelegatesAndCancel]; [request release]; in the view controller's dealloc method. This approach is outlined in ASIHTTPRequest Example Code, but I've been advised it's best to make requests local variables instead of instance variables. And, this particular view controller is a settings table view controller and has 13 switches. For automatic saving to the server, each switch creates & sends a new request each time it's toggled. If I made ivars, I'd have to make 13. That's a lot of code!
Thoughts? Ideas?
I think the first question is: What do you want to happen if the user presses back after pressing a switch? ie. Should the http request be cancelled, or is it important that the request does get to the server? I'll assume for now that you do want to cancel them, as that seems to be implied in your question.
I've been advised it's best to make
requests local variables instead of
instance variables
I'm not sure if that was good advice - you almost always want requests to not be local variables so you can cope with cases like this.
For your case, you could consider using an NSOperationQueue.
Rough steps to do this would be:
Create an NSOperationQueue in your view controller init.
When you want to make a http request, add it to the ASIHTTPRequest queue instead of call startAsynchronous
In dealloc, iterate the objects in the queue, calling [request clearDelegatesAndCancel]; for each one, and then release the queue.
That should solve the crash without needing 13 ivars!
I solved this by retaining the request delegate like NSURLConnection retains its delegate.

Using Protocols in Objective C to Transfer Data Between Different Objects?

Hey guys, I currently have a root table view which has a toolbar at the bottom and has labels and a refresh button within it, much like the Mail app's toolbar. This root table view controller obtains data from a server by allocating and initializing a DataUpdater class. Within this class are the NSURLConnection delegate methods that are called while communicating with the server.
As you can probably guess, I need to know when certain (delegate) functions are called within the DataUpdater class and the values of the parameters passed to these delegate functions so that I can update the labels on the toolbar accordingly (i.e. Connecting..., Updated, etc).
The problem I am having is determining how to notify the root table view controller of what is going on in these delegate methods. Would I use protocols, if so how? I have been skimming the documentation and don't quite see how I would get this effect. Or would you suggest I implement my program another way?
Thanks in advance!
A protocol is a kind of contract that says: I promise to provide the non-optional methods defined in the protocol, and maybe even the optional ones. It's purpose is like Java interfaces: to work around missing multiple-inheritence.
The delegate pattern in Objective-C normally works like this: you define a protocol, and then in your class, you define a variable like id<MyProtocol> myDelegate; and define a setter and maybe getter (either via normal methods, e.g. - (void)setDelegate:(id<MyProtocol>)aDelegate; or via properties.
Note that the delegate is not retained ! So if you work with a property, you need the assign option, not retain.
Now back in your class, you check whether myDelegate is nil and if not, you can directly call its non-optional methods. If you want to call an optional method, you first need to verify its presence via respondsToSelector:.
So if you decide to use the delegate pattern, you need to define a protocol, add that protocol to your root table view controller, implement the necessary methods there, and make sure to call [foo setDelegate:self]; or something similar to inform your other class that the root table view controller is the delegate. And of course implement the delegate calls in your class.
Edit:
An alternative might be to use NSNotifications, BTW. The advantage of notifications is that you can have multiple objects listen and react to them. The disadvantage is that you cannot (directly) pass values back. For example, you can define a delegate method that asks the delegate whether to do something or not. That's not possible with notifications, it's more like shouting into a room instead of having a one-to-one conversation.
DarkDust's answer about protocols is fine but I would like to add some things to it.
One underlying thing that is often forgotten when it comes to delegation is object ownership. When a program is running it creates a tree of objects. Its root object is the application delegate and for example it owns a navigation controller, which owns the individual view controllers, which own the view and the view owns its subviews and so on.
Often the question comes up: "Why is the delegate not retained, just assigned?" The problem is that if you send a message to a deallocated object the program crashes. So how do you make sure the delegate stays around? The answer is object ownership.
I give you an example: a UITableView and its data source which is the TableViewController which is nothing but a delegate. The TableViewController holds a reference with its view property to the UITableView, so it owns the TableView. That means when the tableView is alive there must also be its parent object present, which is the UITableView's delegate. So there is no danger that the delegate goes away somehow.
In the end it is again all about memory management.
Take home message is: think upfront about object ownership will make your program mode modular, easier to maintain and will lead to a looser coupling between individual objects.

Interact with UIProgressBar from model class

I have a MainViewController in my Cocoa Touch app which shows a status view containing a UIProgressBar view.
From the MainViewController, FlickrImage model objects are created and iterated over. the FlickrImage objects themselves interact with the Flickr API, which takes time which is why I want the user see the progress bar. The challenge (at least to me it is ;) now is to interact with the UIProgressBar (send progress messages) from the FlickrImage objects. Do I do this using a NSNotificationCenter or can I just declare the MainViewController as a forward class in FlickrImage and interact with the UIProgressBar directly?
The best way is to not have the model call anything at all, but use KVO to observe the model, and then react to the message you get when the model updates. This is because the point of having a separate model layer is that the model shouldn't have to know anything about how data is presented to the user.
So create a class that keeps track of the loading of all the images (most likely you already have such a class) and do something like:
[imageManager addObserver:self forKeyPath:#"progress" options:nil context:nil];
Make sure that the data manager class has a declared property called progress (ideally with values ranging from 0.0 to 1.0) and when you update the value in the manager, you must use the dot notation: self.progress = newVal;
This is much cleaner than sending notifications from the model class. An alternative would be to register the view as a delegate on the manager. There is no clear-cut rule of thumb for when you should use delegates and when KVO is better, although there might be slightly less overhead in using a delegate protocol. Apple uses both approaches but there is a tendency to rely more on KVO, which in my opinion is a good thing.
I prefer NSNotificationCenter, MainViewController register as observe and update the UIProgressBar.
keeping the object MainViewController in FlickrImage and updating UIProgressBar from FlickrImage which make handling UI from model(you are violating MVC)