iOS 利用runloop阻塞主线程

这里的阻塞主线程,并不是真正的卡死,而是利用runloop让主线程等待。

举例:我有三个方法需要依次执行testLogOne testLogTwo testLogThree,但是方法二testLogTwo中是有block或者是block 中有返回值的,方法三testLogThree需要等待方法二的block回调完成后才能执行。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self testLogOne];
    [self testLogTwo:^{
        NSLog(@"----2----");
    }];
    [self testLogThree];
}

/// 方法一
- (void)testLogOne {
    NSLog(@"----1----");
}

/// 方法二
/// @param twoBlock 回调
- (void)testLogTwo:(void(^)(void))twoBlock {
    
    dispatch_async(dispatch_get_main_queue(), ^{
        if (twoBlock) {
            twoBlock();
        }
    });
}

/// 方法三
- (void)testLogThree {
    NSLog(@"----3----");
}

控制台输出

2021-03-16 18:04:41.691889+0800 demo[45188:559343] ----1----
2021-03-16 18:04:41.692060+0800 demo[45188:559343] ----3----
2021-03-16 18:04:41.714916+0800 demo[45188:559343] ----2----

使用信号量dispatch_semaphore_t ❌

使用信号量dispatch_semaphore_t会直接卡死主线程,永远等待不到信号的的接收。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    /// 卡主线程
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    [self testLogOne];
    [self testLogTwo:^{
        NSLog(@"----2----");
        dispatch_semaphore_signal(semaphore);
    }];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    [self testLogThree];
}

使用dispatch_group_t ⁉️

使用dispatch_group_t也可以将方法三testLogThree,放到dispatch_group_notify中执行,但是,考虑到实际情况下,其他方法可能要比方法三testLogThree先执行,所有也放弃了此用法的考虑。虽然可以将方法三testLogThree放到block中,但是如果有其他特殊情况,例如for循环,这样也是不可取的。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    dispatch_group_t group = dispatch_group_create();

    [self testLogOne];

    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_group_enter(group);
        [self testLogTwo:^{
            NSLog(@"----2----");
            dispatch_group_leave(group);
        }];
    }

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"----2----after");
        //[self testLogThree];
    });

    [self testLogThree];
}

控制台输出

2021-03-16 18:15:47.571770+0800 demo[48810:577013] ----1----
2021-03-16 18:15:47.572034+0800 demo[48810:577013] ----3----
2021-03-16 18:15:47.588403+0800 demo[48810:577013] ----2----
2021-03-16 18:15:47.588557+0800 demo[48810:577013] ----2----
2021-03-16 18:15:47.588653+0800 demo[48810:577013] ----2----
2021-03-16 18:15:47.588736+0800 demo[48810:577013] ----2----
2021-03-16 18:15:47.588830+0800 demo[48810:577013] ----2----
2021-03-16 18:15:47.588919+0800 demo[48810:577013] ----2----
2021-03-16 18:15:47.589213+0800 demo[48810:577013] ----2----
2021-03-16 18:15:47.589303+0800 demo[48810:577013] ----2----
2021-03-16 18:15:47.589590+0800 demo[48810:577013] ----2----
2021-03-16 18:15:47.589831+0800 demo[48810:577013] ----2----
2021-03-16 18:15:47.590538+0800 demo[48810:577013] ----2----after

使用runloop ✅

运行runLoop一次,阻塞当前线程以等待处理。根据条件进行while循环,达到条件后runloop退出

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    __block BOOL isPerformNextStep = NO;

    [self testLogOne];


    for (NSInteger i = 0; i < 10; i ++) {
        [self testLogTwo:^{
            NSLog(@"----2----");
            isPerformNextStep = YES;
        }];
    }

    while (!isPerformNextStep) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
    [self testLogThree];
}

控制台输出:

2021-03-16 18:30:12.403732+0800 demo[54758:602699] ----1----
2021-03-16 18:30:12.407238+0800 demo[54758:602699] ----2----
2021-03-16 18:30:12.407371+0800 demo[54758:602699] ----2----
2021-03-16 18:30:12.407472+0800 demo[54758:602699] ----2----
2021-03-16 18:30:12.407554+0800 demo[54758:602699] ----2----
2021-03-16 18:30:12.407631+0800 demo[54758:602699] ----2----
2021-03-16 18:30:12.407726+0800 demo[54758:602699] ----2----
2021-03-16 18:30:12.407801+0800 demo[54758:602699] ----2----
2021-03-16 18:30:12.407909+0800 demo[54758:602699] ----2----
2021-03-16 18:30:12.408005+0800 demo[54758:602699] ----2----
2021-03-16 18:30:12.408137+0800 demo[54758:602699] ----2----
2021-03-16 18:30:12.408383+0800 demo[54758:602699] ----3----

参考资料

iOS开发-阻塞主线程
IOS 等待条件满足再向下执行但不主卡线程NSRunLoop

你可能感兴趣的:(iOS 利用runloop阻塞主线程)