- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
在我的支持 ARC 的 iOS 代码中,我需要将“self”和其他对象传递给一个 block 。更具体地说,我需要在 ASIHTTPRequest
的 completionBlock
中与 self 和 ASIHTTPRequest
对象进行交互。
_operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(parseServerReply) object:nil];
_request = [ASIHTTPRequest requestWithURL:@"server.address"];
// ...
[_request setCompletionBlock:^{
[self setResponseString:_request.responseString];
[[MyAppDelegate getQueue] addOperation:_operation];
}];
为了避免以下警告:在此 block 中强烈捕获“self”可能会导致保留循环
。我已经修改了我的代码以添加 __weak
属性到这篇文章后面的 block 中使用的对象:Fix warning "Capturing [an object] strongly in this block is likely to lead to a retain cycle" in ARC-enabled code
结果代码是:
_operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(parseServerReply) object:nil];
_request = [ASIHTTPRequest requestWithURL:@"server.address"];
// ...
__weak NSOperation * operation = _operation;
__weak ASIHTTPRequest * request = _request;
__weak typeof(self) * self_ = self;
[request setCompletionBlock:^{
[self_ setResponseString:request.responseString];
[[MyAppDelegate getQueue] addOperation:operation];
}];
我想知道这是否仍然会导致保留周期和内存泄漏。如果是这样,有没有办法避免泄漏?
最佳答案
您不需要将所有内容都设为弱对象,也不想在 block 中一直引用弱对象(尤其是当该 block 可以在不同的线程中执行时)。
这样想。使用 ARC 时,对象是引用计数的。在引用计数变为零之前,不会对对象调用 dealloc。因此,只要周围有一个引用,该对象就会保持事件状态。
但是,请考虑两个相互有强引用的对象。在对方释放其引用之前,双方都不会解除分配。
当您创建一个 block 时,它会捕获它的环境,这意味着它将创建对该 block 范围内使用的任何对象的强引用。
考虑到这一点......
id object = getMeSomeObject();
// <object> is implicitly __strong, and now has a reference.
在释放所有强引用之前,对象不会被释放。如果您在 block 中使用它,该 block 会自动创建自己的强引用,以确保该对象在 block 存在时就存在。
__weak 引用是一种间接级别,使您可以在对象存在时访问该对象。基本上,如果您将一个对象分配给一个 __weak 指针,那么只要该对象还活着,该指针就可以保证为您提供相同的对象。一旦对象启动了它自己的 dealloc(),它就会找到所有的 __weak 指针并将它们设置为 nil。
因此,您的 _weak 指针将始终处于两种状态之一。只要对象存在,它就指向一个有效的对象,或者当对象有 dealloc 时它是 nil。您应该永远不要通过弱指针访问对象,因为该对象可能会在您背后解除分配,给您留下错误的指针。
那么,您想要做什么,它会在堆栈上创建一个 __strong 引用,以便该对象在您需要时一直保持事件状态。
在你的情况下......
[_request setCompletionBlock:^{
[self setResponseString:_request.responseString];
[[MyAppDelegate getQueue] addOperation:_operation];
}];
这个 block 显然持有对 self
的强引用。你可能不想要那样。让我们尝试修复它...
// weakSelf will be "magically" set to nil if <self> deallocs
__weak SelfType *weakSelf = self;
[_request setCompletionBlock:^{
// If <self> is alive right now, I want to keep it alive while I use it
// so I need to create a strong reference
SelfType *strongSelf = weakSelf;
if (strongSelf) {
// Ah... <self> is still alive...
[strongSelf setResponseString:_request.responseString];
[[MyAppDelegate getQueue] addOperation:_operation];
} else {
// Bummer. <self> dealloc before we could run this code.
}
}];
嘿,我们现在有一个弱的 self
,但是......你仍然会遇到同样的问题。为什么?因为 _request 和 _operation 是实例变量。如果您访问 block 内的实例变量,它会隐式创建对 self
的强引用。
再试一次...
// weakSelf will be "magically" set to nil if <self> deallocs
__weak SelfType *weakSelf = self;
[_request setCompletionBlock:^{
// If <self> is alive right now, I want to keep it alive while I use it
// so I need to create a strong reference
SelfType *strongSelf = weakSelf;
if (strongSelf) {
// Ah... <self> is still alive...
[strongSelf setResponseString:strongSelf->_request.responseString];
[[MyAppDelegate getQueue] addOperation:strongSelf->_operation];
} else {
// Bummer. <self> dealloc before we could run this code.
}
}];
现在,您可能不应该“原始”使用实例变量,但那是另一个话题。
通过这些更改,您的 block 不再具有对 self 的强引用,如果 self
确实 dealloc,它会优雅地处理它。
最后,我要重申,对 strongSelf 的赋值是必要的,以防止对象在检查 weakSelf 后消失的潜在问题。具体...
if (weakSelf) {
// Hey, the object exists at the time of the check, but between that check
// and the very next line, its possible that the object went away.
// So, to prevent that, you should ALWAYS assign to a temporary strong reference.
[weakSelf doSomething];
}
strongSelf = weakSelf;
// OK, now IF this object is not nil, it is guaranteed to stay around as long as
// strongSelf lives.
现在,在这种情况下, block 是请求的一部分,它是 self
的一部分,所以 self
deallocs 的可能性很小,但我的主要观点在这里是使用 self 来防止循环保留,但仍然始终通过强引用访问对象——弱-强之舞。
关于iphone - 使用 __weak 属性将参数传递给 block 会导致内存泄漏吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10707143/
你能比较一下属性吗 我想禁用文本框“txtName”。有两种方式 使用javascript,txtName.disabled = true 使用 ASP.NET, 哪种方法更好,为什么? 最佳答案 我
Count 属性 返回一个集合或 Dictionary 对象包含的项目数。只读。 object.Count object 可以是“应用于”列表中列出的任何集合或对
CompareMode 属性 设置并返回在 Dictionary 对象中比较字符串关键字的比较模式。 object.CompareMode[ = compare] 参数
Column 属性 只读属性,返回 TextStream 文件中当前字符位置的列号。 object.Column object 通常是 TextStream 对象的名称。
AvailableSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。 object.AvailableSpace object 应为 Drive 
Attributes 属性 设置或返回文件或文件夹的属性。可读写或只读(与属性有关)。 object.Attributes [= newattributes] 参数 object
AtEndOfStream 属性 如果文件指针位于 TextStream 文件末,则返回 True;否则如果不为只读则返回 False。 object.A
AtEndOfLine 属性 TextStream 文件中,如果文件指针指向行末标记,就返回 True;否则如果不是只读则返回 False。 object.AtEn
RootFolder 属性 返回一个 Folder 对象,表示指定驱动器的根文件夹。只读。 object.RootFolder object 应为 Dr
Path 属性 返回指定文件、文件夹或驱动器的路径。 object.Path object 应为 File、Folder 或 Drive 对象的名称。 说明 对于驱动器,路径不包含根目录。
ParentFolder 属性 返回指定文件或文件夹的父文件夹。只读。 object.ParentFolder object 应为 File 或 Folder 对象的名称。 说明 以下代码
Name 属性 设置或返回指定的文件或文件夹的名称。可读写。 object.Name [= newname] 参数 object 必选项。应为 File 或&
Line 属性 只读属性,返回 TextStream 文件中的当前行号。 object.Line object 通常是 TextStream 对象的名称。 说明 文件刚
Key 属性 在 Dictionary 对象中设置 key。 object.Key(key) = newkey 参数 object 必选项。通常是 Dictionary 
Item 属性 设置或返回 Dictionary 对象中指定的 key 对应的 item,或返回集合中基于指定的 key 的&
IsRootFolder 属性 如果指定的文件夹是根文件夹,返回 True;否则返回 False。 object.IsRootFolder object 应为&n
IsReady 属性 如果指定的驱动器就绪,返回 True;否则返回 False。 object.IsReady object 应为 Drive&nbs
FreeSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。只读。 object.FreeSpace object 应为 Drive 对象的名称。
FileSystem 属性 返回指定的驱动器使用的文件系统的类型。 object.FileSystem object 应为 Drive 对象的名称。 说明 可
Files 属性 返回由指定文件夹中所有 File 对象(包括隐藏文件和系统文件)组成的 Files 集合。 object.Files object&n
我是一名优秀的程序员,十分优秀!