iOS 中的 block 相关面试题

194 阅读1分钟

当一个 block 捕获了 self 指针时

有可能会出现循环引用的问题。

出现时,self 强引用 block,block 又强引用了 self,那么就需要使出「强弱共舞」来解除 block 对 self 的强引用了。

self.name = @"Hello";

__weak typeof(self) weakSelf = self;
self.block = ^(){
    __strong __typeof(weakSelf)strongWeak = weakSelf;

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@", strongWeak.name);
    });
};

self.block();

__strong 只在 block 内部生效,block 执行完了以后强引用关系不再出现


__block 关键字的语义

将一个变量包装成一个struct A,后续对这个变量的访问都会转变成对strut A中一个属性的访问。

// 定义一个 block 获取局部变量 myVariable
- (void)testBlock {
    __block NSInteger myVariable = 100;
    void (^myBlock)(void) = ^{
        NSLog(@"myVariable = %ld", myVariable);
        oooo = 99;
        NSLog(@"修改后, myVariable = %ld", myVariable);

    };
    myBlock();
}

struct __Block_byref_myVariable_0 {
  void *__isa;
__Block_byref_myVariable_0 *__forwarding;
 int __flags;
 int __size;
 NSInteger myVariable; 
};
对于 myVariable 的访问就变成了对结构体中 
__Block_byref_myVariable_0.myVariable 成员变量的访问

于是,本来 block 对于外部的基本变量是无法修改的,但是现在既然都装到了一个结构体·里,那么值传递就变成了指针传递,修改就易如反掌了。

将.m文件编译成 cpp 文件:clang -rewrite-objc BlockDemo.m,可以看到这个Block 持有的属性

如果是某个对象的属性值,不需要用 __block, 因为这个属性值也是一个标量罢了(内存地址)。标量本身并没有修改。只是标量指向的内存地址修改了,对 block 没有影响,block 不需要持有标量指向的值。