使用ARC为ios声明只读属性的正确方法是啥

Posted

技术标签:

【中文标题】使用ARC为ios声明只读属性的正确方法是啥【英文标题】:What is the correct way to declare a readonly property for ios using ARC使用ARC为ios声明只读属性的正确方法是什么 【发布时间】:2012-05-22 01:25:17 【问题描述】:

总的来说,我是 ios 开发的新手,从未处理过手动引用计数(保留、释放、自动释放)。因此,我对魔法 ARC 的表现不是很了解。

我以为我明白了,直到有人问我应该将哪种类型的所有权(weakstrongassign 等)赋予指向对象的只读属性,例如:

@property (readonly,nonatomic) NSString* name;

我在这里读到 Questions about a readonly @property in ARC 离开 strong/weak 不会实际编译,除非您在 @synthesize 属性时指定支持变量;我只是碰巧指定了一个像这样的支持 ivar:

@synthesize name = _name;

现在我了解到变量的默认“生命周期限定符”很强大,来自这里:http://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW4

长话短说 - 我间接将我的属性定义为(readonly,nonatomic,strong),因为_name ivar 被隐式​​声明为__strong

我有几个问题:

    strong 是要使用的正确生命周期限定符吗?我假设是这样,否则支持我的 NSString* 的对象将不会在任何地方拥有,因此会被自动释放(来自 Java 领域,这是有道理的,因为默认情况下所有引用都是强引用)。

    在这种情况下是否还有其他有意义的修饰符,例如copyassign

    将属性声明为(readonly,nonatomic,strong)(readonly,nonatomic)使用该属性的代码有什么影响吗?例如。在没有strong 关键字的情况下声明它会导致对象指针存储为__unsafe_unretained,而strong 属性将存储在__strong 指针中?

谢谢!

编辑

据我所知,以下适用于只读属性:

对于非 NSObject* 类型(int、float、void* 等),请使用 (readonly, assign)。 对于对象指针,请使用 (readonly, strong)(readonly, copy) - 这些功能对于只读属性相同,但如果您扩展/子类并将属性重新声明为 readwrite,您可能需要复制语义。 对于对象指针,(readonly, weak) 仅在您要在该属性中存储一个已经很弱的指针时才有意义(该指针在其他地方必须是强指针,否则该对象将被释放)。

【问题讨论】:

请注意,“strong”是隐含的,因此如果您使用(strong) 扩展只读指定的(readonly),它将起作用,但(copy) 不会。相反,您会看到“ARC 禁止综合属性......具有未指定的所有权或存储属性。”在这种情况下,您需要在标头定义中明确说明(readwrite, copy)。这让我绊倒了几分钟。 【参考方案1】:

    strong 是正确的,如果你想保持对你所指向的任何东西的强(拥有)引用。通常,您确实想要强引用,但为了防止循环引用(特别是在父/子关系中,如果父指向子,子指向父,它们将永远不会被释放)有时需要使用弱引用.另外,如果你想保留一个指向不属于你的对象的指针,但希望它只有在它存在时才有效,那么你想使用弱指针,因为当它获取由所有者释放,您的指针将自动设置为nil,并且不会指向不应该指向的内存。

    assign 与标量值一起使用,并且是默认设置器。如果您想自动制作对象的副本并将指针设置为副本而不是指向原始对象,copy 是有意义的。仅当您有特定需求时才有意义(通常是因为您不希望对象在您身上发生变异)。

    您提供的链接显示 __strong 是默认值(因此您不需要指定它)指的是 variablesnot 声明的属性。声明属性的默认值是assign,所以它肯定会有所作为。但是,如果您想要assign,则无论您是否指定它都没有区别(只是为了清楚它是您想要的)。 编辑:但是,正如 Jacques 所指出的,这正在随着 LLVM 3.1 的变化而发生变化,默认情况下 正在更改,从 assignstrong。在这种情况下,您是否指定strong 绝对没有区别,如果您愿意,可以将其省略。我个人认为最好把它拼出来(特别是因为不同版本之间存在冲突),这样每个看代码的人都在同一个页面上。不过,其他人可能不同意这一点。 :)

我建议在这里阅读Objective-C 编程语言Declared Properties 部分:<document removed by Apple with no direct replacement>

【讨论】:

从 Clang 的下一个版本 (3.1) 开始,他们实际上也更改了属性的默认值:clang.llvm.org/docs/… 有趣...现在 ARC 和非 ARC 代码是不同的。谢谢@JacquesCousteau! 我已经多次阅读您提供的链接,不幸的是,我发现它对有用的信息非常了解,这就是我在这里问的原因。至于您的回答,我认为它没有解决我的问题,即专门针对只读属性的问题。 好吧,我回答了这个问题(除了提供链接之外),因为你在这里问过。 :) 就我的回答而言,这里的一切都适用于声明的属性,无论它们是否是只读的。 readonly 并没有什么特别之处,只是当你 @synthesize 时不会为你提供 setter。 我理解,但是在您的回答中,您说副本在某些情况下是有意义的,但是对于只读属性是否有意义?我已经很困惑了,这就是为什么我希望将解释限制为只读属性。【参考方案2】:

还有一点:属性可以从readonly 重新声明为readwrite。例如,子类可以使超类的只读属性成为可读写的,类似于有多少 Cocoa 类具有添加可变性的子类。同样,一个属性可能是公开只读的,但类可以将其重新声明为可读写,以供类扩展内部使用。因此,当类设置自己的属性时,它可以利用合成的 setter 来正确进行内存管理并发出适当的 Key-Value Observing 更改通知。

就目前的情况而言,该属性的所有其他属性都必须保持一致。可以想象编译器可以放宽这个要求。 (有些人认为这是一个错误。)无论如何,这是声明一个具有所有权属性的readonly 属性的一个原因,例如strongcopy 或weak - 这样它就可以匹配其他地方的readwrite 重新声明。

关于您的问题 3,您是否询问所有权限定符是否会影响调用 getter 的代码?不,它没有。

【讨论】:

所以除了改变合成 ivar 的生命周期限定符之外,强/弱修饰符对只读属性没有任何影响,对吗? 非常感谢您的帮助!【参考方案3】:

这两行代码对我有用:

.h 文件:

@property (nonatomic, readonly, copy) NSString *username;

.m 文件:

@property (nonatomic, readwrite, copy) NSString *username;

【讨论】:

以上是关于使用ARC为ios声明只读属性的正确方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

文件只读是啥意思?

Swift 中的惰性只读属性

使用 ARC 声明委托属性的推荐方法

是否可以在 iOS 中使用 KVC 将值设置为只读属性?

spring事务管理属性为只读是啥意思

属性构造函数只读字段匿名类型