我有一个关于objc块的问题。如果你想在一个块中使用self,你应该将它弱化并在块中再次强化它,这样你就不会进入一个保留周期。在我的情况下,我也想写一个存在块的类的属性。现在我有点困惑,如果这是有道理的,如果我以后可以访问此属性或如果我完全松开对此属性的引用
这是我的代码示例:
__weak typeof(self)weakSelf = self;
void (^handleRequestBlock)(NSURLSessionDataTask*, id) = ^(NSURLSessionDataTask *task, id responseObject)
{
__strong typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf) {
strongSelf->_response = [strongSelf extractResponseData:responseObject forRequestType:requestType];
[strongSelf postSuccessNotification:strongSelf->_response];
}
};
首先让这段代码完全正确或者有什么可以优化的吗?
有人可能会再次解释objc内部发生的事情。我现在阅读了几篇文章,而且我对保留周期比以前更加困惑。据我所知,一个块是一个对象,如果它捕获了变量,那么变量就会在内部复制并默认声明为const,只要你不使用__block声明(那么全局范围内的生命属性呢?)。我仍然没有完全得到块的生命周期和为什么指针可以悬空,因为整个块对象及其内容应该在它们完成后释放。如果有人有时间我会欣赏一个书呆子和详细的答案或链接到良好的阅读资源! :)
提前致谢:)
答案 0 :(得分:4)
我想解释3种编写块的方法。
首先:使用self
void (^handleRequestBlock)(NSURLSessionDataTask*, id) = ^(NSURLSessionDataTask *task, id responseObject)
{
self->_response = [strongSelf extractResponseData:responseObject forRequestType:requestType];
[weakSelf postSuccessNotification:self->_response];
};
块handleRequestBlock
保留self
,如果self
拥有拥有该块的属性,则会有一个保留圈。该块将保留self
,直到您释放块为止。因此,如果在调用块后释放块(将块设置为nil以释放它),则循环将不存在。
注意:大多数实现都不会在调用后释放块,因为我们之后可能需要它,所以保留圈将一直存在。
第二:使用weak
self
__weak typeof(self)weakSelf = self;
NSLog(@"%p", &weakSelf) ;
void (^handleRequestBlock)(NSURLSessionDataTask*, id) = ^(NSURLSessionDataTask *task, id responseObject)
{
NSLog(@"%p", &weakSelf) ;
weakSelf->_response = [strongSelf extractResponseData:responseObject forRequestType:requestType];
[weakSelf postSuccessNotification:weakSelf->_response];
};
该块不会保留self,如果取消分配self实例,weakSelf
为nil。
关于这个例子的更多信息:我添加两行日志来表明:块范围之外和块范围内的变量weakSelf
的地址是不同的。因为weakSelf是一个堆栈本地和__weak
变量,所以使用具有相同值weakSelf
的变量来阻止它,但是不向它指示的实例发送保留消息,weakSelf
这里是另一个变量具有不同的地址。
第三:仅在需要时保留self
。
__weak typeof(self)weakSelf = self;
void (^handleRequestBlock)(NSURLSessionDataTask*, id) = ^(NSURLSessionDataTask *task, id responseObject)
{
__strong typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf) {
strongSelf->_response = [strongSelf extractResponseData:responseObject forRequestType:requestType];
[strongSelf postSuccessNotification:strongSelf->_response];
}
};
第二种方式有一个缺点:如果在执行第一行代码时没有释放self,则在执行这行代码后,self的实例将被释放(因为我们没有保留)它,它可能是在其他线程上发送释放方法并且它将被解除分配),在第二行代码中,weakSelf
为零,所以会发生一些不好的事情,这取决于你的代码的逻辑。
所以第三种方式解决了这个问题,它只在块执行时保留self并在块结束时释放self(释放意味着将保留计数减少1)。
更多链接: