美文网首页iOS面试题
__weak与__strong解决循环引用问题

__weak与__strong解决循环引用问题

作者: EmulatingStep | 来源:发表于2020-03-12 15:11 被阅读0次

当block中涉及self以及self的成员变量时,就会造成循环引用问题。一般解决这类的循环引用是使用__weak__strong
案例:

// .h文件

#import <Foundation/Foundation.h>

@interface Pet : NSObject

@property (nonatomic, copy) void(^block)(void);

@end
// .m文件

#import "Pet.h"

@implementation Pet

- (instancetype)init {
    if (self = [super init]) {
        __weak typeof(self) weakSelf = self;
        self.block = ^{
            __strong typeof(weakSelf) strongSelf = weakSelf;
                [strongSelf training];
        };
    }
    return self;
}

- (void)training {
    NSLog(@"pet training");
}

- (void)dealloc {
    NSLog(@"pet dead");
}

@end
// ViewController文件
#import "ViewController.h"
#import "Pet.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Pet *p = [[Pet alloc] init];
    p.block();
}

@end

运行结果为:

2020-03-12 14:14:56.511389+0800 sss[3705:161369] pet training
2020-03-12 14:14:56.511497+0800 sss[3705:161369] pet dead

执行了block里面的内容,并且解决了循环引用问题。

如果block里面的操作是同步执行的,可以省略__strong。将Pet.m的代码修改:

__weak typeof(self) weakSelf = self;
        self.block = ^{
             [weakSelf training];
        };

运行结果为:

2020-03-12 14:29:54.239222+0800 sss[3751:167410] pet training
2020-03-12 14:29:54.239314+0800 sss[3751:167410] pet dead

执行了block里面的内容,并且解决了循环引用问题。

如果block里面的操作是异步执行的,不可以省略__strong。将Pet.m的代码修改:

__weak typeof(self) weakSelf = self;
        self.block = ^{
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                [NSThread sleepForTimeInterval:5];
                [weakSelf training];
            });
        };

运行结果为:

2020-03-12 14:32:59.274722+0800 sss[3781:169249] pet dead

解决了循环引用问题,但是没有执行block里面的内容。因为self提前于block执行之前释放了,ViewControllerp提前释放了,p就指向nil了,weakSelf也会被置为nil,当休眠结束时,再执行training方法时,实际上是向nil发送了一个消息。此时,__strong不能省略

__weak typeof(self) weakSelf = self;
        self.block = ^{
            __strong typeof(weakSelf) strongSelf = weakSelf;
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                [NSThread sleepForTimeInterval:5];
                [strongSelf training];
            });
        };

运行结果为:

2020-03-12 14:45:08.079523+0800 sss[3851:174924] pet training
2020-03-12 14:45:08.079750+0800 sss[3851:174924] pet dead

执行了block里面的内容,并且解决了循环引用问题。

如果异步执行使用__strongweakSelf还会随着实体被释放和置为nil吗?将Pet.m代码进行修改:

- (instancetype)init {
    if (self = [super init]) {
        __weak typeof(self) weakSelf = self;
        self.block = ^{
            __strong typeof(weakSelf) strongSelf = weakSelf;
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                [NSThread sleepForTimeInterval:5];
                [strongSelf training];
                [weakSelf eat];
            });
        };
    }
    return self;
}

- (void)eat {
    NSLog(@"pet eat");
}

- (void)training {
    NSLog(@"pet training");
}

执行结果为:

2020-03-12 15:01:22.362611+0800 sss[4010:182635] pet training
2020-03-12 15:01:22.362801+0800 sss[4010:182635] pet eat
2020-03-12 15:01:22.362903+0800 sss[4010:182635] pet dead

解决了循环引用问题,并且weakSelf并没有随着实体的释放而置为nil,可以正常调用方法。

推出结论:使用了__strong后,strongSelf也会持有一份weakSelf(不是真正的持有),此时weakSelf不会随着实体的释放而置为nilstrongSelf相当于block中的局部变量,当异步操作结束后,strongSelf会被释放,此时的weakSelf才会被置为nil。解决了循环引用问题,也解决了异步执行问题。

总结:

  • self:是一个指向实例对象的指针,它的生命周期至少是伴随着当前的实例对象的,所以一旦它和对象之间有循环引用是无法被自动打破的。
  • weakSelf__weak能解决循环应用问题,但是在异步执行时,可能会因为实体对象释放,造成weak�Self被置为nil,当block中异步执行weakSelf的方法时,其实是向一个nil发送消息。
  • strongSelfstrongSelf也会持有一份weakSelf(不是真正的持有),weakSelf 不会因为实体释放被置为nil的时候,只有当局部变量strongSelf执行完方法,出了作用域时,会随着strongSelf一起被置为nil,解决了循环引用问题,也解决了异步执行问题。

相关文章

网友评论

    本文标题:__weak与__strong解决循环引用问题

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