1. 以“类族模式”隐藏实现的细节
在我们平时的代码构建中,经常会用到继承。在类的继承关系以及方法的定义上有很多需要注意。
以下几点需要引起注意:
- 在设计业务逻辑的时候,一定要考虑继承类的分层设计,将方法的实现和业务相对应,以降低类与类之间的耦合性。
- 在系统的框架中有很多的类族,它们是类组中的抽象的基类。在使用该类族创建对象的时候会先分配一个继承自该类的子类,然后由该子类实例化想要的实力对象,举例说明;
id test = [[NSArray alloc]init];
if ([test class] == [NSArray class])
{
}
这段代码的if 判断条件永远也不会成立,因为[test class]
是[NSArray class]
的父类,下面用代码证明:
MyArray * arr22 = (MyArray *)@[@1,@2,@3];
MyArray1 * arr11 = (MyArray1 *)@[@1,@2];
NSLog(@"%@",[arr22 class]);
NSLog(@"%@",[arr11 class]);
Father * father = [[Father alloc]init];
Son * son = [[Son alloc]init];
BOOL res = [father isKindOfClass:[NSObject class]];
BOOL res1 = [father isKindOfClass:[Father class]];
NSLog(@"res---%d",res);
NSLog(@"res1---%d",res1);
BOOL res2 = [son isKindOfClass:[NSObject class]];
BOOL res3 = [son isKindOfClass:[Father class]];
NSLog(@"res2---%d",res2);
NSLog(@"res3---%d",res3);
BOOL res4 = [father isMemberOfClass:[NSObject class]];
BOOL res5 = [father isMemberOfClass:[Father class]];
NSLog(@"res4---%d",res4);
NSLog(@"res5---%d",res5);
BOOL res6 = [son isMemberOfClass:[NSObject class]];
BOOL res7 = [son isMemberOfClass:[Father class]];
NSLog(@"res6---%d",res6);
NSLog(@"res7---%d",res7);
id temp = [[Son alloc]init];
BOOL ress = ([Son class] == [temp class]);
NSLog(@"%d",ress);
id arr1 = [[NSArray alloc] init];
BOOL ress1 = ([arr1 class] == [NSArray class]);
NSLog(@"%d",ress1);
NSLog(@"%@",[NSArray class]);
NSLog(@"%@",[arr1 class]);
BOOL ress2 = [arr1 isMemberOfClass:[NSArray class]];
BOOL ress3 = [arr1 isKindOfClass:[NSArray class]];
NSLog(@"%d",ress2);//0
NSLog(@"%d",ress3);//1
NSArray * arr2 = [[NSArray alloc]init];
BOOL ress4 = ([arr2 class] == [NSArray class]);
NSLog(@"%d",ress4);
NSLog(@"%@",[arr2 class]);
打印结果:
打印结果从打印结果我们可以清楚地看出,类之间的继承关系。
- 我们在重写系统类的时候一定要注意查阅官方文档,看哪些方法是必须要实现的。例如当我们重写
NSArray
的时候,就必须要重写count
和objectAtIndex:
,重写其它系统类的时候也要注意查阅官方文档。
2.在类中只用关联对象存放自定义的数据
当我们在开发中遇到在某些类中,添加属性比较困难的时候,就可以使用关联对象。
关联对象是属于运行时机制里面的。
下面我们来看一下基本用法:
- 设定关联对象
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
id object:当前对象
const void *key:所关联对象所对应的键
id value:要关联的对象
objc_AssociationPolicy policy:关联对象存储策略
- 获取关联对象
id objc_getAssociatedObject(id object, const void *key)
id object:当前对象
const void *key:所关联对象所对应的键
- 移除指定对象的全部关联对象
void objc_removeAssociatedObjects(id object)
下面看一段代码:
static void *key = @"xiao";
- (void)viewDidLoad {
[super viewDidLoad];
void (^block)(NSInteger) = ^(NSInteger num){
NSLog(@"%ld",(long)num);
};
objc_setAssociatedObject(self, key, block, OBJC_ASSOCIATION_COPY);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self test1];
}
- (void)test1{
void (^block)(NSInteger) = objc_getAssociatedObject(self, key);
block(90);
}
这样我们就给当前的控制器添加了一个block属性,其实我们完全可以用属性去包装block,当我们无法给当前的抽象类添加属性的时候,我们其实就没有必要再创建该抽象类的实例,然后再去继承属性,这样会增加代码量,这样关联对象,可以节省代码量(在不方便创建属性的情况下),同时也可以优化代码结构。
注:使用这种方式其实也是有一定的弊端的,首先你关联的对象,内部银土其他参数的时候,比如引用block,很容易发生循环引用的现象,而我们又很难去发现,所以不是在不得已的情况下,尽量不要使用这种方式。
网友评论