在 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 相当于指向对象的指针的 NULL。 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