一、動态添加方法
應用場景: 當一個類的方法非常多,加載類到記憶體的時候比較耗資源,需要給每個方法生成映射表. 此時可以動态給某個類添加方法
面試題: 是否使用過performSelector, 其實就是想問你有沒有動态添加過方法
知識點:
1. 所有的方法,預設都有 id self, SEL _cmd 這兩個隐式參數. _cmd表示目前方法的方法編号
2. + (BOOL)resolveInstanceMethod:(SEL)sel 用來判斷,未實作的方法是否是我們想要動态添加的方法
3. 動态添加 class_addMethod(arg1, arg2, arg3, arg4);
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
/*
動态添加方法:
開發中的使用場景: 如果一個類方法非常多,加載類到記憶體的時候比較消耗資源,需要給每個方法生成映射表,可以動态給某個類添加方法
面試題: 是否使用過performSelector, 其實主要想問你有沒有動态添加過方法
*/
- (void)viewDidLoad {
[super viewDidLoad];
Person *p = [[Person alloc] init];
// [p performSelector:@selector(eat)];
[p performSelector:@selector(run:) withObject:@"ZY" withObject:@20];
}
@end
#import "Person.h"
#import <objc/message.h>
@implementation Person
// 所有的方法.預設都有self, _cmd 這兩個隐式參數
// _cmd 表示目前方法的方法編号
void eatFood(id self, SEL _cmd)
{
NSLog(@"吃食物!");
}
void runPace(id self, SEL _cmd, NSString *name, NSNumber *meter)
{
NSLog(@"我叫%@,我今年%@,我在?",name,meter);
// _cmd 表示目前方法的方法編号
NSLog(@"%@",NSStringFromSelector(_cmd));
}
// 當一個對象調用未實作的方法,會調用這個方法來處理,并且會把對應的方法清單傳過來
// 可以用來判斷,未實作的方法是否是我們想要動态添加的方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// if ([NSStringFromSelector(sel) isEqualToString:@"eat"]){
if (sel == NSSelectorFromString(@"eat")) {
/*
param1: class 給哪個類添加方法
param2: SEL 添加哪個方法
param3: IMP: 方法實作(在方法區) => 函數 => 函數入口 => 函數名
param4: type: 方法類型
*/
class_addMethod(self, sel, (IMP)eatFood, "[email protected]:");
return YES;
}
if ([NSStringFromSelector(sel) isEqualToString:@"run:"]) {
class_addMethod(self, sel, (IMP)runPace, "[email protected]:@@");
return YES;
}
return [super resolveInstanceMethod:sel];
}
二、動态添加屬性
應用場景: 給系統的類增加屬性的時候,可以使用runtime動态添加屬性.
本質: 動态添加屬性,就是讓某個屬性與對象産生關聯
runtime一般針對系統的類
需求: 把基類NSObject類,添加一個name字元串屬性
步驟:
1. 給系統自帶的NSObject屬性添加分類
2. 在分類中聲明name屬性,在分類中@property NSString *name; 隻會生成get,set方法的聲明,并且不會生成私有屬性_name.
本質不會生成成員屬性,而是提供get,set方法聲明,供外界調用
3. 在分類中實作get,set方法
4. set方法實作,把傳遞的值給對象關聯
5. get方法實作,把關聯的值取出來傳出去
#import "ViewController.h"
#import "NSObject+Property.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
// 動态添加屬性
// 開發場景:
// 給系統的類添加屬性的時候,可以使用runtime動态添加屬性方法
// 本質:動态添加屬性,就是讓某個屬性與對象産生關聯
// runtime一般都是針對系統的類
/*
需求:讓一個NSObject類 儲存一個name字元串屬性
動态添加NSObject屬性的步驟
1.給系統自帶的NSObject添加分類
2.在分類中聲明屬性的get,set方法,本質并不是真的生成成員屬性,而是提供get,set方法,供外界擷取
3.在分類實作get,set方法
4.set方法實作,把傳遞的值給對象關聯。
5.get方法實作,把關聯的值取出來傳出去
*/
- (void)viewDidLoad {
[super viewDidLoad];
NSObject *objc = [[NSObject alloc] init];
objc.name = @"ZY";
NSLog(@"%@",objc.name);
Person *p = [[Person alloc] init];
p.name = @"GZY";
}
@end
分類NSObject+Property:
#import <Foundation/Foundation.h>
@interface NSObject (Property)
// @property分類: 隻會生成get,set方法聲明,不會生成方法實作,并且不會生成_name私有屬性
@property NSString *name;
@end
#import "NSObject+Property.h"
#import <objc/message.h>
@implementation NSObject (Property)
// 屬性名稱
static const char *key = "name";
// set方法
- (void)setName:(NSString *)name
{
// 讓這個字元串與目前對象産生聯系
/*
param1:object:給哪個對象添加屬性
param2:key:屬性名稱
param3:value:屬性值
param4:policy:儲存政策
*/
objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
// get 方法
- (NSString *)name
{
return objc_getAssociatedObject(self, key);
}
@end