一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
第一个注意事项
init会调用initWithframe:CGRectZero,所以使用重写initWithframe就行了
第二个注意事项:不要在init和dealloc中使用self.property
在init中,进行初始化首选会调用 self = [super init](注意这里只是子类调用了父类的init方法,并不是把父类返回给子类的self,self是对象指针,super只是个标识符,跟self不是一种类型的东东,这里self是子类的对象指针,哪怕调用到了父类的init方法,父类init中的self还是指向子类的对象,因此在父类中调用到了子类的重载方法); 即子类先调用父类init方法,如果父类在init中使用了 self.property,一旦子类重写了 self.property的该方法,那么由于多态父类中调用的其实是子类的accessor方法(即self.propert方法),而此时只是在进行父类初始化,子类初始化还未完成,调用子类的accessor可能会造成崩溃。现实中更多的是某个方法被少调用一次,出现逻辑错误。
在销毁子类对象时,首先是调用子类的dealloc,最后调用父类的dealloc(这与init相反,在ARC中不需要我们手动调用[super dealloc], 系统会在子类dealloc的最后自动调用父类dealloc)。如果在父类dealloc调用了accessor且该accessor被子类重写,就会调用到子类断点accessor。但此时子类已经释放,就会出现错误甚至崩溃。
我们来看下代码: 父类
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_name = @"222";
NSLog(@"parent init:%@", self.name);
}
return self;
}
- (void)setName:(NSString *)name {
_name = name;
NSLog(@"parent set:%@", self.name);
}
- (void)dealloc {
NSLog(@"parent dealloc:%@", self.name);
}
子类
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_arr = [[NSMutableArray alloc] initWithObjects:@"arr1", @"arr2", nil];
NSLog(@"child init:%@", self.name);
self.name = @"111";
}
return self;
}
- (void)setName:(NSString *)name {
[super setName:name];
NSLog(@"child set:%@", self.name);
NSMutableArray *arr = [[NSMutableArray alloc]init];
[arr addObject:self.arr];
NSLog(@"%@", arr);
NSLog(@"arr:%@", self.arr);
}
- (void)dealloc {
NSLog(@"child dealloc:%@", self.name);
}
当我们使用子类的时候,就会崩溃在子类的set方法。所以initWithframe里初始化应该使用下划线实例变量。