一 , 設置關聯(lián)屬性
分類中設置屬性進行關聯(lián)判斷(其中SDWebimage中用到過)
/**
* 下載圖像的 URL 字符串
* 一個屬性:分類中不能有 ivar(成員變量) / getter / setter
*/
const char *jq_URLStringKey = "jq_URLStringKey";
@property (nonatomic, copy) NSString *jq_urlString;
- (NSString *)jq_urlString {
//利用運行時記錄屬性
return objc_getAssociatedObject(self, jq_URLStringKey);
}
- (void)setJq_urlString:(NSString *)jq_urlString {
objc_setAssociatedObject(self, jq_URLStringKey, jq_urlString, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
二, 運行時動態(tài)調用方法(在OC與JS的交互中用到)
#import <objc/message.h>
1 > 調用無返回值的方法
參數(shù)一位當前調用方法對象
參數(shù)二為方法對象
參數(shù)三為需要傳遞的參數(shù)
下面是最基本的調用格式
SEL sel = NSSelectorFromString(methodName);
((void(*)(id, SEL, id))objc_msgSend)(self, sel, parameter);
2 > 調用有返回值的方法
NSString *result = ((NSString *(*)(id, SEL, id, id, id))objc_msgSend)(self, sel, parameter, parameter2, parameter3);
- (NSString *)showFood1:(NSString *)food1 Food2:(NSString *)food2 Food3:(NSString *)food3 {
NSLog(@"%@ -- %@ -- %@", food1, food2, food3);
return @"delicious";
}
3 > 調用類方法, 需要將類轉為類對象
Class personClass = [Person class];
[personClass performSelector:@selector(drink)];
((void(*)(id, SEL))objc_msgSend)(personClass, @selector(drink));
三, 動態(tài)獲取類的屬性和成員變量(字典轉模型或KVC改變系統(tǒng)屬性變量)
const void *propertyListKey = @"propertyListKey";
+ (NSArray *)jq_propertyList {
// 0. --- 判斷屬性數(shù)組是否存在溃列,如果存在直接返回 `屬性數(shù)組對象` ---
NSArray *result = objc_getAssociatedObject(self, propertyListKey);
if (result != nil) {
return result;
}
// 1. 獲取屬性數(shù)組
unsigned int count = 0;
objc_property_t *list = class_copyPropertyList([self class], &count);
NSLog(@"屬性數(shù)量 %u", count);
NSMutableArray *arrM = [NSMutableArray array];
// 2. 遍歷數(shù)組
for (unsigned int i = 0; i < count; i++) {
// 1> 通過下標獲取屬性對象
objc_property_t property = list[i];
// 2> 獲取屬性的名稱
const char *pty = property_getName(property);
// 3> 轉換成 OC 的字符串
NSString *str = [NSString stringWithUTF8String:pty];
[arrM addObject:str];
}
//釋放數(shù)組
free(list);
// --- 保存屬性數(shù)組對象 ---
objc_setAssociatedObject(self, propertyListKey, arrM, OBJC_ASSOCIATION_COPY_NONATOMIC);
return arrM.copy;
}
+ (NSArray *)jq_ivarList {
// 1. 取類的成員變量列表
unsigned int count = 0;
Ivar *list = class_copyIvarList([self class], &count);
// NSLog(@"%u", count);
NSMutableArray *arrayM = [NSMutableArray array];
// 2. 遍歷數(shù)組
for (unsigned int i = 0; i < count; i++) {
// 1> 根據(jù)下標獲取成員變量
Ivar ivar = list[i];
// 2> 取 ivar 的名字
const char *cName = ivar_getName(ivar);
// 3> 轉換成 NSString
NSString *name = [NSString stringWithUTF8String:cName];
[arrayM addObject:name];
}
// 3. 釋放列表
free(list);
return arrayM.copy;
}
四, 動態(tài)交換方法(在AFNetworking中 URLSession 做了一個交叉方法, 交換了系統(tǒng)的resume 方法, 以便在系統(tǒng)調用時可以發(fā)送一個通知來監(jiān)聽方法實現(xiàn))
+ (void)load {
Method originalMethod = class_getClassMethod([UIImage class], @selector(imageNamed:));
Method swizzledMethod = class_getClassMethod([UIImage class], @selector(jq_imageNamed:));
//交換方法
method_exchangeImplementations(originalMethod, swizzledMethod);
}
+ (UIImage *)jq_imageNamed:(NSString *)imageName {
// 1, 加載圖片
UIImage *image = [UIImage jq_imageNamed:imageName];
// 2, 判斷功能
if (image == nil) {
NSLog(@" image == nil");
}
return image;
}
五, 動態(tài)添加方法(不常用)
void laugh(id self, SEL _cmd, id param) {
NSLog(@"%@ - %@ - %@", self, NSStringFromSelector(_cmd), param);
}
//當調用了沒有實現(xiàn)的方法就會調用
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSLog(@"%@", NSStringFromSelector(sel));
//動態(tài)添加laugh方法
if (sel == @selector(laugh:)) {
/*
Class: 給哪個類添加
SEL: 方法編號
IMP: 方法實現(xiàn), 函數(shù)名
types: 方法類型 v -> void @ -> 第一個參數(shù) 表示id類型 : -> 代碼SEL 方法
*/
class_addMethod(self, sel, (IMP)laugh, "v@:@");
//處理完
return YES;
}
return [super resolveInstanceMethod:sel];
}