我们说我有Tree.h
和Tree+Extensions.h
。我知道,如果我在Tree+Extensions.h
@property (nonatomic) NSString *color
中声明然后访问它,它就会崩溃,并且我可以使用objc_getAssociatedObject
和objc_setAssociatedObject
获得类似于该功能的内容
但是,我也看到了这一点:
// Tree+Extensions.h
@interface Tree (Extensions)
@property (nonatomic, readonly) NSString *color;
@end
// Tree+Extensions.m
@implementation Tree (Extensions)
- (NSString *)color {
return @"green";
}
@end
请注意,类别中的属性声明为readonly
,并且访问者方法返回了可以计算的内容。
我已经看到这段代码正常工作,但是想知道为什么这比仅仅在头文件中声明访问器方法更可取。
答案 0 :(得分:2)
让我们首先忽视这是一个类别并且只是谈论这个事实:
@interface Tree
@property (nonatomic, readonly) NSString *color;
@end
@implementation Tree
- (NSString *)color {
return @"green";
}
@end
据我了解,你的问题是:它与此之间的区别是什么:
@interface Tree
- (NSString *)color;
@end
@implementation Tree
- (NSString *)color {
return @"green";
}
@end
从完全实用的角度来看,没有的区别。人们确实习惯于声明属性,但实际上这两个声明具有完全相同的效果 - 即,在任何一种情况下,调用者(导入界面的任何人)都可以说[aTree color]
或aTree.color
,漠然。属性用法(aTree.color
)是方法调用[aTree color]
,反之亦然。即使只声明aTree.color
方法(不是属性),调用者也可以说 color
。这就是为什么,例如,说myArray.count
是合法的(和常见的),即使NSArray的count
未被声明为属性(它只是一种方法) 。并且,反之亦然,即使将[myViewController navigationController]
声明为属性,也可以说navigationController
是合法的(也是常见的)。
现在,在大多数情况下,声明属性的原因是为了让编译器合成相应的实例变量和相应的方法实现。但在这种情况下没有发生;没有实例变量,也没有要合成的getter(已经明确写过)。
因此,总而言之,让我们现在回到原来的问题并总结:您不能使用命名类别(如Tree (Extensions)
)将实例变量添加到现有类中。正如Apple says:
在类别接口中包含属性声明是有效的语法,但是不可能在类别中声明其他实例变量。这意味着编译器不会合成任何实例变量,也不会合成任何属性访问器方法。
嗯,在这种情况下,你不将一个实例变量添加到现有的类中,而你不试图合成" getter&#34 ;:readonly
属性声明由现有" getter"正如你所说的那样,计算整块布料的结果。因此,财产申报虽然毫无意义,但却是完全合法和有效的:它只是声明了" getter"方法
答案 1 :(得分:1)
使用您编写的代码,即使是在类中,您也无法调用setColor:
,当您想要返回没有由ivar支持的内容(例如计算)时,这可能是有意义的,并且你不想暴露给外面的世界。
答案:这是首选,因为您不需要从课堂外访问此属性。