msg_send方法
可以幫助我們調(diào)用系統(tǒng)的私有方法
<pre>`
Person * person = objc_msgSend(objc_getClass ("Person") ),sel_registName("alloc");
person = objc_msgSend(p, sel_registerName("init"));
objc_msgSend (person, @selector(MethodName));
`</pre>
method_exchangeImplementations方法
常常在想修改系統(tǒng)方法的時候調(diào)用此API,如測試時,UIImage圖片一經(jīng)加載就需要提示是否加載成功,每次頁面加載時,顯示加載的VC等功能,下面通過Category重寫imageNamed方法實現(xiàn)每次加載圖片提示加載是否成功的功能
<pre>`
-
(void)load
{
//獲取系統(tǒng)方法
Method imageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));// 獲取fch_imageNamed
Method fch_imageNamedMethod = class_getClassMethod(self, @selector(xmg_imageNamed:));// 交互方法:runtime
method_exchangeImplementations(imageNamedMethod, fch_imageNamedMethod);
// 調(diào)用imageNamed => fch_imageNamedMethod
// 調(diào)用fch_imageNamedMethod => imageNamed
}
`</pre>
這里需要注意一個問題 load方法和 initialize方法的區(qū)別,+load會在類初始加載時調(diào)用,+initialize會在第一次調(diào)用類的類方法或實例方法之前被調(diào)用,會被調(diào)用多次。具體區(qū)別可以參考這篇文章,下面這種方法等價于+load方法
<pre>`
-
(void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method imageNamedMethod = class_getClassMethod(self, @selector(imageNamed:));Method fch_imageNamedMethod = class_getClassMethod(self, @selector(fch_imageNamed:)); method_exchangeImplementations(imageNamedMethod, fch_imageNamedMethod);
});
}`</pre>
如果對initiallze方法了解不深 建議Swizzing寫在+load方法里面
<pre>`
- (UIImage *)fch_imageNamed:(NSString *)name
{
//這里需要注意:由于方法已經(jīng)調(diào)換 fch_imageNamed實際是調(diào)用 imageNamed方法實現(xiàn)
UIImage *image = [UIImage fch_imageNamed:name];
if (image) {
NSLog(@"加載成功");
} else {
NSLog(@"失敗");
}
return image;
}
`</pre>
除非必要情況下,最好少用Swizzling,實際開發(fā)中最好明確記錄在哪里使用了Swizzling.調(diào)用這此方法的注意事項可以參考 這篇文章
resolveInstanceMethod方法
動態(tài)添加方法,常常應用于App會員機制的實現(xiàn),付費版免費版App之間的切換,下面以會員機制的效果來講解這一方法的實現(xiàn)
<pre>`
Person * p = [Person new];
[ p performSelector:@selector(會員方法:) ];
`</pre>
<pre>`
import "Person.h"
import <objc/message.h>
@implementation Person
// void,(id,SEL)
void aaa(id self, SEL _cmd) {
NSLog(@"會員方法實現(xiàn)");
}
// 任何方法默認都有兩個隱式參數(shù),self,_cmd
// 什么時候調(diào)用:只要一個對象調(diào)用了一個未實現(xiàn)的方法就會調(diào)用這個方法,進行處理
// 作用:動態(tài)添加方法,處理未實現(xiàn)
-
(BOOL)resolveInstanceMethod:(SEL)sel
{
// [NSStringFromSelector(sel) isEqualToString:@"eat"];
if (sel == NSSelectorFromString(@"會員方法名稱:")) {
// eat
// class: 給哪個類添加方法
// SEL: 添加哪個方法
// IMP: 方法實現(xiàn) => 函數(shù) => 函數(shù)入口 => 函數(shù)名
// type: 方法類型
class_addMethod(self, sel, (IMP)aaa, "v@:@");return YES;
}
return [super resolveInstanceMethod:sel];
}
`</pre>
關聯(lián)objc_setAssociatedObject
給系統(tǒng)的類添加屬性,讓某個屬性與對象產(chǎn)生關聯(lián),下面為NSObject添加屬性name
<pre>`
import <Foundation/Foundation.h>
@interface NSObject (Property)
// @property分類:只會生成get,set方法聲明,不會生成實現(xiàn),也不會生成下劃線成員屬性
@property NSString *name;
@end
`</pre>
<pre>`
import "NSObject+Property.h"
import <objc/message.h>
@implementation NSObject (Property)
//static NSString *_name;
- (void)setName:(NSString *)name
{
// 讓這個字符串與當前對象產(chǎn)生聯(lián)系
// _name = name;
// object:給哪個對象添加屬性
// key:屬性名稱
// value:屬性值
// policy:保存策略
objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, @"name");
}
`</pre>
更多關于關聯(lián)技術的實現(xiàn)[請參考此文章](a href = "http://blog.leichunfeng.com/blog/2015/06/26/objective-c-associated-objects-implementation-principle/")
多繼承的簡單實現(xiàn)
<pre>`
-
(void)viewDidLoad {
[super viewDidLoad];[self performSelector:@selector(firstMethod)];
}
</pre> <pre>
-(id)forwardingTargetForSelector:(SEL)aSelector
{
Class class = NSClassFromString(@"fristViewController");
ViewController *vc = class.new;
if (aSelector == NSSelectorFromString(@"firstMethod")) {
NSLog(@"firstMethod do this ");
return vc;
}
return nil;
}</pre> <pre>
import "fristViewController.h"
@interface fristViewController ()
@end
@implementation fristViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)firstMethod
{
NSLog(@"firstResaposed");
}
`</pre>