This question already has answers here:
How do I perform several methods in sequence?
(2 answers)
Closed 8 years ago.
In my application I have four methods like
- (void)Method1;
- (void)Method2;
- (void)Method3;
- (void)Method4;
I want to execute these methods one after another. I search for this one in some sources they are using "dispatch_Time" in some sources they are using "NSThread sleepForTimeInterval:" But in my application I don't want to execute those methods using time. I want to execute them if the previous method execution is completed. How can I do this?
Solution Overview
The right way of doing this is to enqueue the methods onto a serial queue.
A serial queue executes one task at a time and thus ensures that a task is only executed once all it's predecessors were executed.
There are several ways of accomplishing what you wish. I will describe 2 of them, one using Grand Central Dispatch and one using NSOperationQueue.
Grand Central Dispatch
Create a queue onto you will enqueue your task. A good practice would be to keep the queue as an instance variable so that you could access it from instance methods (unlike NSOperationQueue, by default custom dispatch queues are serial by default, i.e. they execute one task at a time):
dispatch_queue_t my_queue = dispatch_queue_create("com.suresh.methodsqueue", NULL);
self.methods_queue = my_queue;
Enqueue your methods onto the designated queue one after the other:
dispatch_async(self.methods_queue, ^{ [someObject method1] });
dispatch_async(self.methods_queue, ^{ [someObject method2] });
dispatch_async(self.methods_queue, ^{ [someObject method3] });
dispatch_async(self.methods_queue, ^{ [someObject method4] });
Further re GCD in Apple's developer guides.
Operation Queue
Initialize a queue:
NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
self.methods_queue = aQueue;
Make sure the queue is serial:
[self.methods_queue setMaxConcurrentOperationCount:1]
Enqueue the methods onto the queue, there's several ways of doing so, the following requires the least amount of code:
[self.methods_queue addOperationWithBlock:^{ [someObject method1] }];
[self.methods_queue addOperationWithBlock:^{ [someObject method2] }];
[self.methods_queue addOperationWithBlock:^{ [someObject method3] }];
[self.methods_queue addOperationWithBlock:^{ [someObject method4] }];
Further re Operation Queues in Apple's developer guides.
If the methods don't return until they've finished their work, just call them in order:
[self Method1];
[self Method2];
[self Method3];
[self Method4];
Otherwise, you need to use something like dispatch groups.
call first method somewhere like
[self (void)Method1];
and implement like
(void)Method1{
// logic here
[self (void)Method2];
}
(void)Method2{
// logic here
[self (void)Method3];
}
and so on ...............
Related
I have a thread call in objective C and i want once this thread ends i want to return a value ;the value will be changed inside the thread
So the method must not return the value unless the tread ends
Here is the code i use:
[NSThread detachNewThreadSelector:#selector(CheckBeforePrint2) toTarget:self withObject:nil];
This is My Full Code
- (NSString *) getStatusPrinter:(NSString *) printerSerialNumber
{
self.printerSN = printerSerialNumber;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *Result = #"-1";
[NSThread sleepForTimeInterval:2.0f];
[NSThread detachNewThreadSelector:#selector(CheckBeforePrint) toTarget:self withObject:Result];
[pool release];
return Result;
}
Now i want to wait for the value of Result and return it i am using
cocoa
And i am returning the value to another app
Can anyone help in that.
Thanks
What you are doing here requires the use of a semaphore for example. If there is nothing more to it than you are providing here then a completion block to a background running method is the best way to do it. See option 2 below
Either way, why do you want the parent thread (the thread dispatching a new thread) to wait for another thread? If the parent thread is waiting, it is locked until the dispatched thread is done (according to your requirement). This situation is redundant because the whole point of dispatching another thread is so that the parent thread can continue with other things. Unless of course the parent thread needs to wait for multiple threads, then it makes sense to lock it.
Having said that, its best to just let the dispatching thread / parent thread do the processing that you are dispatching on to another thread. Im only saying this given the details you have provided.
OPTION 1 use a semaphore
Use a semaphore to lock and unlock parent thread
-(void)getStatusPrinter()
{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[NSThread detachNewThreadSelector:#selector(checkBeforePrint2) toTarget:self withObject: semaphore];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[self print]; // this will run after semaphore is unlocked
}
-(void)checkBeforePrint2:(dispatch_semaphore_t)sem
{
//this is within child thread
//do some processing,
dispatch_semaphore_signal(sem);//unlock semaphore
}
But, as I mentioned before, this situation seems redundant because the parent thread waits (therefore unusable) for child thread; why can't it just do the work itself...
OPTION 2 use completion block (PREFERABLE)
Use a completion block that you pass to the child thread. This allows the parent thread to continue. If it is the main thread it remains free for UI stuff.
-(void)getStatusPrinter()
{
[self checkBeforePrint2WithCompletion: ^{
[self print];
}];
//continue with more stuff
}
-(void)checkBeforePrint2WithCompletion:(void (^ __nullable)(void))completion
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//do something before executing completion code
if(completion){
completion();
}
});
}
Disclaimer: there may be typos in this code as it was not written in an editor/ IDE. Please comment if any.
UPDATE in response to added details.
Okay, for the fact that you said you need to return the result to another application, that means the entry thread at getStatusPrinter can not be allowed to return after dispatching a new thread. If you really need to create a new thread for CheckBeforePrint then the entry thread has to wait. That to me is pointless. You can simply run everything on the entry thread.
If you are using openURL:options:completionHandler: then the entry thread doesn't need to wait. The value of result can be passed back within the completion block.
Please refer to Apple's documentation on openURL with a completion handle
I have two methods as loadTopicPostsFromDB and loadTopicPosts. In the loadTopicPostsFromDB method I am updating the value of a global NSString called strLastTimeStamp which should use in the loadTopicPosts. Thus, I want to execute loadTopicPostsFromDB first and after it finished(global string updated) I want to execute loadTopicPosts method.
This is how I did it. But, currently loadTopicPosts method executes before updating the global strLastTimeStamp, so always I get a wrong strLastTimeStamp.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
[self performSelectorOnMainThread:#selector(loadTopicPostsFromDB) withObject:nil waitUntilDone:NO];
});
dispatch_group_notify(group, queue, ^{
NSLog(#"LoadDBCompleted");
[self loadTopicPosts];
});
How can I do this, please advice me on what is the wrong in this implementation.
performSelectorOnMainThread: is finished as soon as iOS has put the task into a queue. The selector has most likely not even started running when the call returns. And really, you shouldn't be using performSelectorOnMainThread at all - the function isn't available in Swift, for good reason. The solution is a lot easier (fix the problems yourself):
dispatch_async (dispatch_get_main_queue (), ^{
[self loadTopicsFromDB];
[self loadTopicPosts];
});
You probably want to perform loadTopicsFromDB on a background thread though.
When you are doing something using network connection I advice you to use blocks to handle the endpoint of the call.
It is pretty simple to write in this code
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self loadTopicsFromDB: ^(BOOL success, NSError *error) {
[self loadTopicPosts];
}];
});
In my app I need to load up data from multiple sources and put them together in a table view. Gathering each of the sources one after another would take forever. To get around this I need to run all of the download operations together. Since they are download tasks, in theory I could just run them, but the issue is that only part of the code on the thread runs asynchronously, which means it will need the main thread to complete the operation.
So in order to get ALL of it running in the background, I need to use GCD, which I don't have much experience with.
//DataLoader.m
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
[self.webLoader getFeedWithCompletion:self.thatOtherCompletionBlock];
[self.otherDataLoader getDataWithCompletion:self.completionBlock];
[self.thatDataLoader getThatDataWithCompletion:self.anotherCompletionBlock]
dispatch_async(dispatch_get_main_queue(), ^(void){
});
});
However, since part of the task is already asynchronous, I need to figure out where to put GCD code.
I could put it before starting the task, like I did above. This could work, however, since the tasks are already partially run in the background (in some cases I cannot change that), it seems wasteful to be running a task that already runs partially in the background in the background. Why run something that already runs in a background thread in another thread?
Another option would be to use GCD in the actual class that gets the feed (ex. webloader), putting it on all code that isn't running in the background
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
.......
});
Which way is better?
There is also another problem. Since part of the tasks are asynchronous, they use completion blocks. Not only do I need to also run the completion blocks in the background, I need to figure out which one is the last one to finish, so I can run some code to clean up and neatly package and ship the data to the view controller.
The way I thought of would be to use a BOOL for each task, simply changing it to true when it's done. Then in my completion blocks I can check if all the other tasks are complete, and if so, run the clean up code. However, this may not be the most elegant solution.
What would be the best way to deal with these tasks, ensuring that it all happens in the background?
GCD groups could easily be used for this. Groups allow you to track arbitrary "members" of the group, and hook a block up to run when all members of the group have finished. It's quite handy. For example (using your code):
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group); // + 1
[self.webLoader getFeedWithCompletion: ^{
self.thatOtherCompletionBlock();
dispatch_group_leave(group); // - 1
}];
dispatch_group_enter(group); // + 1
[self.otherDataLoader getDataWithCompletion:^{
self.completionBlock();
dispatch_group_leave(group); // - 1
}];
dispatch_group_enter(group); // + 1
[self.thatDataLoader getThatDataWithCompletion:^{
self.anotherCompletionBlock();
dispatch_group_leave(group); // - 1
}];
dispatch_group_notify(group, dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// This will get executed once all three of the prior completion blocks have been run.
// i.e. when the group "count" goes to zero.
});
dispatch_release(group);
});
You could also, albeit a bit circuitously, use NSOperation's inter-operation dependency feature to achieve this. Like this:
NSOperationQueue* q = [[[NSOperationQueue alloc] init] autorelease];
NSOperation* completionA = [NSBlockOperation blockOperationWithBlock: self.thatOtherCompletionBlock];
NSOperation* completionB = [NSBlockOperation blockOperationWithBlock: self.completionBlock];
NSOperation* completionC = [NSBlockOperation blockOperationWithBlock: self.anotherCompletionBlock];
NSBlockOperation* afterAllThree = [[[NSBlockOperation alloc] init] autorelease];
[afterAllThree addDependency: completionA];
[afterAllThree addDependency: completionB];
[afterAllThree addDependency: completionC];
[afterAllThree addExecutionBlock:^{
// This will get executed once all three of the prior completion blocks have been run.
}];
// Kick off the tasks
[q addOperationWithBlock:^{
[self.webLoader getFeedWithCompletion: ^{ [q addOperation: completionA];}];
[self.otherDataLoader getDataWithCompletion:^{ [q addOperation: completionB]; }];
[self.thatDataLoader getThatDataWithCompletion:^{ [q addOperation: completionC]; }];
}];
I personally prefer the dispatch_group method, but they would both get the job done.
I need to perform an asynchronous function execution because it is blocking the main thread and hence the UI is not available.
After looking at the questions in stackoverflow, I know there are three ways to do asynchronous function.
An example:
[NSThread detachNewThreadSelector:#selector(showSpinner:) toTarget:self withObject:self.view];
// or
[self performSelectorInBackground:#selector(showSpinner:) withObject:self.view];
// or
NSInvocationOperation *invOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(showSpinner:) object:self.view];
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperation:invOperation];
// or
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
[self showSpinner:self.view];
});
});
My question is how does performSelectorInBackground and detachNewThreadSelector return back to main thread? how do you know that they are done?
A couple of thoughts:
You might want to check Migrating Away From Threads in the Concurrency Programming Guide, which makes a compelling argument for dispatch queues and operation queues, which are discussed earlier in that same guide.
Also, as you delve into various asynchronous operations, remember, do time consuming stuff in background queues/threads, but always dispatch UI stuff back to the main queue. I only mention that because your task, showSpinner sounds a lot like a UI task, which you would never want to do in a background queue/thread. If it has some "expensive" non-UI related tasks, then fine, do that in the background, but make sure the UI stuff gets dispatched back to the main queue.
There are, as an aside, other renditions of the operations queues, e.g., block operations:
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperationWithBlock:^{
// do some slow stuff in the background here
// ok, now do UI stuff in the main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self showSpinner:self.view];
}];
}];
This is roughly equivalent to the GCD (dispatch queue) rendition:
dispatch_queue_t dispatchQueue = dispatch_queue_create("com.ramshad.app", 0);
dispatch_async(dispatchQueue, ^{
// do some slow stuff in the background here
// ok, now do UI stuff in the main queue
dispatch_async(dispatch_get_main_queue(), ^{
[self showSpinner:self.view];
});
});
There are tons of subtle pros and cons between the operation queues and dispatch queues (which we should not get into here because it's been discussed hundreds of times elsewhere on Stack Overflow), but both let you do surprisingly rich asynchronous operations with less complexity than traditional thread programming.
If you decide to stick with threads versus operation and/or dispatch queues (which I wouldn't necessarily recommend), you might want to check out the Threading Programming Guide.
To identify performSelectorInBackground & detachNewThreadSelector end of execution,call a method at the end of the thread method on main thread.
Additionaly NSThread provides an propery as isFinished which returns a Boolean value that indicates whether the receiver has finished execution.
Example:
[self performSelectorOnMainThread:#selector(threadMethod)
withObject:nil
waitUntilDone:NO];
or
[NSThread detachNewThreadSelector:#selector(threadMethod)
toTarget:self
withObject:nil];
-(void)threadMethod{
//here your implementation code
//here call the end notification method.
[self performSelectorOnMainThread:#selector(ThreadExecutionDone)
withObject:nil
waitUntilDone:YES];
}
-(void)ThreadExecutionDone{
//end of the performSelectorInBackground or detachNewThreadSelector.
}
I have a method that builds a package, sends it to a web service, gets a package back, opens it and returns me a nsdictionary. How can I call it on a background queue in order to display a HUD while it requests the data?
You could detach a new thread like following
- (void) fetchData
{
//Show Hud
//Start thread
[NSThread detachNewThreadSelector:#selector(getDataThreaded)
toTarget:self
withObject:nil];
}
- (void) getDataThreaded
{
//Start Fetching data
//Hide hud from main UI thread
dispatch_async(dispatch_get_main_queue(), ^{
//Update UI if you have to
//Hide Hud
});
}
Grand central dispatch (gcd) provides great support for doing what you ask. Running something in the background using gcd is simple:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_NORMAL, 0) ^{
NSDictionary* data = [self fetchAndParseData];
dispatch_async(dispatch_get_main_queue(), ^{
[self dataRetrieved:data];
});
});
This call will return immediately (so your UI will continue to be responsive) and dataRetrieved will be called when the data is ready.
Now, depending on how fetchAndParse data works it may need to be more complicated. If you NSURLConnection or something similar, you might need to create an NSRunLoop to process data callbacks on the gcd thread. NSURLConnection for the most part is asynchronous anyway (though callbacks like didReceiveData will be routed through the UI thread) so you can use gcd only to do the parsing of the data when all the data has been retrieved. It depends on how asynchronous you want to be.
In addition to previous replies, why don't you use NSOperation and NSOperationQueue classes? These classes are abstractions under GCD and they are very simple to use.
I like NSOperation class since it allows to modularize code in apps I usually develop.
To set up a NSOperation you could just subclass it like
//.h
#interface MyOperation : NSOperation
#end
//.m
#implementation MyOperation()
// override the main method to perform the operation in a different thread...
- (void)main
{
// long running operation here...
}
Now in the main thread you can provide that operation to a queue like the following:
MyOperation *op = [[MyOperation alloc] initWithDocument:[self document]];
[[self someQueue] addOperation:op];
P.S. You cannot start an async operation in the main method of a NSOperation. When the main finishes, delegates linked with that operations will not be called. To say the the truth you can but this involves to deal with run loop or concurrent behaviour.
Here some links on how to use them.
http://www.cimgf.com/2008/02/16/cocoa-tutorial-nsoperation-and-nsoperationqueue/
https://developer.apple.com/cocoa/managingconcurrency.html
and obviously the class reference for NSOperation