
第一种:runtime.h里的
方法BOOL class_addProperty(Class cls,const char *name, const objc_property_attribute_t *attributes,unsigned int attributeCount) #include <objc/runtime.h> #import <Foundation/Foundation.h> @interface SomeClass : NSObject { NSString *_privateName}@end@implementation SomeClass- (id)init { self = [super init] if (self) _privateName = @"Steve" return self}@endNSString *nameGetter(id self, SEL _cmd) { Ivar ivar = class_getInstanceVariable([SomeClass class], "_privateName") return object_getIvar(self, ivar)} void nameSetter(id self, SEL _cmd, NSString *newName) { Ivar ivar = class_getInstanceVariable([SomeClass class], "_privateName") id oldName = object_getIvar(self, ivar) if (oldName != newName) object_setIvar(self, ivar, [newName copy])}int main(void) { @autoreleasepool {objc_property_attribute_t type = { "T", "@/"NSString/"" } objc_property_attribute_t ownership = { "C", "" }// C = copy objc_property_attribute_t backingivar = { "V", "_privateName" } objc_property_attribute_t attrs[] = { type, ownership, backingivar } class_addProperty([SomeClass class], "name", attrs, 3) class_addMethod([SomeClass class], @selector(name), (IMP)nameGetter, "@@:") class_addMethod([SomeClass class], @selector(setName:), (IMP)nameSetter, "v@:@") id o = [SomeClass new] NSLog(@"%@", [o name]) [o setName:@"Jobs"] NSLog(@"%@", [o name]) }}输出:SteveJobs 第二种:- (id)valueForUndefinedKey:(NSString *)key 第三种:static char const * const ObjectTagKey@implementation NSObject (ExampleCategoryWithProperty)@dynamic objectTag- (id)objectTag { return objc_getAssociatedObject(self, ObjectTagKey) } - (void)setObjectTag:(id)newObjectTag { objc_setAssociatedObject(self, ObjectTagKey, newObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC)}ios中利用类别给已有的类扩展方法是可以的,但是如果直接的添加属性是会报错的。利用runtime可以达到添加属性的目的。
1.先创建一个分类,以下以UIImage为例子。
2.增加需要的属性。
3.导入runtime框架,重写set方法和get方法。
//其中注意以下的参数是用来表示创建的属性的类型的
分类里添加属性,仅仅是生成了set和get方法的声明,并没有实现,需要我们自己写set和get的方法。
几种set,get方法实现案例
1.可以全局字典实现属性的存取
//声明全局的字典
NSMutableDictionary *_names_
//load方法实现字典
+ (void)load
{
_ names_ = [NSMutableDictionary dictionary]
}
//实现set方法
-(void)setName:(NSstring *)name
{
NSString *key = [NSString stringWithFormat:@"%p", self]
names_[MJKey] = name
}
//实现get方法
- (NSString *)name
{
// NSString *key = [NSString stringWithFormat:@"%p", self]
return names_[MJKey]
}
存在的问题:
全局变量无法释放
如果每个类在不不同的线程,同时访问set和get,如果不不加锁,可能会出现问题
2.关联对象
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC)
}
- (NSString *)name
{
// 隐式参数
// _cmd == @selector(name)
return objc_getAssociatedObject(self, _cmd)
}
第四个参数为关联策略,和变量的对应关系
第二个参数key
第一种方法利用字符串作为key,其中利用@"string",这样写的字符串是放在常量区的,无论哪里用到都是同一内存同一地址,但是这样写容易写错,且编译器没有提醒
更推荐第二种写法,不容易记错其中@selector(name),_cmd_,是函数的隐式参数
实现关联对象技术的核心对象
AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjectAssociation
其中AssociationsManager类管理了一个全局的散列表,key是添加管理属性的对象,value是ObjectAssociationMap的散列表,其中key是第二个参数,value是ObjectAssociation类,ObjectAssociation其中包含有value和policy,也就是我们传入的第三和第四个参数
关联对象并不是存储在被关联对象本身的内存中
关联对象存储在全局的同一的AssociationsManager中
设置关联对象为nil,相当于移出关联对象
评论列表(0条)