我们都知道,用assign修饰属性时,当属性所指向的对象被释放,就造成野指针,访问野指针会导致崩溃,现在我们利用runtime机制来使assign 修饰的@property,拥有weak的效果。
主要的方案是,当一个对象被释放时,会释放其拥有的属性,所以我们利用runtime为NSObject动态添加属性,在此属性被释放时,执行想要的操作。
具体实现如下:
创建一个执行类,用block初始化它,并且在释放时执行block
//.h
@interface YZLBlockExecutor : NSObject
- (instancetype)initWithBlock:(dispatch_block_t)block;
@end
//.m
@interface YZLBlockExecutor ()
@property (nonatomic, copy) dispatch_block_t block;
@end
@implementation YZLBlockExecutor
- (instancetype)initWithBlock:(dispatch_block_t)block{
if (self = [super init]) {
self.block = block;
}
return self;
}
- (void)dealloc{
if (self.block) {
self.block();
}
}
@end
扩展NSObject
//.h
- (void)yzl_runWhenDealloc:(dispatch_block_t)block;
//.m
- (void)yzl_runWhenDealloc:(dispatch_block_t)block{
YZLBlockExecutor *ex = [[YZLBlockExecutor alloc]initWithBlock:block];
objc_setAssociatedObject(self,@"YZLBlockExecutor", ex, OBJC_ASSOCIATION_RETAIN);
}
具体使用
@interface ViewController ()
@property (assign, nonatomic) NSInteger num;
@property (assign, nonatomic) parent *p;
@end
@implementation ViewController{
dispatch_source_t _source;
}
- (void)viewDidLoad {
[super viewDidLoad];
parent *p = [[parent alloc]init];
self.p = p;
[self.p yzl_runWhenDealloc:^{
NSLog(@"释放");
// _p = nil; (2)
}];
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSLog(@"访问:%@",self.p.name);
}
@end
当注释掉(2)时,在viewWillAppear
中执行的操作会引起崩溃,因为self.p
是assign,而临时变量p在出viewDidLoad
时就被释放掉。而不注释(2)就能正常运行。