我在尝试弄清楚为什么我在私有类别中声明的readwrite属性没有生成setter时学到了一些东西.这是因为我的类别被命名为:
// .m
@interface MyClass (private)
@property (readwrite, copy) NSArray* myProperty;
@end
Run Code Online (Sandbox Code Playgroud)
将其更改为:
// .m
@interface MyClass ()
@property (readwrite, copy) NSArray* myProperty;
@end
Run Code Online (Sandbox Code Playgroud)
我的二传手是合成的.我现在知道,类扩展不仅仅是匿名类别的另一个名称.保留一个未命名的类别会导致它变成一个不同的野兽:一个现在提供编译时方法实施强制并允许你添加ivars.我现在理解每个基础的一般原理:类别通常用于在运行时向任何类添加方法,而类扩展通常用于强制私有API实现并添加ivars.我接受这个.
但有些小事让我感到困惑.首先,在高层:为什么要这样区别?这些概念看起来像是类似的想法,无法决定它们是相同的还是不同的概念.如果它们是相同的,我希望使用没有名称的类别和具有命名类别(它们不是)的类别可以完全相同.如果它们不同,(它们是)我会期望两者之间存在更大的语法差异.看起来很奇怪,"哦,顺便说一句,要实现一个类扩展,只需写一个类别,但忽略名称.它神奇地改变了."
第二,关于编译时强制的主题:如果你不能在命名类别中添加属性,为什么这样做会说服编译器你就是这么做的?为了澄清,我将用我的例子来说明.我可以在头文件中声明一个readonly属性:
// .h
@interface MyClass : NSObject
@property (readonly, copy) NSString* myString;
@end
Run Code Online (Sandbox Code Playgroud)
现在,我想转到实现文件并给自己私有的readwrite访问属性.如果我做得正确:
// .m
@interface MyClass ()
@property (readwrite, copy) NSString* myString;
@end
Run Code Online (Sandbox Code Playgroud)
当我不合成时,我会收到警告,当我这样做时,我可以设置属性,一切都很好.但是,令人沮丧的是,如果我碰巧有点误导了类别和类扩展之间的区别,我尝试:
// .m
@interface MyClass (private)
@property (readwrite, copy) NSString* myString;
@end
Run Code Online (Sandbox Code Playgroud)
编译器完全安心认为属性是readwrite.我没有得到任何警告,甚至没有好的编译错误"对象无法设置 - 无论是readonly属性还是没有找到setter",在设置myString时我都没有在类别中声明readwrite属性.我只是在运行时获得"不响应选择器"异常.如果(命名)类别不支持添加ivars和属性,那么要求编译器按相同规则播放是否太过分了?我错过了一些宏伟的设计理念吗?
objective-c ×1