北京哪个公司做网站好,广东涂料网站建设,网站定制开发,营销培训视频课程免费循环引用原因
如果在Block中使用附有_ _strong修饰符的对象类型自动变量#xff0c;那么当Block从栈复制到堆时#xff0c;该对象为Block所持有#xff0c;这样容易引起循环引用。
HPPerson *person [[HPPerson alloc] init];person.block ^{NSLog(person.age--- …循环引用原因
如果在Block中使用附有_ _strong修饰符的对象类型自动变量那么当Block从栈复制到堆时该对象为Block所持有这样容易引起循环引用。
HPPerson *person [[HPPerson alloc] init];person.block ^{NSLog(person.age--- %d,person.age);};
在上面代码中person对象强持有block对象在block语法中block对象又强持有person对象此时达成互相强持有谁也无法释法谁造成循环引用。 当造成block循环引用时编译器会检测出并发出警告 另外如果block内没有使用self也会捕获self引起循环引用
typedef void (^blk_t) (void);interface HPPerson : NSObject
{blk_t _block;int _age;
}
end
#import HPPerson.himplementation HPPerson
-(id)init {self [super init];_block ^{NSLog(age %d, _age);};return self;
}- (void)dealloc
{NSLog(%s, __func__);
}
end这是因为虽然没有使用self但使用了self对象中的结构体成员因此也会捕获self。
避免循环引用
使用weak修饰符
int main(int argc, const char * argv[]) {autoreleasepool {HPPerson *person [[HPPerson alloc] init];person.age 10;__weak HPPerson *weakPerson person;person.block ^{NSLog(person.age--- %d,weakPerson.age);};NSLog(--------);}return 0;
}
编译完成之后是
struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;// block内部对weakPerson是弱引用HPPerson *__weak weakPerson;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, HPPerson *__weak _weakPerson, int flags0) : weakPerson(_weakPerson) {impl.isa _NSConcreteStackBlock;impl.Flags flags;impl.FuncPtr fp;Desc desc;}
};
局部变量消失时候对于HPPerson来说只有一个弱指针指向它那它就销毁然后block也销毁。
使用__unsafe_unretained修饰符
int main(int argc, const char * argv[]) {autoreleasepool {HPPerson *person [[HPPerson alloc] init];person.age 10;__unsafe_unretained HPPerson *weakPerson person;person.block ^{NSLog(person.age--- %d,weakPerson.age);};NSLog(--------);}return 0;
}
编译完成之后是
struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;HPPerson *__unsafe_unretained weakPerson;__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, HPPerson *__unsafe_unretained _weakPerson, int flags0) : weakPerson(_weakPerson) {impl.isa _NSConcreteStackBlock;impl.Flags flags;impl.FuncPtr fp;Desc desc;}
};
虽然__unsafe_unretained可以解决循环引用但是最好不要用因为:
__weak不会产生强引用指向的对象销毁时会自动让指针置为nil__unsafe_unretained不会产生强引用不安全指向的对象销毁时指针存储的地址值不变,会造成野指针
使用_ _Block修饰符
int main(int argc, const char * argv[]) {autoreleasepool {__block HPPerson *person [[HPPerson alloc] init];person.age 10;person.block ^{NSLog(person.age--- %d,person.age);//这一句不能少person nil;};// 必须调用一次person.block();NSLog(--------);}return 0;
}
使用_ _Block修饰符解决循环引用时需要注意的点有
在block对象中需要将_ _block变量置为nil必须调用block对象
如果不调用block对象时会造成下面情况的循环引用
HPPerosn类对象持有BlockBlock持有_ _block变量_ _block变量持有HPPerson对象 因为block会对__block产生强引用
__block HPPerson *person [[HPPerson alloc] init];
person.block ^{NSLog(person.age--- %d,person.age);//这一句不能少person nil;
};
person对象本身就对block是强引用
property (copy, nonatomic) HPBlock block;
__block对person产生强引用
struct __Block_byref_person_0 {void *__isa;
__Block_byref_person_0 *__forwarding;int __flags;int __size;void (*__Block_byref_id_object_copy)(void*, void*);void (*__Block_byref_id_object_dispose)(void*);//__block对person产生强引用HPPerson *__strong person;
};
当执行完person nil时候,__block解除对person的引用,进而全都解除释放了。 但是必须调用person nil才可以否则不能解除循环引用 强弱共舞
当Block捕获self时应该使用弱引用这样即使Block持有self的引用也不会阻止self被释放。由于弱引用可能变成nil因此在Block内部使用self之前需要检查它是否为nil。为了避免在Block内部因self为nil而导致的崩溃可以在Block的开始处使用强引用使用完成之后当Block的作用域结束之后即可释放
#import UIKit/UIKit.h
typedef void(^blk_t)(void);
interface ViewController : UIViewController
property (nonatomic, strong) blk_t block;
property (nonatomic, copy) NSString *name;end
#import ViewController.hinterface ViewController ()endimplementation ViewController- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.self.name Hello;__weak typeof(self) weakSelf self;self.block ^(){dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSLog(%, strongWeak.name);};self.block();
}end此时self持有blockblock弱引用self弱引用会自动变为nil强持有中断所以不会引起循环引用。但该方法可能存在中途就释放掉的问题手动延迟可能需要调用self.name的时候name已经被释放了如果self被销毁那么block则无法获取name。
因此可以改进上面的代码 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();
在完成block中的操作之后才调用了dealloc方法。添加strongWeak之后持有关系为self - block - strongWeak - weakSelf - self。
weakSelf被强引用了就不会自动释放因为strongWeak只是一个临时变量它的声明周期只在block内部block执行完毕后strongWeak就会释放而弱引用weakSelf也会自动释放。
参数形式解决循环引用
通过给block传参(指针拷贝) // 循环引用self.name Hello;self.block ^(ViewController * ctrl){dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSLog(%, ctrl.name);});};self.block(self);
Block循环引用场景 // staticSelf_定义static ViewController *staticSelf_;- (void)blockWeak_static {__weak typeof(self) weakSelf self;staticSelf_ weakSelf;}
weakSelf虽然是弱引用但是staticSelf_静态变量并对weakSelf进行了持有staticSelf_释放不掉所以weakSelf也释放不掉导致循环引用