Is it possible to call an asynchronus NSURLRequest from a thread(NSThread)?
If yes, then is this a good practice?
If no, then can any one can explain with code snippet that what can be the issue?
Thanks
It is possible, but usually not necessary. To do this, you would need to set up an NSRunLoop on your secondary thread.
Usually it's better to just use NSURLConnection from the main thread, it will still not block. For processing the downloaded data, you could easily use dispatch_async from the connectionDidFinishLoading: delegate method.
Related
We can have [NSOperationQueue new] addOperationWithBlock yet we do not have NSOperation withBlock?
I thought the way addOperationWithBlock is to create NSOperation first with that block and then add that to the queue. So we have a function that will do the whole thing but not the one that can do it one thing at a time?
Strange.
Are you looking for +[NSBlockOperation blockOperationWithBlock:]?
I've used GCD before with dispatch_async for background-threading units of work like parsing data from a network request (in, say, JSON or XML), and it's WONDERFUL. But what if I have a background task that's going to run for the length of the application? Is dispatch_async still a good fit for this case, or is there a better way to implement it?
Sure, but create your own dispatch queue for it. (If you use a global queue, you may tie up that queue--or one of its threads--forever.)
dispatch_queue_t dispatchQueue = dispatch_queue_create("com.mycompany.myapp.ForeverOperation", DISPATCH_QUEUE_SERIAL);
dispatch_async(dispatchQueue, ^{
// worker routine
});
More traditionally, you would create an explicit thread for this, and if it will run forever, that might make more "sense". But the results are basically the same.
NSThread * myWorkerThread = [[NSThread alloc] initWithTarget:...
[myWorkerThread start];
If you need to communicate with other threads/queues, as always, standard synchronization techniques may be required.
This really has nothing to do with dispatch_async, which is merely one approach to doing something in a background thread. If you want to do something in a background thread, do it in a background thread! Just be aware that doing this constantly can be a drag on your app, since you've only got so much processing time and only so many processors; you may end up having to study that in Instruments. You might want to break up your task into little bits and do it in short chunks every so often. Both GCD and NSOperation can help with that.
I have been working with a few applications that deal with NSURLConnections. While researching best practices I have noticed a lot of examples online showing how to use NSOperation and NSOperationQueue to deal with this.
I have also noticed on stackoverflow a few examples that show initializing the connection as synchronous and asynchronous using the class methods of NSURLConnection: sendAsynchronousRequest and sendSynchronousRequest.
Currently I am doing my initialization as follows:
[[NSURLConnection alloc] initWithRequest:request delegate:self];
While doing this I have monitored the main thread and the calls to the delegate methods:
connectionDidFinishLoading, connectionDidReceiveResponse, connectionDidReceiveData and connectionDidFailWithError
Everything I have read in Apples documentation and my tests prove to me that this is asynchronous by default behavior.
I would like to know from more experienced Objective C programmers when the other options would be used for either a best practice, or just be more correct than what I see as the most simplistic way to get async behavior?
This is my first question I have posted on here, if more information is needed please ask.
Synchronous is bad bad bad. Try to avoid it. That will block up your main thread if the data transfer is large, thus resulting in an unresponsive UI.
Yes, it is possible to dispatch a synchronous call onto a different thread, but then you have to access any UI elements back on the main thread and it is a mess.
Normally I just use the delegate methods you have described - it is straightforward, and NSURLConnection already handles the asynchronous call for you away from the main thread. All you need to do is implement the simple delegate methods! It's a little more code, but you always want to go asynchronous. Always. And when it is finished loading, use the information you get to update the UI from the finishedLoading delegate method.
You also have the option of using blocks now, but I can't speak for how well those work or even how to use them well. I'm sure there's a tutorial somewhere - the delegate methods are just so easy to implement.
The method you list are the traditional means of asynchronous transfer and an app that uses them will be efficient in processor (and hence power) use.
The sendAsynchronousRequest method is a relatively new addition, arriving in iOS 5. In terms of best practice there's little other than style to differentiate between it and the data delegate methods other than that a request created with the latter can be cancelled and a request created with the former can't. However the tidiness and hence the readability and greater improbability of bugs of the block-based sendAsynchronousRequest arguably give it an edge if you know you're not going to want to cancel your connections.
As a matter of best practice, sendSynchronousRequest should always be avoided. If you use it on the main thread then you'll block the user interface. If you use it on any other thread or queue that you've created for a more general purpose then you'll block that. If you create a special queue or thread for it, or post it to an NSOperationQueue then you'll get no real advantages over a normal asynchronous post and your app will be less power efficient per Apple's standard WWDC comments.
References to sendSynchronousRequest are probably remnants of pre-iOS 5 patterns. Anywhere you see a sendSynchronousRequest, a sendAsynchronousRequest could be implemented just as easily and so as to perform more efficiently. I'd guess it was included originally because sometimes you're adapting code that needs to flow in a straight line and because there were no blocks and hence no 'essentially a straight line' way to implement an asynchronous call. I really can't think of any good reason to use it now.
I want to make a call to my server fetches some data every 30 data that should be used to display annotation on a MKMapView. I have researched about it, but I'm still unsure which to use?
Some guidance please. :)
I'd recommend using an NSTimer, perform a selector and in your selector launch an NSOperation to perform the download. Use KVO to observe for isFinished or use delegates with your NSOperation :)
I have a task that takes a rather long time and should run in the background. According to the documentation, this can be done using an NSOperationQueue. However, I do not want to keep a class-global copy of the NSOperationQueue since I really only use it for that one task. Hence, I just set it to autorelease and hope that it won't get released before the task is done. It works.
like this:
NSInvocationOperation *theTask = [NSInvocationOperation alloc];
theTask = [theTask initWithTarget:self
selector:#selector(doTask:)
object:nil];
NSOperationQueue *operationQueue = [[NSOperationQueue new] autorelease];
[operationQueue addOperation:theTask];
[theTask release];
I am kind of worried, though. Is this guaranteed to work? Or might operationQueue get deallocated at some point and take theTask with it?
There's nothing in the documentation to say what happens when the NSOperationQueue is released. It would be safest to assume there's no guarantee that theTask will get executed.
I would have guessed that an NSOperationQueue releases its tasks when it's released, but I've noticed that the tasks do complete and dealloc even if I release the queue immediately after adding the task. That said, I don't think I'd rely on that behavior - there's more to gain by storing the NSOperationQueue in an instance variable (and releasing it in dealloc). An instance variable will give you a way to call other methods on the queue (cancelAllOperations, setSuspended, etc).
Can't you use the [NSOperation mainQueue] object so that you don't need to worry about autoreleasing it? If you only need to add one task that seems to make the most sense to me.
http://developer.apple.com/mac/library/documentation/Cocoa/Reference/NSOperationQueue_class/Reference/Reference.html#//apple_ref/doc/uid/TP40004592-RH2-SW21
There's no guarantee that it's safe to release an NSOperationQueue while it's still working. I suspect it probably is safe and this guarantee will probably be added someday, but it isn't there now. However, the equivalent Grand Central Dispatch API does guarantee that you can safely release its queues when you're done using them and it will keep them around as long as it needs them. So if you're on a platform with GCD, you can use that to be sure it won't blow up in the meantime.
Alternatively, you could create a wrapper class that checks if a queue is finished and releases both the queue and itself when the queue is finished.