美文网首页
block循环引用

block循环引用

作者: iOS_小张 | 来源:发表于2017-10-09 16:47 被阅读0次

    1.block类型

    1.1__NSGlobalBlock__ :全局区的 (没有引用外部变量)

    应用场景:提示语提示用户或者保存数据等其他情况,不做逻辑操作

    [Person personWithName:^(NSString *personName) {  
           UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:personName delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
            [alert show];
        }];
    没有使用外部变量,此时的 alert 变量是放在 栈区 ,block执行完即释放,类似的情况还有AFNetWorking里failure:^(NSError *error){#提示语#} 不用担心循环引用
    

    1.2__NSStackBlock__ :栈区 (内部使用了外部变量)

    应用场景:做逻辑操作,赋值,遍历数组或者动画等

    [Person personWithName:^(NSString *personName) {
            self.name = personName;
           NSLog(@“%@",self.name);
       }];
    使用了外部变量_name属性,此时就成为了栈Block,类似的还有-(void)enumerateObjectsUsingBlock:(void (^)(id _Nonnull, NSUInteger, BOOL * _Nonnull))block 和 +(void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations 都是 栈Block,不用担心循环引用,下面我会来证实一下,像平时自己写的方法中出现的block,都是栈block,不用担心循环引用
    
    A794F4179CAD08FDA8FF8D01ACC3B9BA.png

    1.3__NSMallocBlock__ :堆区 (copy后Block存放在堆区)

    应用场景:做逻辑操作,一般多见于属性,@property (nonatomic,copy) void (^SelectPeoplesOK)(NSString *employees);或者是执行[block copy]操作,然后赋值给另一个otherblock,那么使用otherblock的时候,就要注意循环引用了

    Person *person = [[Person alloc] init];
        __weak typeof(self) weakSelf = self;
        person.personNameBlock = ^(NSString *personName) {
            weakSelf.name = personName;
        };
       [person blockTest];
        有的小伙伴可能觉得还需要在block里面执行一下__strong __typeof(weakSelf)strongSelf = weakSelf; 其实这个例子不要,下面讨论
    

    2.如何定位Block类型

    对于我自己,我有两个办法,一是打断点在block上面,然后看后台数据。或者是NSLog输出block。只有定位对了block类型,才能决定是否要考虑循环引用问题,不然就一直无脑用了。直接贴代码,贴图了。。。

    #import  typedef void(^PersonNameBlock)(NSString *personName);
    @interface Person : NSObject
    @property (nonatomic,copy) PersonNameBlock personNameBlock;
    - (void)personWithName:(PersonNameBlock)personBlock;
    - (void)blockTest;
    - (void)test;
    @end
    
    #import "Person.h"
    @implementation Person
    - (void)personWithName:(PersonNameBlock)personBlock
    {
         NSLog(@"personBlock : %@",personBlock);
         if (personBlock)
         {
              personBlock(@"张三");
         }
    }
    - (void)blockTest
    {
         NSLog(@"personBlock : %@",self.personNameBlock);
         if (self.personNameBlock)
        {
            self.personNameBlock(@"张三");
        }
    }
    
    - (void)test
    {
        NSLog(@"xxxx");
    }
    
    @end
    
    
    Person *person = [[Person alloc] init];
    [person personWithName:^(NSString *personName) {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:personName delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [alert show];
    }];
    

    3.png

    4.png

    5.png

    6.png

    3.什么时候block里面需要使用__strong typeof(weakSelf)strongSelf = weakSelf

    其实答案简单,就是防止在执行block的时候局部变量weakSelf已经被释放了,weakSelf ==nil,那么执行 weakSelf.属性 的时候,就有问题了。 如果一直都写,大部分情况下是没有问题的,但是要是深究下去,具体情况具体分析,那么部分情况是不需要写的。像上面的例子,就不需要写strongSelf。现在来一个必须要写strongSelf的demo吧。。。

    
        Person *person = [[Person alloc] init];
        __weak Person * weakPerson = person;
        person.personNameBlock = ^(NSString *personName) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2. * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    
                [weakPerson test];
            });
        };
        [person blockTest];
    直接运行这段代码会发现[weakPerson test];并没有执行,打印一下会发现,weakPerson 已经是 Nil 了,这是由于当我们的 viewDidLoad 方法运行结束,由于是局部变量,无论是 person 和 weakPerson 都会被释放掉,那么这个时候在 Block 中就无法拿到正真的 person 内容了。
    
    

    正确写法

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        Person *person = [[Person alloc] init];
        __weak Person * weakPerson = person;
        person.personNameBlock = ^(NSString *personName) {
            __strong Person * strongPerson = weakPerson;
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2. * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    
                [strongPerson test];
            });
        };
        [person blockTest];
    }
    

    4.自我总结

    在使用block的时候,首先还是先确定block类型,然后看看自己的block里面有没有用到“外部变量”,然后如果不确定是否需要block里写
    __strong XXX *xxx,打个断点,跑一下代码,看看__weak XXX *xxx会不会被释放掉,久而久之,也就熟知自己经常写的block会不会有问题了,个人见解,哪里写的不对的,欢迎各位大佬指正批评,谢谢~~

    相关文章

      网友评论

          本文标题:block循环引用

          本文链接:https://www.haomeiwen.com/subject/awjpyxtx.html