【发布时间】:2011-06-08 19:29:31
【问题描述】:
在试图弄清楚为什么我在私有类别中声明的读写属性没有生成设置器时,我学到了一些新东西。这是因为我的类别被命名为:
// .m
@interface MyClass (private)
@property (readwrite, copy) NSArray* myProperty;
@end
改成:
// .m
@interface MyClass ()
@property (readwrite, copy) NSArray* myProperty;
@end
我的二传手是合成的。我现在知道类扩展不仅仅是匿名类别的另一个名称。不命名类别会导致它变成另一种野兽:它现在提供编译时方法实现强制并允许您添加 ivars。我现在了解了其中每一个的基本原理:类别通常用于在运行时向任何类添加方法,而类扩展通常用于强制执行私有 API 实现和添加 ivars。我接受这个。
但是有一些小事让我感到困惑。首先,在高层次上:为什么要这样区分?这些概念看起来像是相似的想法,无法确定它们是相同的还是不同的概念。如果它们相同,我希望使用没有名称的类别与使用命名类别(它们不是)完全相同的事情是可能的。如果它们不同,(它们是)我预计两者之间的句法差异会更大。说“哦,顺便说一下,要实现一个类扩展,只需要写一个类别,但省略名称。它神奇地改变了。”似乎很奇怪。
其次,关于编译时强制执行的主题:如果您不能在命名类别中添加属性,为什么这样做会让编译器相信您这样做了?为了澄清,我将用我的例子来说明。我可以在头文件中声明一个只读属性:
// .h
@interface MyClass : NSObject
@property (readonly, copy) NSString* myString;
@end
现在,我想转到实现文件并授予自己对该属性的私有读写访问权限。如果我做得对:
// .m
@interface MyClass ()
@property (readwrite, copy) NSString* myString;
@end
当我不合成时会收到警告,当我合成时,我可以设置属性,一切都很好。但是,令人沮丧的是,如果我碰巧对 Category 和 Class Extension 之间的区别略有误导,我会尝试:
// .m
@interface MyClass (private)
@property (readwrite, copy) NSString* myString;
@end
编译器完全放心,认为该属性是可读写的。在设置 myString 时,我没有收到任何警告,甚至没有很好的编译错误“无法设置对象 - 要么是只读属性,要么没有找到设置器”,如果我没有在类别中声明读写属性。我只是在运行时收到“不响应选择器”异常。如果(命名的)类别不支持添加 ivars 和属性,那么要求编译器遵循相同的规则是不是太过分了?我是否错过了一些宏大的设计理念?
【问题讨论】:
-
我相信您的意思是
readwrite用于私有 myString 属性声明。我进行了编辑以反映这一点;希望这是正确的。
标签: objective-c