IOS 单例模式

作者: 桃花流水鳜鱼肥 | 来源:发表于2016-05-13 10:38 被阅读266次

    在我认为单例最大的优点就是:通过单例方式访问的实例,都是同一个。

    这个优点也是我在蓝牙音乐盒项目中使用单例模式实现外设控制类和AVFoundation类的原因。
    你们想,假设我在a,b,c页面都会调用到_player,那么我再a页面点击播放、上一首、下一首等等操作后,怎么让b,c页面知道并同步呢?我一开始使用的是通知。可是我试了后发现,最好的还是单例。
    单例模式下的无论在那个类访问_player实例,它的状态都是最新的,也就是a点了播放,那么我在b,c页面访问_play实例,就可以知道它的状态是播放的,不需要通知。


    创建单例:

    .h
    
    + (CustomObject *)share;
    
    .m
    + (CustomObject *)share{
        static CustomObject *instance = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[CustomObject alloc] init];
        });
        return instance;
    }
    

    代码解释:链接
    dispatch_once主要根据onceToken的值来决定是否执行block里的方法,如果onceToken==0,线程执行block里的方法,当onceToken==-1,线程不执行block。当onceToken为其他值时,线程被阻塞,等待onceToken值改变。
    当线程首先调用instance,某一线程要执行block中的代码时,首先需要改变onceToken的值,再去执行block中的代码。这里onceToken的值变为了140734731430192。这样当其他线程再获取onceToken的值时,值已经变为140734731430192。其他线程被阻塞。当block线程执行完block之后。onceToken变为-1。其他线程不再阻塞,跳过block。下次再调用shareInstance时,block已经为-1。直接跳过block。这样dispatch_once在首次调用时同步阻塞线程,生成单例之后,不再阻塞线程。dispatch_once是创建单例的最优方案


    通过下面代码可以理解单例的优点:

    viewController.m
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        CustomObject *cv = [CustomObject share];
        cv.tempString = @"123";
    }
    
    
    SecondView.m
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        CustomObject *cv = [CustomObject share];
        NSLog(@"%@",cv.tempString);
    }
    
    CocoaPodsDemo[87052:9724995] 123
    

    可以看到:
    1.获取CustomObject对象的实例很方便。
    2.在两个类里的实例变量实际上是同一个,没有重新alloc空间,节省了内存。当然,通过单例创建的实例常驻内存,所以资源开销就见仁见智。
    3.获取实例的状态非常容易。因为是同一个实例,当我在第一个类里改变了tempString状态为@"123",我再第二个类想要获取tempString的状态马上就变成了@"123"

    第三条原因让单例使用起来非常爽,也是我认为单例最大的优点,这我一开始就说过了。


    注意:
    访问单例类一定要通过定义的单例方法+ (CustomObject *)share。如果依旧使用alloc、init或者new就会发生下面的情况

    viewController.h
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        CustomObject *cv = [CustomObject share];
        cv.tempString = @"123";
    }
    
    SecondView.h
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        CustomObject *cv = [[CustomObject alloc] init];
        NSLog(@"%@",cv.tempString);
    }
    
    CocoaPodsDemo[87052:9724995] (null)
    

    解释:
    上面两个类里获得的实例其实不是同一个,因为通过单例方式获得实例本来就是通过封锁alloc init方法实现的,但是我再SecondView重新使用了alloc/init方法实例化了。

    那么如何避免呢?下面是我想的一种方法,希望指点:

    
    
    - (instancetype)init{
        return [CustomObject share];
    }
    
    - (instancetype)initHidden{
        self = [super init];
        if (self) {
            
        }
        return self;
    }
    
    + (CustomObject *)share{
        static CustomObject *instance = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[CustomObject alloc] initHidden];
        });
        return instance;
    }
    

    相关文章

      网友评论

      本文标题:IOS 单例模式

      本文链接:https://www.haomeiwen.com/subject/igourttx.html