以动态解析来实现@dynamic属性
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSString *selectorString = NSStringFromSelector(sel);
// 获取方法的类型编码(type encoding)做铺垫
Method exchangeSetM = class_getInstanceMethod([self class], @selector(insteadSetMethod));
Method exchangeGetM = class_getInstanceMethod([self class], @selector(insteadGetMethod));
if ([selectorString hasPrefix:@"set"]) {
// method_getTypeEncoding()获取方法的类型编码(type encoding)
class_addMethod(self, sel, class_getMethodImplementation(self, @selector(insteadSetMethod)), method_getTypeEncoding(exchangeSetM));
}else {
class_addMethod(self, sel, class_getMethodImplementation(self, @selector(insteadGetMethod)), method_getTypeEncoding(exchangeGetM)); // 获取方法的类型编码(type encoding)
}
return YES;
}
- (void)insteadSetMethod {
NSLog(@"调用了==== SET");
}
- (NSString *)insteadGetMethod {
NSString *string = @"调用了==== GET 0001";
return string;
}
复制代码
重写resolveInstanceMethod:
方法,给找不到实现的方法添加set,get
方法。
动态添加属性
动态加载一个属性,只需利用分类机制就OK了,先看代码:
.h 文件
#import <UIKit/UIKit.h>
@interface UIControl (Button)
@property (nonatomic, assign) NSInteger clickCount;
@end
.m 文件
#import "UIControl+Button.h"
#import <objc/runtime.h>
static const char *BtnClick_Key = "btn_clickkey";
@implementation UIControl (Button)
- (void)setClickCount:(NSInteger)clickCount {
objc_setAssociatedObject(self, BtnClick_Key, @(clickCount), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSInteger)clickCount {
return [objc_getAssociatedObject(self, BtnClick_Key) integerValue];
}
@end
调用:
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.clickCount = 4;
复制代码
通过上面代码,就可以动态添加属性。objc_setAssociatedObject()
: set(源对象,key值,value值,属性关联策略)objc_getAssociatedObject()
: get(源对象,key值)
属性关联策略:
typedefOBJC_ENUM(uintptr_t, objc_AssociationPolicy){
// 第一个关联策略是基于基本类型的,也就是我们常用的assign 属性
OBJC_ASSOCIATION_ASSIGN = 0,
/**< Specifies a weak reference to the associated object. *///关联策略是基于对象类型的,如我们正常的是retain nonatomic (非原子操作)类型 ,retain : 保留一个引用指针,内存地址不修改,指向同一块内存地址
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
/**< Specifies a strong reference to the associated object. * The association is not made atomically. *///这个相当于属性中对一些对象或者字符串进行的copy 这个是拷贝一个新对象,内存地址不在一起,还是使用的非原子类型,非原子类型我们也称之为线程不安全的操作,但是对于OC里面的数据操作,我们尽量避开原子操作,原子操作是线程安全的,会影响我们对数据的写入操作
OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
/**< Specifies that the associated object is copied. * The association is not made atomically. */// 简单的指针引用, retain 操作
OBJC_ASSOCIATION_RETAIN = 01401,
/**< Specifies a strong reference to the associated object. * The association is made atomically. *///把简单的对象拷贝到一个新的内存地址
OBJC_ASSOCIATION_COPY = 01403
/**< Specifies that the associated object is copied. * The association is made atomically. */
};
复制代码
获取对象的成员变量或属性
直接上代码
@protocol PersonDelegate <NSObject>
- (void)setBackgroundWithColor1:(NSString *)string;
@end
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign) float weight;
@property (nonatomic, copy) id<PersonDelegate>delegate;
- (void)testOne;
- (void)changeTestString:(NSString *)string;
@end
#import "Person.h"
@interface Person () {
NSString *_decr;
}
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) UIView *testView;
@end
@implementation Person
@end
复制代码
使用class_copyIvarList
获取类的成员变量:
- (void)getInfoByIvar {
unsigned int outCount = 0;
Ivar *ivars = class_copyIvarList([Person class], &outCount);
NSLog(@"ByIvar: %d", outCount);
for (int i = 0; i < outCount; i ++) {
const char *name = ivar_getName(ivars[i]);
NSString *key = [NSString stringWithUTF8String:name];
NSLog(@"==== %@", key);
}
free(ivars);
}
复制代码
它返回的是一个Ivar
的数组,这个数组里面包含了你要查看类的所有实例变量,但是不包括从父类继承过来的。如果你传入的类没有实例变量或者改class
为Nil
,那么该方法返回的就是NULL
,count
值也就变成了0。有一点需要注意:你必须使用free()
方法将该数组释放。 然后就是通过for循环遍历,通过ivar_getName
拿到ivarName
。 以上便是对clas_copyIvarList
的介绍。
使用class_copyPropertyList
获取类的属性
- (void)getInfoByProperty {
unsigned int outCount = 0;
objc_property_t *property = class_copyPropertyList([Person class], &outCount);
NSLog(@"ByProperty: %d", outCount);
for (int i = 0; i < outCount; i ++) {
NSString *name = @(property_getName(property[i]));
NSString *attributes = @(property_getAttributes(property[i]));
NSLog(@"==== %@ --------- %@", name, attributes);
}
free(property);
}
复制代码