单例模式 & 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]; }