Objective c 目标C中的单例属性访问

Objective c 目标C中的单例属性访问,objective-c,properties,singleton,Objective C,Properties,Singleton,我使用的是一个标准的、现代的singleton类,其中singleton持有一个CTFontRef,如下所示: @interface MySingleton : NSObject { CTFontRef paintingFont; } @property (readonly) CTFontRef paintingFont; @end @implementation MySingleton + (MySingleton*)sharedInstance { static d

我使用的是一个标准的、现代的singleton类,其中singleton持有一个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); 

为什么会这样?编译器不应该要求我包含下划线吗?如果不是,早期版本的目的是什么?这个下划线是从哪里来的?我从来没有用下划线来声明属性,我只是在调试器窗口中看到这些看似随机的插入到变量名中。

自Xcode 4.4以来,当您声明
@property
时,编译器将自动为您创建一个ivar并
@synthesis
访问器方法。默认ivar是带有下划线的ivar

使用
->
语法可以直接访问IVAR,而不是属性。因此,在
sharedInstance
方法中,您可以设置自己的ivar(不带下划线)。但是,当您稍后尝试访问它时,您将使用
[]
,它将使用自动合成的getter方法访问您的属性(以及自动生成的带下划线的ivar)

您应该使用
符号而不是
->
来访问属性。或者只需使用名为
\u paintingFont
的自动生成ivar即可

通过添加下面的代码,还可以在实现文件中使属性readwrite。这将允许您在实现中使用点语法来设置属性,但对于其他类仍然保持只读

@interface MySingleton ()
@property (readwrite) CTFontRef paintingFont;
@end
如果需要不同的ivar,可以使用
@synthesis
覆盖它。在这两种情况下,您不再需要声明ivar

@implementation MySingleton
@synthesize paintingFont;
....
@end

这是因为在声明属性paintingFont时,Obj C编译器会创建一个实例变量\u paintingFont

通常,属性/变量的设置可以通过

  • 解决方案中的实例
    sharedInstance->\u paintingFont=…
  • 使用属性和。表示法
    sharedInstance.paintingFont=…
    。这将调用生成的方法setPaintingFont,然后将其分配给实例变量

  • 但是,在这种情况下,属性是只读的,因此无法使用方法2。

    @Merk请参阅我的文章,内容是关于如何使属性仅在实现内部可读写,而不适用于其他实现。@DrummerB-是的,但我更喜欢ivar方式,a)该声明将被错误截取b)我查看接口以查看变量是什么,以及它们在实现中是否不同……我不确定a)是什么意思。你仍然可以使用ivar和properties,但是你也必须使用@synthesis。就像之前一样,整个自动化系统出现了。好的,我明白了。我还要补充几点意见。首先,如上所述,在两个“版本”下,无意中创建了两个不同的IVAR:paintingFont和_paintingFont。这是令人困惑和意外的,从您不查看接口文件就无法确定这一点的角度来看,我一开始觉得“可怕”。另一方面,程序员的错误可以完全局限于实现代码,因为显式的@synthesis语句可以解决这个问题。#2:更重要的是,首先是下划线业务的原因(这是我在最初的问题中试图了解的)它的引入是为了防止出现某种错误,在这种错误中,您无意中更改了setter函数之外的属性,因此错过了setter函数中可能发生的重要副作用。大呆子牧场的人在这里讨论了这个问题:是的,这可能是更好地区分IVAR和财产的原因。我刚才解释了下划线的来源,从技术上讲。顺便说一句,这从来不是一个真正的错误。这只是知道你在做什么的问题。在某些情况下,您可能希望直接访问ivar。