从C程序员的角度保留Objective C中的对象

时间:2015-04-07 11:05:39

标签: objective-c cocoa pointers

在C中编程了15年以上,我最近开始使用Objective C并且有一件事我不太理解:有几个方法返回一个指向对象的指针,但我不拥有这个对象。相反,人们说我需要保留这个对象,只要我需要访问它。

我们以[NSTextField stringValue]的返回值为例。这个方法会给我返回一个NSString。但是我没有这个NSString,所以如果我想使用它,我必须保留它,只要我需要它,例如。

NSString *s = [myTextField stringValue];
...              // why can't the object become invalid during this time?
[s retain];  
....             // do some work
[s release];

这里让我感到困惑的是调用[myTextField stringValue]和[s retain]之间的时间。我不拥有NSString,所以当我在上面的代码的第三行中执行retain调用时,谁保证指向NSString的指针仍然有效?

上面的代码当然非常简单,但是因为必须保证“s”指针在调用retain时仍然有效,所以当我调用retain时,还必须保证指针仍然有效在字符串上很久以后?假设在调用[NSTextField stringValue]后4小时?我的意思是,我甚至可以将NSString指针存储在一个全局变量中并在稍后调用retain,或者是否存在一个规则,即保留必须在当前作用域中发生,或者在获得指针之后很快就会发生而不是4小时后?但是,很难理解Objective C编译器/运行时应如何跟踪所有这些。

从C程序员的角度来看,看起来保留在上面的代码中有些多余,因为[NSTextField stringValue]返回的指针无论如何都必须保持有效,如果它可以调用[retain]就可以了。但那当然不可能是这种情况。我相信一旦你明白了这一切都是有道理的,但目前我仍在努力去理解这一点,因为这与我多年来在C中所做的事情相矛盾。

希望有人可以对此有所了解。谢谢!

2 个答案:

答案 0 :(得分:1)

我确定你知道保留和发布已弃用,而且我们不再需要为这些东西增加负担。

在您的示例中,您正在创建一个新指针:NSString * s并将其指定为指向文本字段指向其文本属性的同一地址。重要的是要理解s的作用域是这里的特定代码片段,其中有一些花括号(大括号)。如果你调用retain on s,你必须在这个范围内释放它,因为之后你不再拥有s指针而且你会有泄漏。 但是指向的对象无论如何都会一直存在,所以这个保留/释放对是多余的。

如果您确实希望将来在某个未确定的位置使用此字符串,那么您的指针需要作为属性或iVar限定为整个实例。然后你可以根据你的例子调用你的retain并保存它直到将来的某个时间,如果textField被释放NSString * text属性所指向的NSString对象应该存活,因为当textField调用它上面的一个发布时它的引用计数不会达到零;您之前添加了一个保留。因此,保留可能会被视为“在此对象中购买股票”#39;并释放出来并出售我在这个对象中的份额'。对象本身决定比textField的发布消息更长,后者当时只是其所有者之一。

所有这些说明,当时制作自己的字符串副本将是一种更传统的方法,如果你只是在一个属于的对象上添加一个保留,那么许多程序员将是至关重要的。 UI(或任何东西)。这种伏都教的最大陷阱是你可以轻松地创造一个“保留周期”。 - 所有权循环,只能涉及两个对象,但可能很容易就是一个复杂的图形。保留周期可能非常难以追踪,因此只需通过良好的设计来避免它们就好了。

答案 1 :(得分:1)

如果您想了解Cocoa中的手动内存管理,您应该阅读两个文档:

以下是核心竞争力关于接收无主对象的内容:

  

如果从程序中的其他位置收到对象,通常保证在收到的方法或函数中保持有效。如果您希望它在该范围之外保持有效,则应保留或复制它。 / p>

以上是高级指南所说的内容:

  

通常保证收到的对象在接收到的方法中保持有效,并且该方法也可以安全地将对象返回给其调用者。在两种情况下使用retain:(1)在accessor方法或init方法的实现中,获取要存储为对象属性的对象的所有权; (2)防止对象因某些其他操作的副作用而失效(如避免导致您正在使用的对象的释放中所述)。