cocoa - 属性(property)的返回地址

标签 cocoa cocoa-touch properties automatic-ref-counting

类A中的函数调用要求和参数为(NSOutputStream **)

我要传递的流保留在B类的属性中

@property (nonatomic, strong) NSOutputStream * outputStream;


我想让外界可以像这样访问B类的属性(对于A类)

- (NSOutputStream **)outputStreamPtr {
    return &_outputStream;
}


但我越来越

从结果类型为“ NSOutputStream * __ autoreleasing *”的函数返回“ NSOutputStream * __ strong *”会更改指针的保留/释放属性

如何在类之外传递属性链接的ivar内存地址?

最佳答案

在您的特定情况下,跳过您要尝试做的事情是否是好的设计的问题,我将尝试解释为什么会出错。如果事实太简单了,就道歉,但希望对您有所帮助。

该问题与属性本身无关,而与变量无关,要理解该问题,我们需要查看什么是变量以及它们在ARC下的行为。一旦完成此操作,就会说明为什么使用NSOutputSteam **时会出错。

我们经常引用“强引用”或“弱引用”,但是这些术语确实有点用词不当。引用既不强也不弱,它们仅仅是引用。强和弱指的是变量如何处理和存储引用。

变量只是一个命名框,它能够保存某种类型的值。例如声明:

int x;


正在请求获得一个能够存储int值的框,并为其指定名称x。那作业:

x = 42;


请求将整数42(的计算机表示)存储在名为x的框中。当处理值类型时,即将计算机表示形式传递并直接存储在变量中的类型,这就是故事的结尾,我们几乎了解所有需要了解的变量。

但是,当存储在变量中的值是引用时,情况会有所不同。例如声明:

NSOutputStream *outStream;


是一个能够存储对NSOutputSteam的引用的框,而不是能够存储实际的NSOutputStream的框。

粗略的类比是将房子的地址存储在盒子中,而不是将实际的房子存储在盒子中(这需要更大的盒子!)。

进一步进行类比,您可能会有很多不同的盒子,所有盒子都存储着同一所房子的地址,但是您不能在多个盒子(位置)中拥有同一个房子-房子是唯一的。编程对象本身是唯一的,但是您可以将对同一对象的引用存储在多个不同的框中。

当不再需要房屋时,可以将其拆除,清理地面,并在同一土地上建造新的不同房屋。 (是的,我们现在要稍微扩展类比;-)。编程中的对象也是如此;它们被创建,具有生命期,并且在不再需要时被拆除-又名垃圾收集,释放等等。

系统如何知道何时不再需要某个对象?不同的编程语言以不同的方式执行此操作。在Objective-C ARC中,它由变量(而不是引用)上的强属性和弱属性处理。这些属性本质上是关于在将新值存储在变量中或变量本身被销毁时如何处理的协议-例如当其拥有的方法method返回(用于局部变量)或其拥有的对象被销毁(例如,变量)时。

如果在声明变量时未指定属性,则假定为strong,因此上面的示例实际上是:

__strong NSOutputStream *outStream;


将引用存储在变量中的强大协议是在作为引用的对象中注册所有权权益,并且只要对象ARC中有所有权权益就不会破坏该对象。因此,当分配:

outStream = w;


经过处理后,看到outStream具有很强的属性:


w引用的对象中注册所有权权益;
如果在outStream中已经存储了现有的引用,则它会取消引用对象的所有权权益的注册;和
将引用存储到outStream中。


这显然比上面的int情况要复杂得多,后者只是将位存储在框中。并且协议根据属性而不同。例如,如果属性较弱(并且在我们的类似术语中比较宽松),则协议为:


注册以接收有关传入引用引用的对象被破坏的通知;
注销以接收有关现有引用所引用的对象被销毁的通知;和
将引用存储到变量中。


发生对象破坏时,已注册接收该对象破坏通知的任何变量都将值nil存储在其中。

这两个协议非常不同,因此简单分配:

a = b;


其中a是参考值变量,其处理方式完全不同,具体取决于附加到a(而不是存储在a中的参考)的属性。

你的情况

当声明类型为NSObjectStream **或通常为<any object> **的参数时,不是传递对NSObjectStream的引用,而是传递对变量的引用,而该变量又持有对NSObjectStream的引用(或通常为<any object> >)-将其视为传递框而不是传递框中的值。

这样做的原因当然是为了使被调用的方法可以将值存储到框中。但是,从上面的内容来看,现在我们将值如何存储到ARC下的框中取决于属性。强,弱等;附在盒子上。因此,被调用的方法不仅需要知道放入框中的值的类型,还需要知道用于存储它的协议。

与变量声明一样,如果未给出协议,则存在默认值,实际上,参数的类型(如错误消息中所示)是:

NSObjectStream * __autoreleasing *


这意味着“一个可以容纳对NSObjectStream的引用并使用协议autoreleasing的盒子”。

自动释放协议与强和弱协议不同,总而言之,它存储新引用而不声明任何所有者权益,并且对旧引用不执行任何操作-例如就像值类型一样,它是一个简单的赋值。 Objective-C将此协议主要用于通过将值存储到传递的框中来返回值的方法,最常见的情况是用于返回错误对象的NSError **参数。为什么存在该协议是另一个故事(这个答案已经很长了!),如果您愿意,可以阅读NSError and __autoreleasing以获得更多详细信息。

现在,您的声明:

return &_outputStream;


您试图返回类型为(默认)为_outputStream的框__strong NSOutputStream *,即该框使用强协议。但是,您已声明函数(默认情况下)以返回__autoreleasing NSOutputStream *类型的框。由于将值存储在框中的方式取决于协议,并且两个协议不同,因此会出现错误。

修复

因此,如果您将函数定义为:

- (NSOutputStream * __strong *)outputStreamPtr
{
   return &_outputStream;
}


那么编译错误将消失。 ARC也将知道如何在返回的框中存储值,并且一切都应该很好。

希望在这个较长的答案之后,您知道为什么,并且不仅比以前更困惑!

当然,正如开头所述,您是否应该首先退还一个盒子是另一个问题,我将在这里跳过。

关于cocoa - 属性(property)的返回地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28308163/

相关文章:

java - 露天更新 Java 支持的网页脚本中的自定义属性

objective-c - 初始化 NSTableView

cocoa - 如何在表格标题中显示排序指示器?

objective-c - 门卫是否允许两个具有相同标识符和不同证书的应用程序

iphone - 使用 iPhone SDK 进行 Ping

c# - 限制属性可接受的值范围的正确方法是什么?

cocoa - 如何从 xib 文件加载并显示窗口

iphone - Objective C - 没有任何内容的 UITextField 的值是多少

ios - 相机对焦 ios

php - 属性默认值为 null 是否与无默认值相同?