iOS: How to do hard work with data in background thread? - ios

I have a method like:
- (BOOL)shouldDoSomeWork {
BOOL result = // here I need do hard work with data in background thread and return result, so main thread should wait until the data is calculated and then return result;
return result;
}
How to implement that?

Are you looking for this:
-(void) startWork
{
//Show activity indicator
[NSThread detachNewThreadSelector:#selector(doSomeWork) toTarget:self withObject:nil];
}
-(void) doSomeWork
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
//Do your work here
[pool release];
[self performSelectorOnMainThread:#selector(doneWork) withObject:nil waitUntilDone:NO];
}
-(void) doneWork
{
//Hide activity indicator
}

Example how to do it with GCD:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Your hard code here
// ...
//BOOL result = ...
dispatch_async(dispatch_get_main_queue(),^{
[self callbackWithResult:result]; // Call some method and pass the result back to main thread
});
});

That's not typically how you would do it. You need something structured more like this:
- (void)doSomeWorkAndThen:(^void)block {
dispatch_async(dispatch_get_global_queue(0, 0), ^ {
// do
// some
// work
dispatch_sync(dispatch_get_main_queue(), ^ {
block();
});
});
That is, you keep the request and what you do afterwards in one place.

Common advice is to use the highest level of abstraction available to you to perform a task. As such NSThread should be relatively low down in the list of things you can do to execute work in the background.
The order you investigate APIs should be like this:
NSOperation / NSOperationQueue
Grand Central Dispatch (libdispatch)
NSThread
POSIX threads
With the first two you write your code as a "unit of work" and then put this work on a queue to be executed at some point. The system takes care of creating and destroying threads for you and the APIs are easy to work with. Here's an example using NSOperationQueue.
NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{
//Do work
//update your UI on the main thread.
[self performSelectorOnMainThread:#selector(workDone:) withObject:workResults waitUntilDone:NO];
}];
[self.operationQueue addOperation:blockOperation];
easy as that.

Related

Dispatch_sync or completion block difference in objective-c

I'm struggling with GCD and blocks. I'm trying to create a series of methods that require data from a previous one. I was thinking about 2 different ways to achieve it.
dispatch_sync serial queue
nested completion blocks
Don't you think the following 2 options return the same value? AS far as I read in Apple's dispatch queues, DISPATCH_QUEUE_SERIAL runs in FIFO order. So both options should return identical values.
What am I doing wrong here? and which one is the best approach?
Thanks for your help!
//Option 1
dispatch_queue_t delete_queue = dispatch_queue_create("delete_queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(delete_queue, ^{
[self dosomething];
});
dispatch_sync(delete_queue, ^{
[self dosomething2];
});
dispatch_sync(delete_queue, ^{
[self dosomething3];
});
//Option 2
-(void)dosomething1:(dispatch_block_t)completion;
-(void)dosomething2:(dispatch_block_t)completion;
-(void)dosomething3:(dispatch_block_t)completion;
[self dosomething:^{
[self dosomething2:^{
[self dosomething3:^{}];
}];
}];
-(void)dosomething:(dispatch_block_t)completion {
/*method logic here*/
completion();
}
-(void)dosomething2:(dispatch_block_t)completion {
/*method logic here*/
completion();
}
-(void)dosomething3:(dispatch_block_t)completion {
/*method logic here*/
completion();
}
Both code samples you have shown are equivalent to just:
[self dosomething];
[self dosomething2];
[self dosomething3];
In other words, both ways execute the methods synchronously, in order, and block the thread until they are done.
Also, as Ken Thomases said, none of your methods "return" anything, so your question about returning doesn't make sense.
It doesn't really make sense to do three separate calls to dispatch_sync() here:
dispatch_sync(delete_queue, ^{
[self dosomething];
});
dispatch_sync(delete_queue, ^{
[self dosomething2];
});
dispatch_sync(delete_queue, ^{
[self dosomething3];
});
You should instead just do them all in a single block:
dispatch_sync(delete_queue, ^{
[self dosomething];
[self dosomething2];
[self dosomething3];
});
As for the use of completion blocks, you can certainly obtain a similar result, except that the completion-handler result would need to be asynchronous.
I think you need to take a step back and explain what kind of API you are trying to design in order to determine how you want to use the tools of the system and language to achieve that API design.

iOS performSelectorInBackground inside performSelectorInBackground

It seems that the function call [self updateUI]; blocked by boo.
Is boo run in another background thread or same as foo as the code below?
How can the [self updateUI]; not block by boo?
- (void)MainFunction
{
[self performSelectorInBackground#selector(foo) withObject:nil];
}
- (void)foo
{
[self performSelectorInBackground#selector(boo) withObject:nil];
//updaate UI in MainThread
[self updateUI];
}
- (void)boo
{
//function here take long time to run;
}
In your code seems that you call foo in background and so the UI is updated in the background thread that is not possible because you need to do that in the main thread. In any case, performSelectorInBackground is a little bit old...use the dispatcher in this way:
- (void)MainFunction
{
[self foo];
}
- (void)foo
{
dispatch_async(dispatch_get_global_queue(DISPATCH_PRIORITY_DEFAUL, 0ull), ^{
[self boo];
dispatch_async(dispatch_get_main_queue(), ^{
//updaate UI in MainThread
[self updateUI];
};
};
}
- (void)boo
{
//function here take long time to run;
}
In this case updateUI wait boo, but if you want updateUI before and doesn't matter when boo finish:
- (void)foo
{
dispatch_async(dispatch_get_global_queue(DISPATCH_PRIORITY_DEFAUL, 0ull), ^{
[self boo];
};
[self updateUI];
}
performSelectorInBackground performs the selector on a NEW thread. From Apple docs:
This method creates a new thread in your application, putting your
application into multithreaded mode if it was not already. The method
represented by aSelector must set up the thread environment just as
you would for any other new thread in your program.
If you would like to perform both functions on the SAME background thread, you'll have to declare the background thread (also called queue) as a private member of the class (so it will be accessible from both functions) and perform the selector on that queue

Grand Central Dispatch and functions

I've been looking at this question to try to solve the problem I have here. The tl;dr is I want to use GCD to let me show a "Waiting" screen while I preform some tasks, then hide the screen when it's done. Right now, I have
- (void) doStuff
{
// Show wait on start
[self.waitScreen setHidden:NO];
dispatch_queue_t queue = dispatch_queue_create("com.myDomain.myApp",null);
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
// Double nesting the dispatches seems to allow me to do UI changes as part of 'Code to execute' below.
// If I do not double nest like this, the UI still freezes while it executes
dispatch_queue_t queue2 = dispatch_queue_create("com.myDomain.myApp",null);
dispatch_async(queue2, ^{
dispatch_async(dispatch_get_main_queue(), ^{
// Code to execute
{
//... Do my time consuming stuff here ...
// For testing purposes, I'm using
int i = 0;
while (i < 1000000000)
{
i++;
}
}
// Hide Wait Screen on End
[self.waitScreen setHidden:YES];
});
});
});
});
}
And this works just how I want. I'm calling [self doStuff] like so
- (IBAction) buttonTouchUpInside:(id)sender
{
[self doStuff];
}
- (void) doStuff
{
// ... code from first code block here ...
}
Everything to this point works perfectly. Now, I've discovered I will need to use this in a function call. So I need something like:
- (IBAction) buttonTouchUpInside:(id)sender
{
NSMutableString *string= [self doStuff];
// ... use 'string' to do other stuff ...
// For testing, I'm using
self.label.text = string;
}
- (NSMutableString *) doStuff
{
// ... code from first code block here ...
}
How do I need to change the syntax to be able to pass variables around with dispatch_async?
I looked at the Apple Docs and tried
- (IBAction) buttonTouchUpInside:(id)sender
{
NSMutableString *string= [self doStuff];
// ... use 'string' to do other stuff - shows 'nil' when I put breakpoints here ...
// For testing, I'm using
self.label.text = string;
}
- (NSMutableString *) doStuff
{
__block NSMutableString *string = [[NSMutableString alloc] initWithString:#"Initing"];
// Show wait on start
[self.waitScreen setHidden:NO];
dispatch_queue_t queue = dispatch_queue_create("com.myDomain.myApp",null);
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_queue_t queue = dispatch_queue_create("com.myDomain.myApp",null);
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
// Code to execute
{
int i = 0;
while (i < 1000000000)
{
i++;
}
[string setString:#"Hello World"];
}
// Hide Wait Screen on End
[self.waitScreen setHidden:YES];
});
});
});
});
return string;
}
But when I run this, label just shows Initing. I need it to show Hello World. None of the changes I make in the block are being passed through.
After looking at some other questions, this seems to be referred to as a "race condition". As I understand it, once it hits the dispatch_async, the code in the block starts running on a new thread, but the code outside of the block continues to run at the same time on the old thread. So it looks like the thread outside the block is getting to self.label.text = string before the thread running the block can get to [string setString:#"Hello World"];. How can I make the self.label.text = string line wait until [string setString:#"Hello World"]; finishes?
First of all your reasoning of double nesting is flawed. Not sure why it might have worked, but the correct way is to do some async work, and any time you want to update the ui wrap that code in a block on the main queue.
- (void) doStuff
{
// Show wait on start
[self.waitScreen setHidden:NO];
// queue should be a global variable, you don't want to create it every time you
// execute doStuff
dispatch_async(queue, ^{
// Code to execute
{
//... Do my time consuming stuff here ...
// For testing purposes, I'm using
int i = 0;
while (i < 1000000000)
{
i++;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
// Hide Wait Screen on End
[self.waitScreen setHidden:YES];
});
});
}
Since your queue is performing work asynchronously you can't simply return a value from doStuff without waiting, which will block the queue you call doStuff on again.
If you just want to set a value on a label, do that too in the block executed on the main queue, like hiding the wait screen.
Another common way to do things it to provide a callback block to execute as soon as work is finished.
- (void) doStuffWithCompletionBlock:(void(^)(NSString *))block
{
// again, a global variable for the queue
dispatch_async(queue, ^{
// do some work here that shouldn't block the UI
dispatch_async(dispatch_get_main_queue(), ^{
block(#"My result string");
});
});
}
- (void) myAction:(id)sender
{
__weak typeof(self) weakSelf = self;
[self doStuffWithCompletionBlock:^(NSString *result) {
weakSelf.label.text = result;
}];
}
Notice that I call the completion block on the main queue, this is a choice. You could leave that out, but then you would still have do all UI updates on the main queue later in the completion block itself.

Handle concurrency and asynchronous response

I am trying to implement concurrency in objective C. I have a problem with an actions that needs to be run in a synchronized way. The problem here is that I use function that executes a block after completion.
I want to connect to a bluetooth device to run some operations and connect to the next device.
for (Beacon * beacon in beacons) {
[beacon setDelegate:self];
[beacon connectToBeacon];
}
But the connection is asynchronous. The beacon call the delegate (in this case it's the same class) method didConnectSuccess when connection is successful.
I need to wait all my operations in "beaconDidConnect" and deconnection to finish before connecting to the next device.
I currently use a combination of dispatch queue and dispatch semaphore, my semaphore is an ivar
dispatch_queue_t myCustomQueue;
myCustomQueue = dispatch_queue_create("com.example.MyCustomQueue", NULL);
for (Beacon * beacon in beacons) {
[beacon setDelegate:self];
dispatch_async(myCustomQueue, ^{
dispatch_semaphore_wait(semaphoreBluetooth, DISPATCH_TIME_FOREVER);
[beacon connectToBeacon];
});
}
In combination with
- (void)beaconDidDisconnect:(Beacon *)beacon
{
dispatch_semaphore_signal(semaphoreBluetooth);
}
Without the dispatch_async, by blocking the callback (beaconDidConnect), the wait was causing a deadlock.
I wanted to dispatch_semaphore_wait in the for loop and not in the dispatch block but the wait causes the callback to wait again, causing a deadlock.
This way it seems to work but I found it a bit ugly.
My other issue is that in my beaconDidConnect method I need to chain asynchronous call and in each waiting the previous to terminate.
All those calls have a termination block, executing when the call is done. I could write instructions in deeper and deeper block but I'd like to avoid this.
I'd need an equivalent of the javascript "promise" concept.
Currently I have something with dispatch queue and dispatch semaphore but I sometimes have deadlock for unknown reason.
Eg :
- (void)beaconConnectionDidSucceeded:(Beacon *)beacon
{
dispatch_semaphore_t semaphoreEditing = dispatch_semaphore_create(1);
dispatch_queue_t editingQueue = dispatch_queue_create("com.example.MyCustomQueue.Editing", NULL);
// First writing procedure
dispatch_async(editingQueue, ^{
dispatch_semaphore_wait(semaphoreEditing, DISPATCH_TIME_FOREVER);
[beacon writeSomeCaracteristic:caracteristic withValue:value withCompletion:^(void) {
dispatch_semaphore_signal(semaphoreEditing);
}];
});
// A unknow number of writing sequences
dispatch_async(editingQueue, ^{
dispatch_semaphore_wait(semaphoreEditing, DISPATCH_TIME_FOREVER);
[beacon writeSomeCaracteristic:caracteristic withValue:value withCompletion:^(void) {
dispatch_semaphore_signal(semaphoreEditing);
}];
});
//
// ...
//
dispatch_async(editingQueue, ^{
dispatch_semaphore_wait(semaphoreEditing, DISPATCH_TIME_FOREVER);
[beacon writeSomeCaracteristic:caracteristic withValue:value withCompletion:^(void) {
dispatch_semaphore_signal(semaphoreEditing);
}];
});
// Terminate the edition
dispatch_async(editingQueue, ^{
dispatch_semaphore_wait(semaphoreEditing, DISPATCH_TIME_FOREVER);
[beacon disconnectBeacon];
dispatch_semaphore_signal(semaphoreEditing);
});
}
I want to write clear code that execute my instructions in a sequential way.
If your asynchronous methods do have a completion handler, you can "serialize" or "chain" a number of asynchronous calls like shown below:
[self asyncFooWithCompletion:^(id result){
if (result) {
[self asyncBarWithCompletion:^(id result){
if (result) {
[self asyncFoobarWithCompletion:^(id result){
if (result) {
...
}
}];
}
}];
}
}];
Of course, this gets increasingly confusing with the number of chained asynchronous calls, and especially when you want to handle errors, too.
With a third party library which especially helps to overcome these problems (including error handling, cancellation) it may look similar as the code below:
Given:
- (Promise*) asyncFoo;
- (Promise*) asyncBar;
- (Promise*) asyncFoobar;
"Chaining" the three asynchronous methods including error handling:
[self asyncFoo]
.then(^id(id result){
... // do something with result of asyncFoo
return [self asyncBar];
}, nil)
.then(^id (id result){
... // do something with result of asyncBar
return [self asyncFoobar];
}, nil)
.then(^id(id result) {
... // do something with result of asyncFoobar
return nil;
},
^id(NSError*error){
// "catch" any error from any async method above
NSLog(#"Error: %#", error);
return nil;
});
For general info about "Promises", please read wiki article Futures and Promises.
There are number of Objective-C libraries which implement a Promise.
Have you considered use NSOperation and NSOperationQueue?
If you need to wait for every beacon to run a set of operations before continue, you can store every set of operations in a NSOperation and put all the operations inside a NSOperationQueue with a maxConcurrentLimit of 1. It might be easier to cancel/pause/terminate every single operation and the queue will take care of the concurrency.
I kept the dispatch_queue and dispatch_semaphore for the connection but for the writing actions I use a library called Sequencer I found here.
It follows the Promises principle CouchDeveloper talked about.

Mulithreading: executing method calls only after finished executing other method

I am trying to process method asynchronously, as per requirements, once the first method has completed, only then the second method should start executing. The Problem is first method itself has code that runs on background thread.
I tried dispatch_semaphore_wait, but that didnt work either.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
[self firstMethod];
NSLog(#"firstMethod Done");
});
dispatch_group_notify(group, queue, ^ {
NSLog(#"1st method completed");
NSLog(#"2nd method starting");
[self secondMethod];
});
FirstMethod itself runs on another worker thread like this
-(void)firstMethod
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//processing here.....
}];
What is the best way to achieve it, I cannot change the definition of firstMethod as it provided by some 3rd party and also changing it means changing lots of existing code from where this method is being called
You can use a completion block. You just need to modify firstMethod this way:
- (void)firstMethodWithOnComplete:(void (^)(void))onComplete {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//processing here.....
onComplete();
});
}
And then use it this way:
[self firstMethodWithOnComplete:^{
[self secondMethod];
}];
Dispatch a Single Queue and call your Methods in order
dispatch_group_async(group, queue, ^{
[self firstMethod];
NSLog(#"firstMethod Done");
[self secondmethod];
});
Or you might dispatch a group of 3 concurrent queues(This is a Wild guess)

Resources