我看到建议在单例类而不是 AppDelegate 中定义全局数据(即 NSArray 或 NSDictionary)。
为什么是这样?
谢谢,弗兰克
AppDelegate 特定于您正在处理的项目。如果您决定启动您正在开发的应用程序的新版本,或者(更有可能)将其从 iOS 等移植到 Mac...
AppDelegate 将保持原样。
通过将这样的全局信息放入单例中,您可以创建一个独立于运行它的应用程序的类。
此外,您最好不要在 AppDelegate 中保留 App 特定的东西(如 applicationWillEnterBackground),并且不想用其他东西堵塞它。
如果您打算为代码创建单元测试,则应避免使用全局单例,因为它们会使您的代码更难测试。同样,根据我的经验,具有暴露的NSArray
或NSDictionary
用于此类值的代码很容易很快出现错误。
我发现一个有用的设计模式是实际创建一个配置或全局值对象,其中包含您想要的所有属性。通常,此类包装NSArray
or NSDictionary
,您可以从 plist 文件中加载它。该对象可以在 AppDelegate 中实例化,然后在您实例化视图控制器和其他对象时传递。这更易于测试,因为您可以轻松地在测试中模拟配置对象。
从 plist 文件加载此类配置对象时的外观示例:
界面:
@interface ConfigManager : NSObject {
}
@property (readonly) NSString* masterUser;
@property (readonly) UIImage* masterUserImage;
@end
然后在.m
@interface ConfigManager ()
@property (strong) NSDictionary* configDict;
@end
@implementation ConfigManager
-(id)init {
self = [super init];
if ( self ) {
NSString *pathStr = [[NSBundle mainBundle] pathForResource:@"AppConfig" ofType:@"plist"];
NSData *plistData = [NSData dataWithContentsOfFile:pathStr];
NSString *error = nil;
NSPropertyListFormat format;
self.configDict = (NSDictionary*)[NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if(nil == self.configDict || nil != error ) {
NSLog(@"%@",error);
return nil;
}
}
return self;
}
-(NSString*)masterUser {
return [self.configDict objectForKey:@"masterUser"];
}
-(UIImage*)masterUserImage {
NSString* imageName = [self.configDict objectForKey:@"masterUserImage"];
return [UIImage imageNamed:imageName];
}
当然,更改对象的属性以满足您的需要。这种方法的好处是,您可以在处理应用程序的全局配置所需的通用代码(例如加载图像)时实现。这有助于防止由于在整个代码库中一遍又一遍地复制相同的代码而导致的一类常见错误。
我不认为 Singeltons 是一个好的解决方案,我更喜欢将应用程序全局变量更好地保存在一个诚实的全局可访问类上,比如 AppDelegate。
18 年前,单例构造被认为是一种设计模式,但后来 Erich Gamma 意识到,将这种模式添加到他的“设计模式 - 可重用面向对象软件的元素”一书中是一个坏主意。
今天在像 java 这样的现代语言中,Singeltons 是邪恶的,因为一旦它们被初始化就无法删除它们,从而严重干扰了单元测试。所以至少在java中使用单例时它更有可能有一个糟糕的设计。老实说,如果你有一个全局对象,那么就这样处理它,不要将它隐藏在伪全局元素后面。
然而,Objective-C 没有虚拟机,因此单例可能不会影响单元测试,(我对此不确定)。
如果它们不影响单元测试,Singleton 有时使用起来很方便,例如 [NSFileManager defaultManager]。
但我不会将 NSArray 或 Dictionary 存储到单例中。
这样您就不会弄乱 AppDelegate。大多数 AppDelegate 就像全球数据的厨房水槽。一切都被扔在那里。使用单例(或者如果 ARC 则只是一个常规类)将您的真实全局数据与基本 AppDelegate 函数分开。