The library bolts-Swift was always used in Swift.

When I changed projects and realized that this library was not used in my new OC project, and that I needed it to be more concise in my implementation (of course other methods would have worked, but it always felt bad), I found the OC version bolts-objc.

But you can’t just install the library for a few lines of code, so read the source code now and write a simplified version yourself.

Here’s GitHub’s address:

OC version: bolts-objc

Swift version: bolts-Swift

This article is written for OC version, swift version will be written in the next part

First of all,

So let’s take a look at the approach that we would normally use, and we’ll start here.

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"Start");
    [[self getStringAsync:@"111"] continueWithBlock:^id _Nullable(BFTask * _Nonnull t) {
        NSLog(@"% @", t.result);
        return t.result;
    }];
    [[self getStringAsync:@"222"] continueWithSuccessBlock:^id _Nullable(BFTask * _Nonnull t) {
        NSLog(@"% @", t.result);
        return t.result;
    }];
     NSLog(@"The end");
}
Copy the code
// Return the Task object
- (BFTask *)getStringAsync: (NSString *)str{
    / / create
    BFTaskCompletionSource *successful = [BFTaskCompletionSource taskCompletionSource];
    dispatch_async(dispatch_get_main_queue(), ^{
        [successful setResult:str];
    });
    return successful.task;
}
Copy the code

Print the result

2018-04-16 10:38:32.974577+0800 RQRR [2607:83284] Start 2018-04-16 10:38:32.975714+0800 RQRR [2607:83284] End 2018-04-16 10:38:32.982849+0800 RQRR [2607:83284] 111 2018-04-16 10:38:32.983826+0800 RQRR [2607:83284] 222Copy the code

The dispatch_async asynchronous thread completes and returns the result. First create a BFTaskCompletionSource class using the BFTaskCompletionSource class method.

Look at the implementation in the source code

In this BFTaskCompletionSource class, I’m going to ignore some of them.

BFTask
__covariant - covariant

The constructor is also very simple as follows:

BFTask
viewdidLoad

[[self getStringAsync:@"111"] continueWithBlock:^id _Nullable(BFTask * _Nonnull t) {
        NSLog(@"% @", t.result);
        return t.result;
    }];
Copy the code

The continueWithBlock method of the returned BFTask object is called. All right, let’s take a look here.

Another object is called. And passed in [BFExecutor defaultExecutor]

What is BFExecutor?

Return a thread-safe singleton.

- (BFTask *)continueWithExecutor:(BFExecutor *)executor block:(BFContinuationBlock)block cancellationToken:(nullable BFCancellationToken *)cancellationToken { BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource]

The most important way is to start from the bottom without asking for a long timeCopy the code

Synchronized @synchronized(self.lock) acts as a thread lock. It’s used in a lot of places, which means everything else is locked until it’s done.

And then the self.leted initialization is NO, so doing this will put your block back into the method.

Store them in self.callbocks and copy an object with a block using the previous singleton.

In this way, the method will be executed twice and then there are two blocks in self.callbocks.

    [[[self getStringAsync:@"111"] continueWithBlock:^id _Nullable(BFTask * _Nonnull t) {
        NSLog(@"First %@", t.result);
        return t.result;
    }] continueWithBlock:^id _Nullable(BFTask * _Nonnull t) {
        NSLog(@"Second %@", t.result);
        return t.result;
    }];
Copy the code

The callback method is stored in an array. When is it called?

Look at the code below, after all the copies are successful, in the asynchronous method you execute. Call [successful setResult: STR]; In the


// Return the Task object
- (BFTask *)getStringAsync: (NSString *)str{
    / / create
    BFTaskCompletionSource *successful = [BFTaskCompletionSource taskCompletionSource];
    dispatch_async(dispatch_get_main_queue(), ^{
        [successful setResult:str];
    });
    return successful.task;
}
Copy the code

The trySetResult method is called here

Here we also have the self.lock lock, which self.completed said is NO, so we do the following, copy result, and execute the [self runContinuations] method

And finally, what does the runContrnuations method do? See here lock, broadcast, unlock. Lock -> Release all thread locks -> unlock. The block method is then looped through. Finally, the block array is emptied.