Objective-C 中的只读属性?
我在接口中声明了一个只读属性,如下所示:
@property (readonly, nonatomic, copy) NSString* eventDomain;
也许我误解了属性,但我认为当您将其声明为 readonly
时,您可以在实现内部使用生成的设置器(.m
) 文件,但外部实体无法更改该值。 这个问题说这就是应该发生的事情。这就是我所追求的行为。但是,当尝试使用标准 setter 或点语法在 init 方法内设置 eventDomain
时,它会给我一个 无法识别的选择器发送到实例。
错误。当然,我正在 @synthesize
处理该属性。尝试像这样使用它:
// inside one of my init methods
[self setEventDomain:@"someString"]; // unrecognized selector sent to instance error
那么我是否误解了属性的 readonly
声明?还是有其他事情发生?
I have declared a readonly property in my interface as such:
@property (readonly, nonatomic, copy) NSString* eventDomain;
Maybe I'm misunderstanding properties, but I thought that when you declare it as readonly
, you can use the generated setter inside of the implementation (.m
) file, but external entities cannot change the value. This SO question says that's what should happen. That is the behavior I'm after. However, when attempting to use the standard setter or dot syntax to set eventDomain
inside of my init method, it gives me an unrecognized selector sent to instance.
error. Of course I'm @synthesize
ing the property. Trying to use it like this:
// inside one of my init methods
[self setEventDomain:@"someString"]; // unrecognized selector sent to instance error
So am I misunderstanding the readonly
declaration on a property? Or is something else going on?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您需要告诉编译器您还需要一个设置器。一种常见的方法是将其放在 类扩展:
You need to tell the compiler that you also want a setter. A common way is to put it in a class extension in the .m file:
Eiko等人给出了正确答案。
这里有一个更简单的方法:直接访问私有成员变量。
示例
在头 .h 文件中:
@property (strong, nonatomic, readonly) NSString* foo;
在实现 .m 文件中:
就是这样,这就是您所需要的。没有混乱,没有大惊小怪。
详细信息
自 Xcode 4.4 和 LLVM 编译器 4.0 起 (Xcode 4.4 中的新功能),您无需搞乱其他答案中讨论的琐事:
synthesize
关键字声明属性
foo
后,您可以假设 Xcode 添加了一个以下划线前缀命名的私有成员变量:_foo
。如果该属性声明为
readwrite
,Xcode 会生成一个名为foo
的 getter 方法和一个名为setFoo
的 setter。当您使用点符号(我的 Object.myMethod)时,会隐式调用这些方法。如果属性被声明为只读,则不会生成 setter。这意味着用下划线命名的支持变量本身不是只读的。readonly
仅仅意味着没有合成 setter 方法,因此使用点表示法设置值会失败并出现编译器错误。点表示法失败是因为编译器阻止您调用不存在的方法(setter)。解决这个问题最简单的方法是直接访问以下划线命名的成员变量。即使不声明下划线命名的变量,您也可以这样做! Xcode 会在构建/编译过程中插入该声明,因此编译后的代码确实会有变量声明。但您永远不会在原始源代码文件中看到该声明。不是魔法,只是语法糖。
使用
self->
是访问对象/实例的成员变量的一种方法。您也许可以省略它,只使用 var 名称。但我更喜欢使用 self+arrow,因为它使我的代码能够自我记录。当您看到self->_foo
时,您就明确知道_foo
是该实例上的成员变量。顺便说一句,关于属性访问器与直接 ivar 访问的优缺点的讨论正是您将在 Dr. Matt Neuberg 的iOS 编程一书。我发现阅读和重读非常有帮助。
Eiko and others gave correct answers.
Here's a simpler way: Directly access the private member variable.
Example
In the header .h file:
@property (strong, nonatomic, readonly) NSString* foo;
In the implementation .m file:
That’s it, that’s all you need. No muss, no fuss.
Details
As of Xcode 4.4 and LLVM Compiler 4.0 (New Features in Xcode 4.4), you need not mess with the chores discussed in the other answers:
synthesize
keywordAfter declaring a property
foo
, you can assume Xcode has added a private member variable named with a prefix of underscore:_foo
.If the property was declared
readwrite
, Xcode generates a getter method namedfoo
and a setter namedsetFoo
. These methods are implicitly called when you use the dot notation (my Object.myMethod). If the property was declaredreadonly
, no setter is generated. That means the backing variable, named with the underscore, is not itself readonly. Thereadonly
means simply that no setter method was synthesized, and therefore using the dot notation to set a value fails with a compiler error. The dot notation fails because the compiler stops you from calling a method (the setter) that does not exist.The simplest way around this is to directly access the member variable, named with the underscore. You can do so even without declaring that underscore-named variable! Xcode is inserting that declaration as part of the build/compile process, so your compiled code will indeed have the variable declaration. But you never see that declaration in your original source code file. Not magic, just syntactic sugar.
Using
self->
is a way to access a member variable of the object/instance. You may be able to omit that, and just use the var name. But I prefer using the self+arrow because it makes my code self-documenting. When you see theself->_foo
you know without ambiguity that_foo
is a member variable on this instance.By the way, discussion of pros and cons of property accessors versus direct ivar access is exactly the kind of thoughtful treatment you'll read in Dr. Matt Neuberg's Programming iOS book. I found it very helpful to read and re-read.
我发现使用只读属性的另一种方法是使用 @synthesize 来指定后备存储。例如
,然后在实现中,
您的方法可以设置
m_whatever
,因为它是一个成员变量。过去几天我意识到的另一件有趣的事情是,您可以使子类可写的只读属性如下所示:(
在头文件中)
然后,在实现中
它将使用头文件中的声明,因此子类可以更新财产的价值,同时保留其只读性。
但在数据隐藏和封装方面略有遗憾。
Another way I've found to work with readonly properties is to use @synthesize to specify the backing store. For example
Then in the implementation
Your methods can then set
m_whatever
, since it is a member variable.Another interesting thing I have realized in the past few days is you can make readonly properties that are writable by subclasses like such:
(in the header file)
Then, in the implementation
It will use the declaration in the header file, so subclasses can update the value of the property, while retaining its readonlyness.
Slightly regrettably in terms of data hiding and encapsulation though.
请参阅 自定义 iOS 文档中的现有类。
只读属性只有一个 getter 方法。您仍然可以直接在属性的类中或使用键值编码设置支持 ivar。
See Customizing Existing Classes in the iOS Docs.
Readonly properties only have a getter method. You can still set the backing ivar directly within the property's class or using key value coding.
你误解了另一个问题。 在该问题中有一个类扩展,声明如下
:生成的 setter 仅在类的实现中可见。因此,正如 Eiko 所说,您需要声明一个类扩展并覆盖属性声明,以告诉编译器仅在类内生成 setter。
You are misunderstanding the other question. In that question there is a class extension, declared thus:
That is what generates the setter only visible within the class's implementation. So as Eiko says, you need to declare a class extension and override the property declaration to tell the compiler to generate a setter only within the class.
最短的解决方案是:
MyClass.h
MyClass.h
The shortest solution is:
MyClass.h
MyClass.h
如果属性被定义为只读,则意味着实际上不会存在可以在类内部使用或从其他类外部使用的 setter。 (即:如果有意义的话,您只会有一个“getter”。)
从声音来看,您需要一个标记为私有的普通读/写属性,您可以通过在您的类变量中将类变量设置为私有来实现接口文件如下:
If a property is defined as readonly, that means that there effectively wont be a setter that can be used either internally to the class or externally from other classes. (i.e.: You'll only have a "getter" if that makes sense.)
From the sounds of it, you want a normal read/write property that's marked as private, which you can achieve by setting the class variable as private in your interface file as such: