Objective-C語言是一門動態(tài)語言,它將很多靜態(tài)語言在編譯和鏈接時期做的事放到了運行時來處理。這種動態(tài)語言的優(yōu)勢在于:我們寫代碼時更具靈活性,如我們可以把消息轉(zhuǎn)發(fā)給我們想要的對象,或者隨意交換一個方法的實現(xiàn)等。
這種特性意味著Objective-C不僅需要一個編譯器,還需要一個運行時系統(tǒng)來執(zhí)行編譯的代碼。對于Objective-C來說,這個運行時系統(tǒng)就像一個操作系統(tǒng)一樣:它讓所有的工作可以正常的運行。這個運行時系統(tǒng)即Objc Runtime。Objc Runtime其實是一個Runtime庫,它基本上是用C和匯編寫的,這個庫使得C語言有了面向?qū)ο蟮哪芰Α?/p>
Runtime庫主要做下面幾件事:
封裝:在這個庫中,對象可以用C語言中的結(jié)構(gòu)體表示,而方法可以用C函數(shù)來實現(xiàn),另外再加上了一些額外的特性。這些結(jié)構(gòu)體和函數(shù)被runtime函數(shù)封裝后,我們就可以在程序運行時創(chuàng)建,檢查,修改類、對象和它們的方法了。
找出方法的最終執(zhí)行代碼:當程序執(zhí)行[object doSomething]時,會向消息接收者(object)發(fā)送一條消息(doSomething),runtime會根據(jù)消息接收者是否能響應該消息而做出不同的反應。
基本解釋
- Runtime 是一套比較底層的純C語言API, 它是OC的幕后工作者
- 我們平時寫的OC代碼在運行時都會編譯器轉(zhuǎn)為runtime的C語言代碼
- 其中最主要的是消息機制OC的函數(shù)調(diào)用成為消息發(fā)送 屬于動態(tài)調(diào)用過程 在編譯的時候并不能決定真正調(diào)用哪個函數(shù)
- 事實證明, 在編譯階段,OC可以調(diào)用任何函數(shù),即使這個函數(shù)并未實現(xiàn),只要申明過就不會報錯
- 而C語言在編譯階段就會報錯 只有在真正運行的時候才會根據(jù)函數(shù)的名稱找到對應的函數(shù)來調(diào)用。
實際用法
#import "ViewController.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "Person.h"
#import "NSObject+my.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *phoneImg;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
/******************1.消息發(fā)送*******************/
Person *p = [Person new];
// [p run];
objc_msgSend(p,@selector(run));
objc_msgSend([Person class], @selector(run));
/******************2.方法交換*******************/
self.phoneImg.image = [UIImage imageNamed:@"banner"];
/******************3.獲取實例變量*******************/
//參數(shù)1:你要獲取的類,參數(shù)2:數(shù)量指針
unsigned int iVarCount;
Ivar *iVarList = class_copyIvarList([Person class], &iVarCount);
for (int i = 0; i < iVarCount; i++) {
Ivar aVar = iVarList[i];
NSLog(@"%s",ivar_getName(aVar));
}
/******************4.獲取對象方法*******************/
unsigned int methodCount;
Method *methodList = class_copyMethodList([Person class], &methodCount);
for (int i = 0; i < methodCount; i++) {
Method aMethod = methodList[i];
SEL methodSel = method_getName(aMethod);
NSLog(@"%@",NSStringFromSelector(methodSel));
}
/******************5.動態(tài)創(chuàng)建類,添加實例變量*******************/
//創(chuàng)建一個類 參數(shù)1:父類 參數(shù)2:你要創(chuàng)建的類名 參數(shù)3:
Class MyClass = objc_allocateClassPair([Person class], "MyClass", 0);
//添加實例變量 參數(shù)1:要往哪個類添加, 參數(shù)2:變量名 參數(shù)3:變量大小 參數(shù)4:對齊方式-傳0 參數(shù)5:類型編碼(要去文檔查看)
if (class_addIvar(MyClass, "_city", sizeof(NSString *), 0, "@")) {
NSLog(@"變量添加成功");
id myP = [[MyClass alloc]init];//使用id類型來接收
//賦值
[myP setValue:@"廣州" forKey:@"_city"];
//取出
NSLog(@"%@",[myP valueForKey:@"_city"]);
}
/******************6.動態(tài)創(chuàng)建類,添加對象方法*******************/
//添加對象方法 參數(shù)1:要往哪個類添加, 參數(shù)2:方法選擇器 參數(shù)3:實現(xiàn) 參數(shù)4:實現(xiàn)的函數(shù)類型編碼(要去文檔查看)
if (class_addMethod(MyClass, @selector(aMethod:), (IMP)aMethod_IMP, "v@:@")) {
NSLog(@"方法添加成功");
id myP = [[MyClass alloc]init];//使用id類型來接收
[myP aMethod:@"哈哈"];
}
/******************7.分類添加屬性*******************/
NSObject *obj = [NSObject new];
obj.myName = @"aNema";
NSLog(@"%@",obj.myName);
}
//方法實現(xiàn)
void aMethod_IMP(id self,SEL _cmd,NSString * str){
NSLog(@"%s = %@",__func__,str);
}
//OC里的方法
- (void)aMethod:(NSString *)str{
NSLog(@"%s",__func__);
}
@end
UIImage分類
//
// UIImage+my.m
// 01-runtime
//
// Created by iOS on 15/12/24.
// Copyright ? 2015年 iOS. All rights reserved.
//
#import "UIImage+my.h"
#import <objc/runtime.h>
@implementation UIImage (my)
+ (void)load{
//1.獲取舊方法
Method imageNameM = class_getClassMethod(self, @selector(imageNamed:));
//2.獲取新方法
Method imageWithNameM = class_getClassMethod(self, @selector(imageWithName:));
//3.交換
method_exchangeImplementations(imageNameM, imageWithNameM);
}
//+ (UIImage *)imageNamed:(NSString *)name{
//
//}
+ (UIImage *)imageWithName:(NSString *)name{
NSLog(@"%s",__func__);
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
name = [name stringByAppendingString:@"_iPad"];
}else {
name = [name stringByAppendingString:@"_iPhone"];
}
return [self imageWithName:name];
}
@end
NSObject分類
//
// NSObject+my.m
// 01-runtime
//
// Created by iOS on 15/12/24.
// Copyright ? 2015年 iOS. All rights reserved.
//
#import "NSObject+my.h"
#import <objc/runtime.h>
@implementation NSObject (my)
static const void *myNameKey = "myNameKey";
- (void)setMyName:(NSString *)myName{
// [self setValue:myName forKey:@"myName"];
//設(shè)置關(guān)聯(lián) 參數(shù)1:要關(guān)聯(lián)的對象 參數(shù)2:綁定的key 參數(shù)3:這個key要關(guān)聯(lián)的值 參數(shù)4:要使用的策略
objc_setAssociatedObject(self, myNameKey, myName, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)myName{
// return [self valueForKey:@"myName"];
return objc_getAssociatedObject(self, myNameKey);
}
@end