I'm newbie with this so forgive me with any mistakes...
My situation:
- (id)initWith... //Some arguments
There's an initialization method that returns an object. It does a lot of work to set its instance variables with the values of the arguments. To maximize performance I divide the job in two threads. One thread sets a set of related variables and the other thread another bunch of them.
- (id)initWith:arguments {
self = [super init];
if (self) {
[NSThread detachNewThreadSelector:#selector(setFirstSetOfVariables:) toTarget:self withObject:argObject];
[self setSecondSetOfVariables:arguments];
//Check if the thread finished its work and return the value
return self;
}
To make it easy think both sets of vars that the method has to set don't have any relationship. Then my question is: how do I check if the first thread finished? I could create a BOOL var but I'd have to create a loop to check. I could also call a method to say it's ready. But as I don't know a lot of it, I don't know wether a method invoked inside a thread would be run in the main thread or in the other. Sorry. Thank you for any info.
You can do it this way to simplify the whole thing
ComplicatedObject *myComplicatedObject = [ComplicatedObject alloc] init;
[myComplicatedObject setLongTimeTakingVariables];
and in the ComplicatedObject create a method like
-(void)setLongTimeTakingVariables{
dispatch_async(dispatch_get_global_queue(),^{ All of your code can go here. Infact you need not split it into two sections, because it will happen in the background and your userinterface will not get affected }
But if you want to split then you can do
dispatch_async(dispatch_get_global_queue((DISPATCH_QUEUE_PRIORITY_LOW, 0)),^{
some work here
}
dispatch_async(dispatch_get_global_queue((DISPATCH_QUEUE_PRIORITY_LOW, 0)),'{
some other work here
}
Read the Concurrency Programming Guide and every thing is explained very clearly.
Related
Guys I need some help to architect my multithreading in iOS.
I'm using ARC in my code.
So basically I need following,
In my main thread nstimer fire some method which should be executed in a separate thread, that thread does some calculation and puts data into some ivar, and another thread should read data from that ivar and do some other calculation, i.e. if there is no data the second thread should wait until there is any.
So basically I would like to hear some advice which technology is the best choice for my task, to use cocoa thread (NSThread), GCD or Operation queues.
Also can someone please provide me with some pseudo code on aspects of mutual blocking/synchronization between two threads.
Since you are saying that some calculations should wait for other calculations to finish, I would say that you should have a look at NSOperation and set dependencies for the different operations (using addDependency).
Unless you left something our of your problem description, that is a perfect fit for GCD/block combo. In fact, I wouldn't even use a NSTimer (GCD provides a better alternative - see dispatch_source_create for example of creating GCD based timer), but that's your call, and not what the question asked. Anyway, with GCD...
- (void)handleTimer:(NSTimer *)timer {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
__block id someObject;
// Do work... manipulate someObject in some manner...
// When done, invoke other thread... main thread in this case
dispatch_async(dispatch_get_main_queue(), ^{
// This code is running in a different thread, and can use someObject directly
});
});
}
I have a toolkit that I need to work with (to interface with a remote service). This toolkit queries the remote service and asks for results. It does this asynchronously, which in most cases is good, but not for creating concise methods. I want to make methods similar to the following:
-(NSArray *)getAllAccounts {
NSString *query = #"SELECT name FROM Account";
//Sets "result" to the query response if no errors.
//queryResult:error:context: is called when the data is received
[myToolkit query:query target:self selector:#selector(queryResult:error:context:) context:nil];
//Wait?
return result.records;
}
The problem is, inside the toolkit the methods call each other using #selector, not direct calls, so getting return values is difficult. Further, the actual query uses:
NSURLConnection *connection = [[[NSURLConnection alloc] initWithRequest:aRequest delegate:self] autorelease];
Which is asynchronous. By the time the data has been received from the service, my method has long ago returned... without the information. So my question is this: Is there a way to pause execution until the data has been returned? Could I accomplish this using a second thread to get the data while the main thread rests (or using 3 threads so the main thread doesn't rest?)
I don't want to edit the toolkit to change their method (or add a new one) to be synchronous, so is there a way to make a method as I want?
You might want to consider NOT making it all synchronous, especially if the sample code in your post is run on your main application thread. If you do that, the main thread will block the UI and the application will cease to respond until the remote transaction is complete.
Therefore, if you really insist on the synchronous approach, then you should definitely do it in a background thread so that the UI does not become unresponsive, which can actually lead to your App getting killed by the OS on iphone.
To do the work in a background thread, I would strongly recommend using the Grand Central Dispatch stuff, namely NSBlockOperation. It will free you from having to actually create and manage threads and makes your code pretty neat.
To do the synchronous thing, take a look at the NSCondition class documentation. You could do something like the following:
NSCondition* condition = ...;
bool finished = NO;
-(NSArray *)getAllAccounts {
[condition lock];
NSString *query = #"SELECT name FROM Account";
//Sets "result" to the query response if no errors.
//queryResult:error:context: is called when the data is received
[myToolkit query:query target:self selector:#selector(queryResult:error:context:) context:nil];
while (!finished)
[condition wait];
[condition unlock];
return result.records;
}
Then in the method called by the toolkit to provide the results you'd do:
- (void) queryResult:error:context: {
// Deal with results
[condition lock]
finished = YES;
[condition signal];
[condition unlock];
}
You'd probably want to encapsulate the "condition" and "finished" variables in your class declaration.
Hope this helps.
UPDATE: Here is some code to offload the work to a background thread:
NSOperationQueue* queue = [NSOperationQueue new];
[queue addOperationWithBlock:^{
// Invoke getAllAccounts method
}];
Of course, you can keep the queue around for later use and move the actual queuing of the work to inside your method call to make things neater.
The way to wait is to return from your current code. Finish up doing what you want done after the wait, in the asynchronous callback method you specify. What's so difficult about that?
Any synchronous waits in the main UI thread will block the UI and make the user think your app has locked up, which is likely far worse than your thinking the code isn't concise enough.
I need ideas on the following -
In the main thread at some point of execution say Point A(sequential logic), I need to remember the state of execution and delegate the execution of some other logic onto another thread, and let the main thread handle the UI events etc. When the delegated logic completes on the other thread then the flow of execution should continue from the point A and should recollect the entire execution context and proceed as if it never paused there.
Regards,
Sunil Phani Manne
It's hard to implement this exactly the way you're saying (for example do(things)... yield(other_thread); ...do(more_things);.
Here are a couple other options I can think of (you'd have to implement these yourself, using delegates or notifications for example; I'm just giving a basic outline of how it would work):
do(things)
[object doStuffOnOtherThreadWithCallback:^{ // block-based
do(more_things)...
}];
or...
do(things)
[object doStuffOnOtherThreadWithCallbackTarget:self // target/selector-based
selector:#selector(callbackSelector)];
}
- (void)callbackSelector {
do(more_things)...
}
One option you have is encapsulating the whole sequential logic that comes after Point A in your delegate and then execute it on the main thread when the secondary thread ends.
In other words, when you start the thread by calling, e.g.
[NSThread detachNewThreadSelector:sel toTarget:target withObject:delegate]
you can implement your target target so that it has a specific selector completion that is called at the end of sel on the main thread, like this (this is the your delegate class):
#implementation YOURDelegateClass {
.....
-(void)completion {
}
-(void)sel {
...
...
[self performSelectorOnMainThread:#selector(#"completion") withObject:self];
}
}
Of course you have many sub-options available here, like using a different call to start the background execution, etc.
The important point is that: you have to encapsulate in a selector all the logic that comes after Point A, and that you have to schedule the execution of this selector on the main thread, in order to get back to your context (although your context will have changed in the meantime because you will also have updated the UI).
EDIT:
Having to schedule the execution on the main thread defeats blocks from being suitable for this kind of callback. On the other side, block have the advantage that they in some limited sense give you access to the same lexical context in which the block was defined (which is roughly what you call context).
A workaround for this could be the following. Before detaching the new thread, store in a delegate the block you would like to execute at completion:
typedef void(^CustomBlock)(void);
#property (nonatomic, copy) CustomBlock customBlock;
....
int a = ...
delegate.customBlock = ^{
NSLog(#"hello %d.....", a);
}
[NSThread detachNewThreadSelector:sel...
....
-(void)completion {
[self customBlock];
}
Of course, you only get the context preservation that is guaranteed to you by block. But here you hit against a limit of the language.
If you need more context preservation, then the only possibility is encapsulating that context in your delegate class ivars.
One thing is for sure. There, most probably, isn't any direct feature in Cocoa that does that. Since you're saying that you can't duplicate the resources onto the new thread (for a very good reason), I am going to suggest that you make use of NSUndoManager. For every change you make in the thread, push an undo operation for that change onto the undo manager. At the end of the thread, execute all the undo operations in the undo manager object. This should, if done correctly, restore your state. Now, since the idea is untested, there could be a chance that not all actions can be undone. You will have to check that out first.
I have a library project that uses ASIHTTPRequest to make URL requests and parse the responses. The library will be used by a separate iPhone app project.
If my iPhone controller code responds to a touch event, then calls into the library to make URL requests, how do I best perform the requests asynchronously?
In the library, if I use the delegate pattern for asynchronous requests as shown in the ASIHTTPRequest sample code, how do I return data from the library back to the calling code in the iPhone controller?
If I instead make synchronous URL requests with ASIHTTPRequest inside the library, what's the easiest way to put the calls to the library from the iPhone controller on a separate thread to avoid tying up the UI thread?
I'm no ASIHTTPRequest expert (NSURLRequest has always done me fine), but from a quick poke at the code, it looks like you'd use its delegate and didFinishSelector properties to give it someone to tell when the URL request is finished. So, for example:
- (void)startURLRequest
{
ASIHTTPRequest *myRequest;
/* code to set the request up with your target URL, etc here */
myRequest.delegate = self;
myRequest.didFinishSelector = #selector(HTTPRequestDidFinish:);
/* ... */
[myRequest startAsynchronous];
}
- (void)HTTPRequestDidFinish:(ASIHTTPRequest *)request
{
NSLog(#"Request %# did finish, got data: %#", request, request.data);
[myTargetForData didReceiveData:request.data fromURL:request.originalURL];
}
Apple explicitly recommend that you use the built-in runloop style mechanisms for asynchronous HTTP fetching, not separate threads. Using separate threads is likely to result in worse performance — at least in terms of battery life and/or device heat, even if it's still fast enough.
That said, as a learning point, by far the quickest way to switch something onto a separate thread and have it report back to the main thread (remember: UIKit objects may be messaged only from the main thread) is by changing this:
- (void)postResult:(NSString *)result
{
instanceOfUILabel.text = result;
}
- (void)doExpensiveOperationOn:(NSString *)source
{
/* lots of expensive processing here, and then... */
[self postResult:result];
}
- (IBAction)userWantsOperationDone:(id)sender
{
[self doExpensiveOperationOn:#"some value or another"];
}
Into this:
- (void)postResult:(NSString *)result
{
instanceOfUILabel.text = result;
}
- (void)doExpensiveOperationOn:(NSString *)source
{
/* we're on a thread without an autorelease pool now, probably we'll want one */
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* lots of expensive processing here, and then... */
/* in this simplified example, we assume that ownership of 'result' is here on this thread, possibly on the autorelease pool, so wait until postResult has definitely finished before doing anything that might release result */
[self performSelectorOnMainThread:#selector(postResult:) withObject:result waitUntilDone:YES];
[pool release];
}
- (IBAction)userWantsOperationDone:(id)sender
{
[self performSelectorOnBackgroundThread:#selector(doExpensiveOperationOn:) withObject:#"some value or another"];
}
There's about a million possible concurrency errors you can make by just going threaded without thinking about it though, and in that example an obvious problem is that whatever triggered the IBAction can [probably] trigger it several more times before doExpensiveOperationOn has finished. Multithreading is not something to be dashed into lightly.
For anyone's future reference, the easiest approach I found is to use the async request functionality built into ASIHTTPRequest, setting my library object as the delegate and setting the didFinishSelector: and didFailSelector: values to different methods inside my library for each request.
At the end of processing each response, I assign the parsed response (an NSString* or NSArray*) to a property of my library object instead of returning a value.
When my iOS view controller delegate is loaded, I add a change observer to each of the properties in the library using Key-Value Observing. When the response is parsed and assigned to the property in the library, the observeValueForKeyPath:ofObject:change:context: method is called in the code of my view controller delegate, and from there I can figure out which property was changed and therefore what UI needs to be updated.
I would like to have an object be callable from the main thread
MyObj* backgroundObject = [[MyObj alloc] initInBackground];
BOOL result = [backgroundObject computeResult];
But have all the methods of backgroundObject compute in another thread.
And also have backgroundObj be able to send messages to it's delegate. How can I do such a thing? Is it possible?
As others have pointed out, an NSObject doesn't exist on any one thread, a thread only comes into play when you start executing its methods.
My suggestion would be to not use manual threads for every time that a method is called on the object, but instead use NSOperations and an NSOperationQueue. Have an NSOperationQueue as an instance variable of the object, and have calls to the various methods on the object create NSOperations which are inserted into the queue. The NSOperationQueue will process these operations on a background thread, avoiding all of the manual thread management you would need to have for multiple accesses to methods.
If you make this NSOperationQueue have a maximum concurrency count of 1, you can also avoid locking shared resources within the object between the various operations that will be performed on a background thread (of course you'll still need to lock instance variables that can be accessed from the outside world).
For callbacks to delegates or other objects, I'd recommend using -performSelectorOnMainThread:withObject:waitUntilDone so that you don't have to think about making those delegate methods threadsafe.
See the Concurrency Programming Guide for more.
Sure, you can use NSThread for that, and have backgroundObject use performSelectorOnMainThread: to contact the delegate.
NSThread documentation
performSelectorOnMainThread:withObject:waitUntilDone:
Objects do not exist in threads AFAIK. The function you send to an object will always be performed on the thread you sent it from (unless you use NSThread or performSelectorOnMainThread or something along those lines).
What you need is a NSOperation and a block/delegate parameter to notify the caller of completion.
Look at the documentation of NSOperation and NSOperationQueues
You should use GCD:
/*
* I didn't initalised your object in background, because
* because in the most cases you need your object to stick around
* and only perfom the time consimung calculations in background
*/
MyObj* backgroundObject = [[MyObj alloc] initInBackground];
...
- (void)startBackgroundTask {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//in a perfectly async non blocking block :-)
BOOL result = [backgroundObject computeResult];
dispatch_async(dispatch_get_main_queue(), ^{
//post your result, or do something else with your result
[[NSNotificationCenter defaultCenter] postNotificationName:"backgroundComputeResultDone" object:[NSNumber numberWithBool:result]];
if (result) {
//do some stuff
}
});
});
}
Maybe you can take a look at these two videos from apple here:
WWDC 2011 - Session 210 - Mastering Grand Central Dispatch
WWDC 2011 - Session 308 - Blocks and Grand Central Dispatch in Practice