面试题
1. Category能否添加成员变量?如果可以,如何给Category添加成员变量?
- 不能直接给Category添加成员变量,但是可以间接实现Category有成员变量的效果
序言
- 给一个分类添加成员变量,实际上在类的实现方法中会添加一个带下划线的成员变量和set,get方法。
代码例子如下
@interface Person : NSObject
/** age*/
@property(nonatomic,assign)int age;
@end
@implementation Person {
int _age;
}
- (void)setAge:(int)age {
NSLog(@"setAge %d",age);
_age = age;
}
- (int)age {
NSLog(@"getAge %d",_age);
return _age;
}
@end
// 调用
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Person *person = [[Person alloc] init];
person.age = 100;
NSLog(@"age = %d",person.age);
}
return 0;
}
打印结果
思考:如何实现给分类“添加成员变量”?
默认情况下,因为分类底层结构的限制,不能添加成员变量到分类中。但可以通过关联对象来间接实现。
关联对象提供了以下API
添加关联对象
void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
- 获得关联对象
id objc_getAssociatedObject(id object, const void * key)
- 移除所有的关联对象
void objc_removeAssociatedObjects(id object)
key的常见用法
公用方法
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person1 = [[Person alloc] init];
person1.age = 5;
person1.name = @"person1";
person1.weight = 10;
Person *person2 = [[Person alloc] init];
person2.age = 50;
person2.name = @"person2";
person2.weight = 100;
NSLog(@"person1 - age is %d, name is %@, weight is %d", person1.age, person1.name, person1.weight);
NSLog(@"person2 - age is %d, name is %@, weight is %d", person2.age, person2.name, person2.weight);
}
return 0;
}
1.static void *MyKey = &MyKey;
objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(obj, MyKey);
代码如下:
@implementation Person (Test)
static const void *NameKey = &NameKey;
static const void *WeightKey = &WeightKey;
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
return objc_getAssociatedObject(self, NameKey);
}
- (void)setWeight:(int)weight {
objc_setAssociatedObject(self, WeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)weight {
return [objc_getAssociatedObject(self, WeightKey) intValue];
}
@end
2.static char MyKey;
objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, &MyKey)
代码如下
@implementation Person (Test)
static const char NameKey;
static const char WeightKey;
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, &NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
return objc_getAssociatedObject(self, &NameKey);
}
- (void)setWeight:(int)weight {
objc_setAssociatedObject(self, &WeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)weight {
return [objc_getAssociatedObject(self, &WeightKey) intValue];
}
@end
3.使用属性名作为key
objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(obj, @"property");
代码如下
@implementation Person (Test)
#define NameKey @"name"
#define WeightKey @"weight"
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
return objc_getAssociatedObject(self, NameKey);
}
- (void)setWeight:(int)weight {
objc_setAssociatedObject(self, WeightKey, @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)weight {
return [objc_getAssociatedObject(self, WeightKey) intValue];
}
@end
4.使用get方法的@selecor作为key
objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, @selector(getter))
代码如下
@implementation Person (Test)
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
// 隐式参数
// _cmd == @selector(name)
return objc_getAssociatedObject(self, _cmd);
}
- (void)setWeight:(int)weight {
objc_setAssociatedObject(self, @selector(weight), @(weight), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)weight {
// _cmd == @selector(weight)
return [objc_getAssociatedObject(self, _cmd) intValue];
}
@end
运行结果
关联对象的原理
实现关联对象技术的核心对象有
AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjcAssociation
objc4源码解读:objc-references.mm
本文参考:
路飞_Luck (https://www.jianshu.com/p/07f7b96bb03f)
以及借鉴MJ的教程视频
非常感谢.
项目连接地址 - iOS-associate-object