在 Objective-C 类别中初始化一个静态变量

Posted

技术标签:

【中文标题】在 Objective-C 类别中初始化一个静态变量【英文标题】:Initialising a static variable in Objective-C category 【发布时间】:2011-01-04 00:33:00 【问题描述】:

我试图创建一个静态变量来存储图像字典。不幸的是,我能找到的最好的初始化方法是检查每个使用该变量的函数。由于我在一个类别中创建这个变量,我不能只在初始化程序中初始化它。有没有更简洁的方法来初始化 navigationBarImages?

static NSMutableDictionary *navigationBarImages = NULL;

@implementation UINavigationBar(CustomImage)
//Overrider to draw a custom image
- (void)drawRect:(CGRect)rect

    if(navigationBarImages==NULL)
        navigationBarImages=[[NSMutableDictionary alloc] init];
    
    NSString *imageName=[navigationBarImages objectForKey:self];
    if (imageName==nil) 
        imageName=@"header_bg.png";
    
    UIImage *image = [UIImage imageNamed: imageName];
    [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];


//Allow the setting of an image for the navigation bar
- (void)setImage:(UIImage*)image

    if(navigationBarImages==NULL)
        navigationBarImages=[[NSMutableDictionary alloc] init];
    
    [navigationBarImages setObject:image forKey:self];

@end

【问题讨论】:

我不鼓励用 NULL 初始化 Obj-c 对象,你应该用 nil 初始化它! @DanielSanchez,虽然我同意,但实际上,nil 只是将 NULL 转换为对象。 @FireLizzard nil 相当于指向对象的指针的 N​​ULL。 nil 和 NULL 不能互换。 NULL 的定义与 nil 不同。 nil 定义为 (id)0。 NULL 不是。 nshipster.com/nil 【参考方案1】:
__attribute__((constructor))
static void initialize_navigationBarImages() 
  navigationBarImages = [[NSMutableDictionary alloc] init];


__attribute__((destructor))
static void destroy_navigationBarImages() 
  [navigationBarImages release];

这些函数会在程序启动和结束时自动调用。

【讨论】:

我比+initializer更喜欢这个。 我不明白.. 这是哪里?就这么写?应该发生什么?【参考方案2】:

考虑这种方法,

static NSMutableDictionary *navigationBarImages()

    static NSMutableDictionary *dict = NULL;
    if(dict == NULL)
    
        dict = [[NSMutableDictionary alloc] init];
    
    return [[dict retain] autorelease];

然后,每当您使用 navigationBarImages 时,将其替换为 navigationBarImages(),如下所示:

改变

NSString *imageName=[navigationBarImages objectForKey:self];

NSString *imageName=[navigationBarImages() objectForKey:self];

如果函数调用开销困扰您,可以使用临时变量来捕获 navigationBarImages() 的返回,

NSMutableDictionary *dict = navigationBarImages();
[dict doSomething];
[dict doSomething];

缺点是一旦你调用了navigationBarImages(),NSMutableDictionary的实例就被创建了,那么直到程序结束它才会有机会释放。

【讨论】:

这个生命周期对于静态变量来说是典型的,所以我不会认为它本身是一个缺点。 这不会像使用dispatch_once 来初始化字典那样线程安全。代码会更好用:static dispatch_once_t once; static NSMutableDictionary *dict = nil; dispatch_once(&once, ^ dict = [[NSMutableDictionary alloc] init]; ); return dict;【参考方案3】:

您只需要在使用之前在已知点设置一次静态。例如,您可以设置一个 NSApplication 委托并让它在 -applicationDidFinishLaunching: 中完成工作

【讨论】:

我无法在另一个文件中访问它 - 静态变量只在类的范围内声明 只定义一个独立的设置函数。 不。那是行不通的。 Something 必须调用 setup 函数。 但这就是我的意思,比尔。提供一个setup函数,在头文件中通告,从-applicationDidFinishLaunching:调用 (“独立”是指“普通的 C 函数”)【参考方案4】:

一种选择是使用 C++。将文件的扩展名更改为 .mm 并将 = NULL 替换为 [[NSMutableDictionary alloc] init]

【讨论】:

【参考方案5】:

您可以在您的类别的 .m 文件中添加 +initialize — 您只需要确保您没有破坏现有的实现,否则您会得到普遍的错误。 (显然,如果您编写代码,您可以确定这一点,但对于第三方代码,这可能不是最好的方法。)

【讨论】:

...您将如何确定?坏主意。 您当然可以确定您是否编写了该类,或者您可以使用运行时自省方法或类似方法。我通常只在我自己的源代码中使用 +initialize,我只是把它作为一个选项放在那里。通常,它最好的选择,只是没有类别。 如果你写了这个类,你不需要把+initialize放在一个类别中。如果你没有编写它,你就不能相信你不会在库的未来版本中踩到它。将 +initialize 放在一个类别中风险大于其价值。 在大多数情况下,这可能比它的价值更大、更麻烦,但我不同意你从不需要/想要将+initialize 放在一个类别中。例如,我可能已经编写了库/框架代码,但只想要一个客户端项目中的静态变量和初始化。我只是想提供一个在某些情况下合适的替代方案——让我们不要对它好战...... :-)

以上是关于在 Objective-C 类别中初始化一个静态变量的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C 框架中的 Swift 类别在运行时无法识别

在 Swift 3 的值类型中访问 Objective-C 类别的属性(关联参考)

在 Swift 3 的值类型中访问 Objective-C 类别的属性(关联参考)

在 Objective-C 中使用类别的私有方法:从子类调用 super

如何在 Swift 中调用 Objective-C 类别方法

在 Swift 中使用 Objective-C 类别的正确方法是啥?