Multiple async methods, one completion handler - ios

I have two async methods:
- (void)login: (void (^)(BOOL))completion{
// some network stuff with completion
}
and
- (void)download: (void (^)(BOOL))completion{
// some network stuff with completion
}
For a background fetch, I need both methods to be completed, and return just one completion.
I could of course, nest the methods, as such
- (void)login: (void (^)(BOOL))completion{
//....
[self download:^(BOOL success) {
//....
if (success){
completion(true);
}
}];
}
However, as soon as I add one or more methods that need to be completed at the same time, code gets messy.
I remember having read about a way, with which you could just kind of group all those methods on one thread, but I just don't seem to have the right vocabulary to find that here on SO or elsewhere.
I hope you understand what I'm talking about, and point me in the right direction.
thanks ahead

If the task really presents a dependency and it's possible that you have to add more methods in the future maybe you should consider use NSOperationQueue.

What you can do is pass the completion block down to the download method so when download completes the completion is chained all the way back up the caller like so:
- (void)login: (void (^)(BOOL))completion{
// some network stuff with completion
[self download:completion];
}
- (void)download: (void (^)(BOOL))completion{
completion(YES);
// some network stuff with completion
}

Related

iOS - Concatenating asynchronous block-based operations

How would you perform N asynchronous operations, such as network calls, working with completion block operations and no delegates/notifications?
Given N methods like this:
- (void)methodNWithCompletion:(void (^)(Result *))completion {
Operation *operation = [Operation new];
// ...
// Asynchronous operation performed here
// ...
return;
}
A straightforward solution would be to call each operation in the completion block of the previous one:
[self method1WithCompletion:^(Result *result) {
// ...
[self method2WithCompletion:^(Result *result) {
// ...
[self method3WithCompletion:^(Result *result) {
// ...
[self method4WithCompletion:^(Result *result) {
NSLog(#"All done");
}
}
}
}
but I'm looking for a more elegant and reusable solution, easier to write and maintain (with no many indented blocks).
Many thanks,
DAN
It all depends on what you want to do. Many powerful sophisticated tools are at your disposal. You can use such things as:
Serial queue (if you want the completion blocks run in order)
Concurrent queue (if you don't care whether the completion blocks execute simultaneously or in what order)
Dispatch group (if there is something you want to do only after all completion blocks have finished)
Operation and OperationQueue (if you want to establish the dependency order in which networking operations must take place - see esp. the fantastic WWDC 2015 video on this topic)

Socket Rocket Asynchronous delegate methods

Using Socket Rocket library for WebSocket connections.
When I saw the source of Socket Rocket, it is clearly visible that it is calling the methods of its delegate class (my class) asynchronously using dispatch_async.
But when in my class where the delegate the method is implemented, I put a infinite while loop, the UI gets blocked.
Why is that so when the delegate method is already called asynchronously?
SRWebsocket.m
- (void)_handleMessage:(id)message
{
SRFastLog(#"Received message");
[self _performDelegateBlock:^{
[self.delegate webSocket:self didReceiveMessage:message];
}];
}
// Calls block on delegate queue
- (void)_performDelegateBlock:(dispatch_block_t)block;
{
if (_delegateOperationQueue) {
[_delegateOperationQueue addOperationWithBlock:block];
} else {
assert(_delegateDispatchQueue);
dispatch_async(_delegateDispatchQueue, block);
}
}
My delegate implementation (code that should have been handled asynchronously)
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
//some code to process message
//emulating a long running operation
while(1)
{
}
}
But when I put a dispatch_async in my long running operation, the UI doesnt get blocked.
Is it because the block as a whole is run asynchronously but the delegate call inside it is done synchronously. So, as soon as the delegate call is over, _performDelegateBlock returns?
Please explain
_delegateDispatchQueue - default value will your main queue. So, if you want to run code asynchronously for your delegate, you need to provide your own queue

AsyncTask implementation using NSOperation in iOS

I implemented AsyncTask(Android) in iOS using NSOperation subclass.
-(id)initWithParam:(NSArray *)params{
if (self = [super init]) {
paramsArray = params;
}
return self;
}
- (void)start {
#autoreleasepool {
if (self.isCancelled)
return;
NSInteger result;
result = [self doInBackground:paramsArray];
dispatch_async(dispatch_get_main_queue(), ^{
[self postExecute:result];
});
}
}
- (BOOL) doInBackground: (NSArray *) parameters{
BOOL status = false;
int i;
for (i=0; i<100000; i++) {
NSLog(#"printing i::%d",i);
}
if (i == 100000) {
status = YES;
}
return status;
}
- (void) postExecute: (BOOL) deviceState{
if (deviceState) {
NSLog(#"Finished");
}
}
-(BOOL)isConcurrent{
return YES;
}
This is the way I implemented in iOS.Please suggest and any thing I want to add for this functionality.
And also, when can I call isExecuting and isFinished in NSOperation subclass
In answer to your question, unfortunately, no, this implementation is not correct. Close, but not quite there.
A couple of things:
Your example is not concurrent operation. In the case of NSOperation, the term "concurrent operation" (now called an "asynchronous operation") has a special meaning. An asynchronous operation is one that that continues to run asynchronously even after the start method finishes. And you designate this by returning YES from isConcurrent (in older iOS versions) and isAsynchronous (in contemporary iOS versions). But the example operation in the question is completely done when start ends, so therefore is not an asynchronous operation and therefore isConcurrent and isAsynchronous should therefore return NO.
Let's assume in this example that you changed isConcurrent to return NO, as would be appropriate with what you're performing in start. That would fix this operation. But don't let this confuse you. If you added this operation to your own operation queue, it would still run asynchronously/concurrently with respect to the main queue, it's just that it's an operation that automatically finishes when start finishes, and therefore isAsynchronous/isConcurrent should return NO.
You ask "when can I call isExecuting and isFinished?" Well, you generally don't call those methods. You generally implement those methods. Specifically, when an asynchronous operation eventually finishes, you must ensure that the app (a) posts KVN for the isExecuting and isFinished keys; and (b) you override isExecuting and isFinished to ensure that they correspondingly return the appropriate values.
You only have to implement this isExecuting and isFinished code when the operation is truly an asynchronous/concurrent operation. See the Configuring Operations for Concurrent Execution section of the Concurrency Programming Guide: Operation Queues. Also see the introductory section of the NSOperation class definition.
Whether your operation should be asynchronous or not (or even whether you need to subclass NSOperation at all) is unclear. It depends entirely upon what task you want to perform, and whether the task itself runs asynchronously or not.

Is it safe to pass an Objective-C block to performSelector:withObject:afterDelay:?

I want to pass a block argument to -performSelector:withObject:afterDelay:.
For example, consider this:
[self performSelector:#selector(delayedBlock:) withObject:^{
// some code in block
} afterDelay:2];
- (void)delayedBlock:(void (^)(void))code {
code();
}
It works but I am not sure if I need to do something special because of ARC.
As rmaddy wrote in the comment, there are better ways to perform a block with a delay, but if you want to use performSelector:withObject:afterDelay:, you should copy the block.
[self performSelector:#selector(delayedBlock:) withObject:[^{
// some code in block
} copy] afterDelay:2];
From Blocks Programming Topics:
Typically, you shouldn’t need to copy (or retain) a block. You only need to make a copy when you expect the block to be used after destruction of the scope within which it was declared. Copying moves a block to the heap.
You can use the GCD directly:
Here's a simple technique, based on GCD, that I'm using:
void RunBlockAfterDelay(NSTimeInterval delay, void (^block)(void))
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*delay),
dispatch_get_current_queue(), block);
}
Or use this useful category:
#implementation NSObject (PerformBlockAfterDelay)
- (void)performBlock:(void (^)(void))block
afterDelay:(NSTimeInterval)delay
{
block = [block copy];
[self performSelector:#selector(fireBlockAfterDelay:)
withObject:block
afterDelay:delay];
}
- (void)fireBlockAfterDelay:(void (^)(void))block
{
block();
}
#end
Check out the discussion in this thread:
Blocks instead of performSelector:withObject:afterDelay:

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.

Resources