单例模式 & Init(allocWithZone:)

一、Init

在分配内存后,子类通过该实例方法,实例化类的新对象。

1、init消息需要在同一行复合alloc方法使用,如SomeClass *obj = [[SomeClass alloc] init];

2、方法返回值可能为nil,比如在没有相机的设备上新建相机对象就会返回nil。为保证你的创建过程的容错性,因此规范的写法如下:

- (instancetype)init {
    if (self = [super init]) {
        // Initialize self
    }
    return self;
}

3、alloc和allocWithZone:方法,实例化一个isa对象变量,isa指向描述类的数据结构,内存中对象的其它变量初始化为0。alloc调用allocWithZone:方法,方法参数memory zones已不再使用。

在该方法后,必须调用init方法,完成对象初始化过程。

4、调用init方法前,对象指针不可用称为悬挂指针。调用init后,对象地址会发生改变,对象所在内存空间可以使用。

二、单例模式

单例提供全局可访问且共享的对象实例。通过自定义单例构造方法的方式,提供统一获取贯穿app的资源和服务,例如音频播放声音、网络管理对象发起HTTP请求。

在OC中,你通过dispatch_once方法包裹实例化对象方法,以确保创建唯一的单例对象。在app的生命周期内,dispatch_once中的block有且仅执行一次。

单例对象工厂方法如下:

static SomeClass *sharedInstance = nil; // 静态变量

+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[SomeClass alloc] init];
    });
    return _sharedInstance;
}  

三、单例问题

问题:如果不通过sharedInstance构造实例对象,而通过init,不就违反单例模式的设计了吗?

解决方案:由于init方法调用前,必定调用alloc和allocWithZone:方法,且alloc调用allocWithZone:方法,所以重写allocWithZone:方法,就可以保证不管通过什么方式创建的实例,都是同一个。

新增代码如下:

+(instancetype)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    return instance;
}

四、最后说明

可以通过重写description方法,来确认是否是同一个对象,代码如下:

-(NSString *)description{
    return [NSString stringWithFormat:@"< %p > name = %@, myObj = %p, arry = %p, mutable = %p", self, self.name, self.myObj, self.arry self.mutableArr];

}
原文地址:https://www.cnblogs.com/zhouyi-ios/p/5066465.html