我正在使用标准的现代单例类,其中包含一个包含CTFontRef的单例,如下所示:
@interface MySingleton : NSObject {
CTFontRef paintingFont;
}
@property (readonly) CTFontRef paintingFont;
@end
@implementation MySingleton
+ (MySingleton*)sharedInstance
{
static dispatch_once_t once;
static MySingleton *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
//NB
sharedInstance->paintingFont =
CTFontCreateWithName(CFSTR("Helvetica"), 80.0, nil);
});
return sharedInstance;
}
@end
然后我在其他地方打电话给[[MySingleton sharedinstance] paintingFont]
。
然而,此调用返回nil
,直到我在paintingFont
之前插入下划线,如下所示:
sharedInstance->_paintingFont =
CTFontCreateWithName(CFSTR("Helvetica"), 80.0, nil);
这是为什么?编译器不应该要求我包含下划线吗?如果不是早期版本的目的是什么?这个下划线在哪里出现?我从来没有用下划线声明属性,我只是在调试器窗口中看到它们看似随机插入到变量名中。
答案 0 :(得分:3)
自Xcode 4.4起,当您声明@property
时,编译器将自动为您创建一个ivar,并为@synthesize
创建访问器方法。默认的ivar是带有下划线的ivar。
使用->
语法直接访问ivars而不是属性。因此,在您的sharedInstance
方法中,您可以设置自己的ivar(不带下划线)。但是,当您稍后尝试访问它时,您使用[ ]
将使用自动合成的getter方法来访问您的属性(以及使用下划线自动生成的ivar)。
您应该使用.
表示法而不是->
来访问该媒体资源。或者只使用自动生成的名为_paintingFont
的ivar。
您还可以通过添加以下代码在您的实现文件中创建属性readwrite。这将允许您在实现中使用点语法来设置属性,但仍然只为其他类保留它。
@interface MySingleton ()
@property (readwrite) CTFontRef paintingFont;
@end
如果您想要不同的ivar,可以使用@synthesize
覆盖它。在这两种情况下,您都不必再声明ivar了。
@implementation MySingleton
@synthesize paintingFont;
....
@end
答案 1 :(得分:2)
这是因为在声明属性paintFont时,Obj C编译器会创建一个实例变量_paintingFont。
通常,属性/变量的设置可以通过
完成sharedInstance->_paintingFont = ...
sharedInstance.paintingFont = ...
。这将调用生成的方法setPaintingFont,然后将其分配给实例变量。但是在这种情况下,属性是只读的,所以不能使用方法2.