昨天看了iTunes上standford 公开课视频《Developing iOS 7 Apps for iPhone and iPad》,给自己打了打基础。
看完了一会就觉得自己以前的写法很“垃圾”,所以现在动手改了改风格,先改的是property的getter和setter。
视频里说在getter里做初始化比init里要好很多,结合我的实践,在我的单例中,我一直对没地方初始化property而耿耿于怀。
比如在单例中:
@implementation DDKStageArray
NSManagedObjectContext *context=nil;
+(DDKEquipArray *)arrayInstance{
static dispatch_once_t pred = 0;
dispatch_once(&pred, ^{
singleton = [[self alloc]init]; // 跳到allocWithZone:
});
DDKAppDelegate *delegate = [UIApplication sharedApplication].delegate;
context = delegate.managedObjectContext;
return singleton;
}
. . .
@end如果定义成一个@property (weak, nonatomic)NSManagedObjectContext *context;
然后尝试在arrayInstance中给他init,会发现根本不允许在那里放置property。退而求其次,我可以把property放在-(void)init方法里面,arrayInstance自己会调用-(void)init。后来为了解决创建多实例的问题,又搞了个+ (id)allocWithZone:(struct _NSZone *)zone方法,结果-(void)init方法不会被调用了。
// 防止[[DDKStageArray alloc]init]产生多实例
+ (id)allocWithZone:(struct _NSZone *)zone{
@synchronized(self){
count++;
singleton = [super allocWithZone:zone];
return singleton;
}
return nil;
}
这种多线程单例是我抄的,为啥要搞个计数器现在还不明白。总之property没法好好初始化。我就搞了个类静态量 NSManagedObjectContext *context= nil ; 这下类方法就可以对他初始化了。可是这玩意因为是单例,所以如果有多个单例的话,类静态量是不允许重名的,否则符号冲突。
列了一大堆现象,问题两个(上文标红),现在理一理头绪,我到底想干啥?给单例加上property,就这么简单。
然后我觉得getter很不错!
@interface BBUEquipArray ()
@property (weak, nonatomic)NSManagedObjectContext *equipContext;
@property (weak, nonatomic)NSEntityDescription *entityDescription;
@end
@implementation DDKEquipArray
+(DDKEquipArray *)arrayInstance{
static dispatch_once_t pred = 0;
dispatch_once(&pred, ^{
singleton = [[self alloc]init]; // 跳到allocWithZone:
});
return singleton;
}
不要的全砍掉,代码清爽很多写上getter,只写一个,另一个就不贴了。
#pragma mark - Getter
- (NSManagedObjectContext *)equipContext
{
if (!_equipContext) {
DDKAppDelegate *delegate = [UIApplication sharedApplication].delegate;
_equipContext = delegate.managedObjectContext;
}
return _equipContext;
}
编译通过,好像不错的样子?理论上调用equipContext的时候,我getter都会给你初始化。
跑一跑,直接throw exception。。。exception不贴了,太丢人。问题代码在这里:
DDKCoreDataEquip *event = [NSEntityDescription insertNewObjectForEntityForName:@"DDKCoreDataEquip" inManagedObjectContext:_equipContext];
BBUCoreDataEquip *event = [NSEntityDescription insertNewObjectForEntityForName:@"BBUCoreDataEquip" inManagedObjectContext:self.equipContext];
该省的不能省了,这里必须让他调用一次getter把他初始化咯,改成 self . equipContext 目标达成!
【结论】
在使用getter做初始化的时候,特别小心那些被当做参数传递的属性。务必使用self.property来保证getter的调用。