Running Cocoa block in secondary thread - iphone

I have a call that goes to a server. I want the callback here to be run asynchronously in a secondary thread that's not the UI thread. Core Data here freezes up and I'd like to try to make the app feel more responsive. What's the best way to have this callback run in a secondary thread? Code example would be great!
[[SomeServer sharedInstance] doServerCallCallback:^(NSObject *param) {
NSManagedObjectContext *moc = [MYAPPDELEGATE managedObjectContext];
/* do more stuff with param */
[MYAPPDELEGATE saveManagedObjectContext];
}];
The server call itself doesn't need to be in a secondary thread, however the code executed in the block should be.

Putting some work on a background thread is easy: fire off your block with dispatch_async(), -[NSOperationQueue addOperationWithBlock:], or possibly even something related to the server connection you're using, like +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]. (Look up any of those in the docs for usage examples.)
If you're looking to do Core Data stuff on your background thread, it gets nasty unless you're on iOS 5.0 or newer. Apple has a big writeup on Concurrency and Core Data for the pre-5.0 case, but the new stuff, while a whole lot easier for simple uses like you're proposing, isn't as well documented. This question should give you a good start, though.

The block that you're passing is an object that the server will execute at some point. If you want the block to be executed on a different thread, you'll need to change SomeServer's implementation of -doServerCallCallback:.
See the Grand Central Dispatch Reference manual for complete information about using blocks. In short, the server should create a dispatch queue when it starts up. You can then use a function like dispatch_async() to execute the block.

Related

iphone - Should I use NSOperationQueue and NSOperation instead of NSThread?

I am facing a design problem of my app.
Basically, the followings are what I am going to do in my app.
A single task is like this:
Read custom object from the underlying CoreData databse
Download a json from a url
Parse the json to update the custom object or create a new one (parsing may take 1 - 3 secs, big data)
Analyse the custom object (some calculations will be involved, may take 1 - 5 sec)
Save the custom object into CoreData database.
There may be a number of tasks being executed concurrently.
The steps within one task obviously are ordered (i.e., without step 2 downloading the json, step 3 cannot continue), but they also can be discrete. I mean, for example, task2's step 4 can be executed before task1's step 3 (if maybe task2's downloading is faster than task1's)
Tasks have priorities. User can start a task with higher priority so all the task's steps will be tried to be executed before all others.
I hope the UI can be responsive as much as possible.
So I was going to creating a NSThread with lowest priority.
I put a custom priority event queue in that thread. Every step of a task becomes an event (work unit). So, for example, step 1 downloading a json becomes an event. After downloading, the event generates another event for step 3 and be put into the queue. every event has its own priority set.
Now I see this article: Concurrency and Application Design. Apple suggests that we Move Away from Threads and use GCD or NSOperation.
I find that NSOperation match my draft design very much. But I have following questions:
In consideration of iPhone/iPad cpu cores, should I just use one NSOperationQueue or create multiple ones?
Will the NSOperationQueue or NSOperation be executed with lowest thread priority? Will the execution affect the UI response (I care because the steps involve computations)?
Can I generate a NSOpeartion from another one and put it to the queue? I don't see a queue property in NSOperation, how do I know the queue?
How do I cooperate NSOperationQueue with CoreData? Each time I access the CoreData, should I create a new context? Will that be expensive?
Each step of a task become a NSOperation, is this design correct?
Thanks
In consideration of iPhone/iPad cpu cores, should I just use one NSOperationQueue or create multiple ones?
Two (CPU, Network+I/O) or Three (CPU, Network, I/O) serial queues should work well for most cases, to keep the app responsive and your programs streaming work by what they are bound to. Of course, you may find another combination/formula works for your particular distribution of work.
Will the NSOperationQueue or NSOperation be executed with lowest thread priority? Will the execution affect the UI response (I care because the steps involve computations)?
Not by default. see -[NSOperation setThreadPriority:] if you want to reduce the priority.
Can I generate a NSOpeartion from another one and put it to the queue? I don't see a queue property in NSOperation, how do I know the queue?
Sure. If you use the serial approach I outlined, locating the correct queue is easy enough -- or you could use an ivar.
How do I cooperate NSOperationQueue with CoreData? Each time I access the CoreData, should I create a new context? Will that be expensive?
(no comment)
Each step of a task become a NSOperation, is this design correct?
Yes - dividing your queues to the resource it is bound to is a good idea.
By the looks, NSOperationQueue is what you're after. You can set the number of concurrent operations to be run at the same time. If using multiple NSOperation, they will all run at the same time ... unless you handle a queue on your own, which will be the same as using NSOperationQueue
Thread priority ... I'm not sure what you mean, but in iOS, the UI drawing, events and user interaction are all run on the main thread. If you are running things on the background thread, the interface will still be responsive, no matter how complicated or cpu-heavy operations you are running
Generating and handling of operations you should do it on the main thread, as it won't take any time, you just run them in a background thread so that your main thread doesn't get locked
CoreData, I haven't worked much with it specifically, but so far every Core~ I've worked with it works perfectly on background threads, so it shouldn't be a problem
As far as design goes, it's just a point of view ... As for me, I would've gone with having one NSOperation per task, and have it handle all the steps. Maybe write callbacks whenever a step is finished if you want to give some feedback or continue with another download or something
The affection of computation when multithreading is not going to be different just because you are using NSThread instead of NSOperation. However keep in mind that must current iOS devices are using dual core processors.
Some of the questions you have are not very specific. You may or may not want to use multiple NSOperationQueue. It all depends on how you want to approach it. if you have different NSOperation subclasses, or different NSBlockOperations, you can manage order of execution by using priorities, or you might want to have different queues for different types of operations (especially when working with serial queues). I personally prefer to use 1 operation queue when dealing with the same type of operation, and have a different operation queue when the operations are not related/dependable. This gives me the flexibility to cancel and stop the operations within a queue based on something happening (network dropping, app going to the background).
I have never found a good reason to add an operation based on something happening during the execution of a current operation. Should you need to do so, you can use NSOperationQueue's class method, currentQueue, which will give you the operation queue in which the current operation is operating.
If you are doing core data work using NSOperation, i would recommend to create a context for each particular operation. Make sure to initialize the context inside the main method, since this is where you are on the right thread of the NSOperation background execution.
You do not necessarily need to have one NSOperation object for each task. You can download the data and parse it inside the NSOperation. You can also do the data download abstractly and do the data manipulation of the content downloaded using the completion block property of NSOperation. This will allow you to use the same object to get the data, but have different data manipulation.
My recommendation would be to read the documentation for NSOperation, NSBlockOperation and NSOperationQueue. Check your current design to see how you can adapt these classes with your current project. I strongly suggest you to go the route of the NSOperation family instead of the NSThread family.
Good luck.
Just to add to #justin's answer
How do I cooperate NSOperationQueue with CoreData? Each time I access
the CoreData, should I create a new context? Will that be expensive?
You should be really careful when using NSOperation with Core Data.
What you always have to remember here is that if you want to run CoreData operations on a separate thread you have to create a new NSManagedObjectContext for that thread, and share the main's Managed Object Context persistant store coordinator (the "main" MOC is the one in the app delegate).
Also, it's very important that the new Managed Object Context for that thread is create from that thread.
So if you plan to use Core Data with NSOperation make sure you initialize the new MOC in NSOperation's main method instead of init.
Here's a really good article about Core Data and threading
Use GCD - its a much better framework than NS*
Keep all your CoreData access on one queue and dispatch_async at the end of your routines to save back to your CoreData database.
If you have a developer account, check this WWDC video out: https://developer.apple.com/videos/wwdc/2012/?id=712

Correct way to poll a webservice in an IPhone app

I am trying to determine the best strategy to poll a webservice once a minute, parse the xml returned and then update an object stored in a shared instance. This process needs to run in a separate thread, and will continue as long as the app is running.
It seems that I could put all the code to call the webservice and parse the xml into an NSOperation and add that NSOperation to an NSOperationQueue stored in the app delegate as soon as the app launches.
Is it a correct approach to use an NSTimer inside the main method of the NSOperation so that the operation will loop once a minute, indefinitely? In that scenario the NSOperation would never actually return - this seems what I want but I am not sure if this is the right way to think about it.
The problem I am trying to solve is of course extremely common, so I am trying to figure out the correct way to implement it. Any advice greatly appreciated.
The real correct way to do it is to use push notifications. If any of your users have cell plans with limited data or data charged based on usage, they will thank you for it.
But if you insist on polling, you may as well use the NSTimer directly rather than messing with a timer inside an NSOperation. This will run on the main thread, but you could have the timer callback use performSelectorInBackground:withObject: to do processing in the background. Or you could just skip the timer altogether and run the whole polling sequence on a separate NSThread, and use sleepForTimeInterval: to delay between polls.
I would highly recommend you take a look at ASIHTTPRequest. What an amazing little class, and really well documented.
Edit:
Take a look at this answer for what seems to be the optimal solution.
one approach: create a thread and use a run loop, updating or idling as appropriate. then you can perform the request from the secondary thread and post it to the rest of the app after it's been parsed/prepped.
this way offers more control over pause/resume/delays/timing, and you can easily control the number of active requests (which should be exactly zero or one).
I wouldn't use NSTimer for this problem/design. I would create NSThread from the AppDelegate when the application starts. I would lower the priority of this thread. Inside the NSThread main method is basically a loop.
-(void)main {
while(true) {
// get raw data from url
// hash the result
// compare the hash to the last time
if (currentHash != lastHash) {
// post a notification to default center with the new data
lastHash = currentHash;
}
// sleep the thread sleepForTimeInterval
}
}
Your Model object would subscribe to the notification from the thread and parse the new data and updates ivars. Your View object would listen to the Model using KVO and display any updates/changes.

Running C code in an Objective C (Cocoa) Thread (for iOS)

First of all, I am a a very new Objective C/Cocoa iOS Developer but I've written C/C++ applications before.
So I managed to run the Rabbitmq-c (http://hg.rabbitmq.com/rabbitmq-c/) client inside my iPhone App, and I can connect to Rabbitmq directly from my app and even consume a queue item. So all's good.
Now my problem is, my iPhone app needs to use the rabbitmq-c library to poll for incoming messages in from the server. Probably there will be, an almost infinite while loop.
Do I have to take this to a new thread? Ideally, I want to wrap the rabbitmq-c class as an Async objective C class and use NSNotification (or something similar) to notify my UI. I'm a bit leery of creating a new thread, as I read about stuffs like Runloop etc can solve a lot of problems without using an extra thread.
What is the best way for me to go about this? Any examples of code or directions would be helpful. Please remember, I am not dealing with an Objective C code/Coca rabbitmq library here, I'm using C code inside my iPhone app.
Thanks
Subrat
don't block the main thread with your server polling.
since the operation never ends, create your own thread and run loop for this server polling. you can potentially use the run loop (each thread has one) instead of the infinite while. the alternatives involve regularly spawning threads. it's easiest to just use one thread for this.
once you have an update, post the notification (if you choose NSNotification) from the main thread -- UIKit is meant to operate from the main thread only.
for samples, i'd begin with samples related to NSRunLoop and CFRunLoop.
good luck
You can also create custom delegates for updating the UI, or the stuff related to UIKit.
Notifications might be a little easier to code and offer the advantage that multiple objects can observe one notification. With delegates, such a thing cannot be done without modifying the delegating object (and is unusual).
Some advantages of delegating:
The connection between delegating object and delegate is made clearer, especially if implementing the delegate is mandatory.
If more than one type of message has to be passed from delegatee to delegate, delegating can make this clearer by specifying one delegate method per message.
Or other way is to write method to receive messages. This method can have infinite loop.
Later you can put this method in background thread like this.
[self performSelectorInBackground:#selector(receiveMessages) withObject:nil];

Killing a thread or an alternative

Is there any way I can kill a thread spawn through:
[NSThread detachNewThreadSelector:#selector(serverFetchInThread) toTarget:self withObject:nil];
The scenario I am working on is that in my main thread I am letting user enter data in my search bar and what ever user is typing I need to send to server for searching in a separate thread. Now, if user changes his selection by deleting old data and entering new data I do not want the previous thread to waste its time, kill it and spawn a new thread with new data.
Be there any other better way to handle this situation, please guide me.
No, there is no way to kill a thread from another thread. And for good reason as there is no way to do so in a fashion where the targeted thread is killed without risk of crashing the app.
To directly answer your question; you need to have some kind of a flag that indicates to the thread that it should stop doing whatever it is doing and exit.
However, a couple of questions are raised by your question:
First, why are you using threads and not using GCD? Concurrency via GCD or NSOperation is the generally recommended way to solve such problems.
Secondly, if you are talking to a server, are you using HTTP (most of the time, that is the case)? If so, why not directly use the asynchronous features of NSURL and friends?
Have a good look at using NSOperationQueue.
You can subclass NSOperation it to wrap up your server communications, and even make that queue serial (maximum operations = 1).
If a server operation is not yet finished and user has generated more input, you can cancel the existing one, and add the new one.
Due to the effect of the NSOperation wrapping your connection, you can just use the simple synchronous version and keep the connection handling very straightforward.
Also worth mentioning is compatibility. I would prefer to use GCD and blocks, but for compatibility, NSOperationQueue is required.

Is there any sample code to do iPhone mulitithreading tasks?

I have some slow internet task to save and load file, I'd like to do those slow tasks in some background thread. I am wondering whether that's doable, and if it is, any sample code?
Then after it is finished, I'd like it to notice back to the main thread, so that I could update the UI.
Take a look at NSURLConnection. It will load an NSURL (using NSURLRequest) in the background, and send delegate methods regarding its status.
Ultimately the device you are running your code on has a single processor and cannot possibly load large quantities (gigabytes) of data. The best route, by is likely that suggested by Ben (NSURLConnection asynchronously) which gives you the added advantage of being able to cleanly cancel and handle error messages. While it isn't technically threaded in the way you probably think you want it to be, it is well integrated with the event loop and is non-blocking. If that is still not enough, I would suggest looking at NSOperation and NSOperationQueue. You can fire off an NSOperation sub-class object and perform the download there (I would still advise doing it asynchronously there so as to enable canceling, pausing, etc).
Log in to the iPhone Developer Center and search for Introduction to Threading Programming. Or, maybe you can log in and use this link:
http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Multithreading/Introduction/chapter_1_section_1.html#//apple_ref/doc/uid/10000057i-CH1-SW1
If you do decide you need a background thread even after using asynchronous HTTP calls to gather the data, don't forget to wrap the background thread code in a new NSAutoReelasePool and then release it at the end.