Why are Objective-C delegates usually given the property assign instead of retain?
我正在浏览由斯科特·史蒂文森维护的精彩博客,我试图理解一个基本的目标C概念,即分配代表"分配"财产与"保留"。注意,在垃圾收集环境中两者都是相同的。我主要关注的是一个非基于GC的环境(例如:iPhone)。
直接从斯科特的博客:
"assign关键字将生成一个setter,它将值直接分配给实例变量,而不是复制或保留它。这最适合于nsinteger和cgloat之类的基元类型,或者不直接拥有的对象,例如委托。"
您不直接拥有委托对象意味着什么?我通常会保留我的代表,因为如果我不希望他们进入深渊,RETAIN会帮我解决。我通常将UITableViewController从其各自的数据源和委托中抽象出来。我还保留了那个特定的对象。我想确保它永远不会消失,所以我的UITableView总是有它的委托。
有人能进一步解释我错在哪里/为什么,这样我就可以理解在Objective-c 2.0编程中使用委托的assign属性而不是retain的这种常见范例吗?
谢谢!
- 用"代表"和"iphone"重新标记。
- 为什么委托分配而不是复制(如nsstring?)
避免保留代理的原因是需要避免保留周期:
A创建BA将自己设置为B的委托…A由其所有者发布
如果B保留了A,A不会被释放,因为B拥有A,因此A的dealLoc永远不会被调用,导致A和B都泄漏。
你不必担心A会离开,因为它拥有B,因此会在DealLoc中将其清除。
- 我不同意,迈克。我刚发现一个问题,一个模态有一个委托,它忽略了模态。但当我在模式中执行内存警告时,它会释放委托。然后,当我去解散我的模式,代表是零。撞车。
- 好吧,所以我不同意,但你是对的,这是一个设计缺陷。我发现我是通过一个真正的解雇者的儿童班来传递我的解雇通知。该子类已释放,无法传递到模式的容器委托以取消。我把它改为传递一个指向最后一个委托的指针,这个委托在内存警告时没有被释放,一切都很好。
- 您的代码不应该以这样的方式编写:一个nil委托会导致代码崩溃。只有所属对象才应具有所属引用。当取消分配时,它必须在释放所拥有对象的委托之前将其设置为nil。然后,发送给nil委托的任何消息都将被忽略。但是,在消息中传递nil对象可能会崩溃。只需确保你不以这种方式与代表打交道。
- 等等——这不是weak所做的吗?问题是为什么使用assign而不是weak?
- @沃科克伦:不,这个问题是为什么用assign而不是retain。这个问题早于ARC;直到ARC被引入,weak和strong(后者与retain同义)才存在。你应该单独问你关于weak和assign的问题。
因为发送委托消息的对象不拥有委托。
很多时候,它是相反的,就像控制器将自己设置为视图或窗口的委托:控制器拥有视图/窗口,因此如果视图/窗口拥有其委托,两个对象将彼此拥有。当然,这是一个保留循环,类似于具有相同结果的泄漏(应该是死的对象仍然活着)。
其他时候,对象是对等的:两个对象都不拥有另一个,可能是因为它们都属于同一个第三个对象。
不管怎样,带有委托的对象都不应保留其委托。
(顺便说一下,至少有一个例外。我不记得那是什么,我觉得没有什么好的理由。)
附录(增加2012-05-19):在ARC下,你应该使用weak,而不是assign。当对象死亡时,弱引用会自动设置为nil,从而消除了委托对象最终向死委托发送消息的可能性。
如果出于某种原因,您要远离ARC,至少将指向对象的assign属性更改为unsafe_unretained,这表明这是对对象的不包含但非零引用。
assign仍然适用于ARC和MRC下的非对象值。
- NSURLConnection保留其代表。
- 是的,使用weak,但这并不能回答最初的问题:为什么苹果使用assign而不是weak?
- @wcochran:最初的问题是"为什么给定assign而不是保留代理属性";当被问到weak时,它不存在。你的问题不一样,你应该单独问。我很乐意回答。
- @wcochran和peter,这个问题是不是在别的地方问过?
请注意,当您有一个要分配的委托时,每当要解除分配对象时,总是将委托值设置为nil非常重要-因此,如果对象在其他地方没有这样做,则应始终小心地在解除分配中消除委托引用。
- "请注意,当您有一个分配的委托时,每当要解除分配对象时,总是将委托值设置为nil非常重要"为什么?
- 因为任何左引用集都将在解除分配对象后无效(指向不再分配给预期对象类型的内存),因此如果尝试使用它,将导致崩溃。调试器中出现这种情况的一个标志是,调试器声明某个变量的类型与实际声明的变量的类型完全不同。
- 只有当您作为委托的对象被另一个源(如计时器或其他异步回调)保留时,才需要这样做。否则,它将在您释放后被释放,并且不会尝试调用委托方法。
- @安德鲁:是的,但是如果你总是练习把代表们排除在外,那么你就不会忘记什么时候重要了,或者如果你不小心过度保留了一个被持有的物体,它仍然在周围。如果您消除了代理,那么结果只是一个泄漏,而不是随后发生崩溃的泄漏。
其中一个原因是为了避免保留周期。只是为了避免出现这样的情况:A和B两个对象相互引用,而没有一个对象从内存中释放出来。
Acutally分配最适合于nsinteger和cgfloat之类的基本类型,或者不直接拥有的对象,例如委托。
- 这是从OP的报价单和接受的答案中分别复制的,不是吗?