静态类和单例的区别及相互转换

本文介绍了iOS开发中静态类和单例的使用场景及区别,提供了一个登录功能的实现案例,说明了如何从静态类转换为单例,以及单例在内存管理和继承上的优势。通过实例分析,帮助开发者理解并合理运用这两种设计模式。

相信不少iOS的开发者在读或者写不同的代码时经常能够遇到静态类和单例,基本上优秀的开源项目都将二者完美的切入到项目中。二者的使用优劣对比网上也是各有其说,比较老套我就不文字分析二者的区别了,笔者对此查询了相关资料和对比几个优秀的代码,得出以下结论:
1. 如果项目大量用到了同一个类的若干方法,那就将这个类改为单例,或者新建继承此类的单例,这样可以减少多次初始化该类的弊端。
2. 如果一些常用的方法多个项目都可以使用,可以形成一个静态类的集合,方便以后重用。
3. 只要你愿意,二者可以相互转换。

举个例子,拥有登录功能的项目,都要处理登录数据及逻辑,两个方法:

方法一:建一个登录数据处理类:LoginEngine

LoginEngine.h
@interface LoginEngine : NSObject
// 保存用户名
+ (void)saveName:(NSString *)name;
// 获取用户名
+ (NSString)name;
@end
LoginEngine.m
@implementation LoginEngine
+ (void)saveName:(NSString *)name {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:name forKey:@"name"];
    [userDefaults synchronize];
}
+(NSString *)name {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
return [userDefaults objectForKey:@"name"];
}
@end

然后静态类的调用就不多说,简单明了:
在登录成功的地方:

[LoginEngine saveName:@"张三"];

同时可以直接获取保存的用户名:

NSString *name = [LoginEngine name];

没错,这就是为什么那么多开发者喜欢用类方法的原因,调用简单。

方法二:用单例LoginEngine实现

网上一大堆对二者区别及优势的分析,不比想的那么复杂,初期阶段,你就想着如何理解它并合理使用它就行了。还是刚才的类LoginEngine,做稍微的改动:

LoginEngine.h
@interface LoginEngine : NSObject
// 构造 LoginEngine 单例
+ (instancetype)sharedInstance;
// 保存用户名
- (void)saveName:(NSString *)name;
// 获取用户名
- (NSString)name;
@end
LoginEngine.m
@implementation LoginEngine
+ (instancetype)sharedInstance {
    static LoginEngine *_loginEngine = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _loginEngine = [[self alloc] init];
    });
    return _loginEngine;
}
- (void)saveName:(NSString *)name {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:name forKey:@"name"];
    [userDefaults synchronize];
}
-(NSString *)name {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
return [userDefaults objectForKey:@"name"];
}
@end

在登录成功的地方:

[[LoginEngine sharedInstance] saveName:@"张三"];

同时可以直接获取保存的用户名:

NSString *name = [[LoginEngine sharedInstance] name];

这里需要着重说一下单例的实现,不是拷贝代码就行,要理解它,单例的本意就是让APP一个生命周期只运行一次该单例的初始化方法,方法有很多,比较常用和建议的就是用GCD的方法dispatch_once,这就保证了整个周期只会初始化一次,同时也带来了一定的弊端就是APP运行中一直会保留分配给这个单例的内存,不过相对于整个内存的消耗来说,这点点内存可以忽略不计。相对于每次调用静态类都要初始化来说,是一种更加优选的方法。

补充:

看到他们的区别了没有?单例就是把静态类的类方法改为实例化方法,然后添加只初始化一次的类方法,这样调用的时候先类方法来初始化,然后调用你需要的实例化方法!反之亦然。
当然笔者对单例的举例过于简单,读者需要知道的是单例相对于静态类来说,有一个巨大优势就是可以继承,上述的单例可以用新建一个继承于LoginEngine的类来实现,比如新建一个类:LoginEngineClient

LoginEngineClient.h
@interface LoginEngineClient : LoginEngine
+ (instancetype)sharedInstance;
@end
LoginEngineClient.m
@implementation LoginEngineClient
+ (instancetype)sharedInstance { 
static LoginEngine *_loginEngine = nil; 
static dispatch_once_t onceToken; 
dispatch_once(&onceToken, ^{ 
_loginEngine = [[self alloc] init]; 
}); 
return _loginEngine; 
} 
@end

这样调用的时候直接调用LoginEngineClient
在登录成功的地方:

[[LoginEngineClient sharedInstance] saveName:@"张三"];

同时可以直接获取保存的用户名:

NSString *name = [[LoginEngineClient sharedInstance] name];

这种优势在很多稍微大一点的项目中提现就比较明显,比如网络请求类,可以做一个单例,这样处理大量不同请求的时候就会更加的清晰,后期维护和管理就相对更加容易。
好了,多说无益,希望你能弄明白!我是Jonrencxr,我的个人组件头是CXR或CR。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值