如果从块中调用的方法使用自我,我是否需要使用弱自我指针?
使用self.
在块中导致保留周期,所以我需要创build一个weakSelf
的引用。 我明白这一点
但!
如果从我的块我调用一个方法,使用self
“,这是否也导致保留周期?例如,如果我重新加载UITableView
从一个块和我的一些UITableView
委托方法我self.
这是否意味着我必须到处传递这个薄弱的参考?
我可能会误解你的问题,但你的措辞:
如果从我的块中我调用一个使用“自我”的方法,这是否也会导致保留周期? 例如,如果我从块中重新加载UITableView,并在我称为“自我”的一些UITableView委托中,我正在导致一个保留周期? 那意味着我必须到处传递这个弱引用。
暗示你误解了self
。 希望如果是这样,以下将帮助,而不是阻碍你的理解…
什么是self
?
标识符self
只是您的方法的参数之一的名称,它只是隐式传递,而不是像其他参数那样显式传递。 例如,如果你有一个类:
@implementation MyClass - (void) someMethod:(NSInteger)value { ... self ... value } @end
那么这种方法是有效的 (即为了清晰起见,将事实稍微弯曲一点):
- (void) someMethod:(NSInteger)value withObject:(MyClass *)self { ... self ... value }
当一个实例方法被调用时,为self
parameter passing的值是方法应该对其进行操作的实例的引用,例如调用
MyClass *someInstance = ... [someInstance someMethod:42];
实际上是呼吁:
someMethod:42 withObject:someInstance
强大的参考周期
只要存在对该对象的强烈引用,对象(包括类和块的实例)就保持活动状态。
如果一个对象A
拥有一个强引用,比如在一个实例variables或者属性中,对象B
,那么只要A
还活着, B
至less会保持活着(可能还有其他强引用)。
如果一个对象A
持有对B
的强烈引用,而B
持有一个,那么你有一个强大的引用周期 – 每个对象保持另一个活着,并且不会被收集。 这可能导致内存泄漏 – 从未收集到未使用的内存 – 除非A
和B
都是从创build直到程序结束。
此外,您不要简单地通过将引用存储在方法的局部variables和参数中来创build强引用循环。 就其性质而言,这些variables及其内容是瞬态的,并且在方法返回时被破坏。
在块中使用self
使用“自我”。 在块导致保留周期,所以我需要创build一个weakSelf的参考。
不完全的。 当你在一个块中使用self
时,通过引用一个实例variables直接或间接地使用self
,编译器会警告你可以创build一个引用周期。 ( 注意 :还有其他方法可以创build引用循环,无论是否使用块,编译器都不会警告您,pipe理循环只是您需要注意的事情。
如果在self
引用的对象中存储对块的引用,则只会实际创build一个循环。 然而,这本身并不坏,只要在某些时候手动打破循环 – 比如说将nil
存储在引用块的variables中 – 循环就不会有问题了。
最后…
你本身没有什么担心你的:
UITableView委托我称之为“自我”。
因为这个self
只是一个委托的本地参数,它的初始值在某些时候回到了调用链上,它来自于你评估你的weakSelf
引用并确定它不是nil
,然后调用它的方法。
HTH
首先: self
不会导致保留周期。 这是一个都市传奇。 不正确是显而易见的:单个引用永远不会导致循环。 如果程序块是由self
直接或间接引用的,例如通过属性,那么在块内使用self
会导致保留循环。
给你Q:
如果你在块内部调用一个方法,这个消息可能是接收者self
,所以你在块内有一个self
的用法。 为此,它被捕获并保留。
如果你真的没有使用self
内部的self
也不使用自己的财产,你没有self
的用法,它不被捕获,因此不保留。 但在这种情况下,你可以有一个悬挂指针或没有参考。
当程序块执行时,你不需要担心引用 – 最终完成它所做的任何事情,所有这些引用都会消失。
您需要担心的是在创build块时捕获的引用。 这些参考文献一直保持到块消失。 所以,如果你的块有一个“自我”的参考,那只是因为块存在的参考。 如果你将这个块存储在自己的属性中,你就有一个循环。
所以如果你把一个块作为一个属性存储在自己中,那么这个块不应该捕获自己。 这很容易通过让它访问和捕获自己的弱副本。 请记住,块正在执行时,自我的弱副本可能是零。 这意味着自己的对象已经离开了我们的世界,你的块可能不需要做任何事情。
简短的回答 :不,在这种情况下,自我不被保留。
长答案
首先,保持自我和参照周期不是一回事。 引用循环是一系列对象之间的强引用循环:A-> B-> C-> A是一个保留循环。
一般的想法是,你要始终保证,如果你在一个块中引用self,那么你不要强烈地引用这个块,也不要通过一个强引用链来引用它。 事实上,如果您确定在某些条件下打破了保留周期,则可以有目的地使用保留周期。 不是我个人推荐这个。
看看苹果网站上的文档 。 它清楚地表明,值是以块的forms捕获的,并且捕获一个对象引用将保留这个对象。
基本上这意味着引用一个块中的一个对象的retainCount递增1,当这个块被释放时,retainCount递减1。
但是,在块中使用__weak指针时,保留计数是不变的。
这是一个例子:
- (void) doSomething { NSLog(@"%@", self); } - (void) callBlock { __weak typeof(self) weakSelf = self; dispatch_block_t block = ^{ [weakSelf doSomething]; }; }
当你写[obj method:params]
这实际上转化为以下调用: objc_msgSend(obj, @selector(method:), params)
。 Objective-C的一个特点是,如果你调用一个nil指针的方法,它返回nil。 这通过objc_msgSend(nil, @selector(anyselector), ...)
总是返回nil来保证。 请注意,SEL仅仅是一个const char [],所以它不会以任何方式影响保留计数。
因此当这个块被执行的时候,如果你的对象被释放了,弱的weakSelf
variables将被取消,并且块的主体将会转化为objc_msgSending为零,除了浪费很less的CPU周期之外它什么也不做。
综上所述,Objective-C消息系统的实现方式是调用一个方法不会保留这个对象或者这个方法或者这个方法的实现,因为这是一个简单的函数调用。