iOS 单例模式

前言:

单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

要点:

显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

一、单例的优缺点

1.单例的优点(主要优点)

实例控制:Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例
因为其上面的特点,对于项目中的个别场景的传值,存储状态等等更加方便

2.单例的缺点(主要缺点)
单例实例一旦创建,对象指针是保存在静态区的,那么在堆区分配空间只有在应用程序终止后才会被释放
单例不能继承

二、单例的几种写法

OC

1.静态指针方式(单线程模式单例)

///.h
@interface SingleExample : NSObject

+ (instancetype)sharedInstance;

@property (nonatomic, copy) NSString *order_id;

@end

///.m
#import "SingleExample.h"

@implementation SingleExample

+ (instancetype)sharedInstance{
    static SingleExample *myInstance = nil;
    if(myInstance == nil){
        myInstance = [[SingleExample alloc]init];
    }
    return myInstance;
}
@end

///测试
SingleExample *model = [SingleExample sharedInstance];
model.order_id = @"0001";
NSLog(@"------%@-------",model.order_id)

2.多线程加锁单例

/**
dispatch_once 无论使用多线程还是单线程,都只执行一次
GCD创建单例不仅可以解决多条线程的线程安全问题,也能保证性能,是官方荐的方式。
dispatch_once主要是根据onceToken的值来决定怎么去执行代码。
当onceToken = 0时,线程执行dispatch_once的block中代码
当onceToken =- 1时,线程跳过dispatch_once的block中代码不执行
当onceToken为其他值时,线程被阻塞,等待onceToken值改变

dispatch_once执行的流程
当线程调用shareInstance,此时onceToken = 0,调用block中的代码。此onceToken的值变为72。
当其他线程再调用shareInstance方法时,onceToken的值已经是72了,线程阻塞。
当block线程执行完block之后,onceToken变为-1.其他线程不再阻塞,跳过block。
下次再调用shareInstance时,block已经为-1.直接跳过block。
 */

///.h
@interface SingleExample : NSObject

+ (SingleExample *)shareInstance;

@property (nonatomic, copy) NSString *order_id;

@end

@implementation ShareManage

///.m
+ (SingleExample *) shareInstance {
    
    static SingleExample * single = nil;
    static dispatch_once_t onceToken ;
    
    NSLog(@"onceToken开始::::::%ld",onceToken);
    dispatch_once(&onceToken, ^{
        
        shareInstance =[[SingleExample alloc]init];
        NSLog(@"onceToken执行中::::::%ld",onceToken);
       // [NSThread sleepForTimeInterval:10];
        
    }) ;
    NSLog(@"onceToken执行结束::::::%ld",onceToken);
    return shareInstance;
    
}

@end

///测试
SingleExample *model = [SingleExample shareInstance];
model.order_id= @"0002";
NSLog(@"------%@-------",model.order_id)

3.单例的健壮性

///.h
@interface ShareManage : NSObject

+ (instancetype)shareManager;

@property (nonatomic, strong) NSString *NAME;

@end

///.m
#import "ShareManage.h"

@interface ShareManage()<NSCopying,NSMutableCopying>

@end

static ShareManage *manager = nil;

@implementation ShareManage

+ (instancetype)shareManager{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc]init];
        //不是使用alloc方法,而是调用[[super allocWithZone:NULL] init]
        //已经重载allocWithZone基本的对象分配方法,所以要借用父类(NSObject)的功能来帮助出处理底层内存分配的杂物
    });
    return manager;
}

///用alloc返回也是唯一实例
+ (id)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [super allocWithZone:zone];
    });
    return manager;
}

///对对象使用copy也是返回唯一实例
- (nonnull id)copyWithZone:(nullable NSZone *)zone {
    return manager;
}

 ///对对象使用mutablecopy也是返回唯一实例
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
    return manager;
}
/*
 
 当static关键字修饰局部变量时,只会初始化一次且在程序中只有一份内存
 allocWithZone mutablecopyWithZone 这个类遵守<NSCopying,NSMutableCopying>协议
 如果_instance = [self alloc] init];创建的话,
 将会和-(id) allocWithZone:(struct _NSZone *)zone产生死锁。
 dispatch_once中的onceToken线程被阻塞,等待onceToken值改变。
 当用alloc创建对象、以及对对象进行copy mutableCopy也是返回唯一实例
 
 */
@end

///测试
ShareManage *manage = [ShareManage shareManager];
manage.NAME = @"测试单例,输出名称";
NSLog(@"------%@-------",manage.NAME)

Swift

1.最简单的 全局变量方法(“单行单例”方法) 通过 static 关键字创建

class SingletonOne {
    static let sharedInstance = SingletonOne()
    private init() {} 
    //切记私有化初始化方法,防止外部通过init直接创建实例。
}

2.严格单例模式 继承自 NSObject

class SingletonClass: NSObject {

    static let shared = SingletonClass()
    
    // Make sure the class has only one instance
    // Should not init or copy outside
    private override init() {}
    
    override func copy() -> Any {
        return self // SingletonClass.shared
    }
    
    override func mutableCopy() -> Any {
        return self // SingletonClass.shared
    }
    
    // Optional
    func reset() {
        // Reset all properties to default value
    }
}
/**
静态属性 shared 持有唯一的实例,对外公开。

重载 init() 方法,使其对外不可见,不可以在外部调用,防止在外部创建实例。

重载 copy()、mutableCopy() 方法,返回 self,防止在外部复制实例。这里也可以返回 SingletonClass.shared,效果是一样的,因为只有一个实例。只有 shared 能调用 copy()、mutableCopy() 方法,那么 self 就是 shared。写 self,代码比较简洁。

单例一旦创建,一直持有,不能手动销毁,但可以重置数据。如果需要的话,可以添加一个重置数据的方法 reset()。例如,当前用户退出登录,需要把当前用户实例的所有属性重置为默认值,防止数据错误。

*/

3.不继承自 NSObject

class SingletonClass2 {
    
    static let shared = SingletonClass2()
    
    // Make sure the class has only one instance
    // Should not init outside
    private init() {}
    
    // Optional
    func reset() {
        // Reset all properties to default value
    }
}
///不继承自 NSObject 的类没有 copy()、mutableCopy() 方法,不需要重载。

4.方法内定义静态常量

class SingleFour :NSObject{
 
    var tValue = "df"

    static var sharedInstance : SingleFour {
        struct Static {
            static let instance : SingleFour = SingleFour()
        }
        return Static.instance
    }
}

或

class ShareManage: NSObject {

    var tValue = "df"

    class var shareOnce : ShareManage {
        struct tOnce {
            static let instance = ShareManage()
        }
        return tOnce.instance
    }

}

///测试
ShareManage.sharedInstance.tValue = "1001"
print("123456789" + ShareManage.sharedInstance.tValue)

5.全局的常量

let single = SingleSix()
 
class SingleSix {
 
    var tValue = "df"
    class var sharedInstance : SingleSix {
        return single
    }
}

///测试
ShareManage.sharedInstance.tValue = "1001"
print("123456789" + ShareManage.sharedInstance.tValue)

6.使用GCD技术实现的单例模式 使用dispatch_once可以保证其中的代码只执行一次

/**
class SwiftSingleton {
    class var shared: SwiftSingleton {
        dispatch_once(&Inner.token) {
            Inner.instance = SwiftSingleton()
        }
        return Inner.instance!
    }
    struct Inner {
        static var instance: SwiftSingleton?
        static var token: dispatch_once_t = 0
    }
}
///swift3.0之后 dispatch_once_t、dispatch_once不可用。修改为下面代码
*/

var sharedInstance : ShareManage  {
    
    struct Inner {

        static var instance: ShareManage?
        static var token = {0}()
    }
    
    _ = Inner.token
    
    return Inner.instance!
 
}


class ShareManage {
    static let sharedInstance: ShareManage = { ShareManage() }()
    
    var shareName = ""
}

///测试
ShareManage.sharedInstance.shareName = "100"
print("123456789" + ShareManage.sharedInstance.shareName)

三、系统中的单例

UIApplication(应用程序实例)
NSNotificationCenter(消息中心):
NSFileManager(文件管理):
NSUserDefaults(应用程序设置):
NSURLCache(请求缓存):
NSHTTPCookieStorage(应用程序cookies池):

END

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 简介: 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统...
    RunnerFL阅读 3,813评论 0 0
  • 本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗...
    水中的蓝天阅读 5,033评论 0 3
  • IOS单例模式(Singleton)单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例...
    Living_元宝儿阅读 5,086评论 1 6
  • 单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称...
    Lee坚武阅读 4,795评论 0 49
  • 单例模式大概是设计模式种较简单的一种设计模式。但在实际的开发过程中仍然存在一些坑。所以本文总结了下iOS中的单例模...
    CrazyItCoder阅读 5,120评论 0 4