【问题标题】:Initialising a static variable in Objective-C category在 Objective-C 类别中初始化一个静态变量
【发布时间】: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 不是。

标签: objective-c initialization categories static-variables


【解决方案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 放在一个类别中。例如,我可能已经编写了库/框架代码,但只想要一个客户端项目中的静态变量和初始化。我只是想提供一个在某些情况下合适的替代方案——让我们不要对它好战...... :-)
    猜你喜欢
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    • 1970-01-01
    • 2017-07-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-26
    • 2010-11-06
    相关资源
    最近更新 更多