runtime 的一些理解, 整理收集了不少網(wǎng)絡的知識, 只是用于自己對runtime的理解,以備以后自己查閱吧
歸納: **
OC是運行時語言,只有在程序運行時,才會去確定對象的類型,并調用類與對象相應的方法。平時編寫的OC代碼, 在程序運行過程中, 其實最終都是轉成了runtime的C語言代碼, runtime算是OC的幕后工作者。利用runtime機制讓我們可以在程序運行時動態(tài)修改類、對象中的所有屬性、方法,就算是私有方法以及私有屬性都是可以動態(tài)修改的。
runtime是屬于OC的底層, 可以進行一些非常底層的操作。在程序運行過程中, 動態(tài)創(chuàng)建一個類, 動態(tài)地為某個類添加屬性\方法, 修改屬性值\方法,遍歷一個類的所有成員變量(屬性)\所有方法等。
相關知識點
Ivar:定義對象的實例變量,包括類型和名字。objc_property_t:定義屬性。這個名字可能是為了防止和Objective-C 1.0中的用戶類型沖突,那時候還沒有屬性。Method:成員方法。這個類型提供了方法的名字(就是選擇器)、參數(shù)數(shù)量和類型,以及返回值(這些信息合起來稱為方法的簽名),還有一個指向代碼的函數(shù)指針(也就是方法的實現(xiàn)**)。
SEL:定義選擇器。選擇器是方法名的唯一標識符,我理解它就是個字符串。
****運行時應用(一)****——** 攔截系統(tǒng)自帶的方法交換實現(xiàn)**
- <objc/runtime.h>
2.<objc/message.h>
運行時應用(二)—— 使用對象關聯(lián)為分類增加屬性(每個對象的屬性互不干擾)
1、對象的關聯(lián)方法有
將某個值與某個對象關聯(lián)起來,將某個值存儲到某個對象中
利用參數(shù)key將對象中存儲的對應值取出
2、利用分類為每個對象添加屬性(可作為對象的標簽或存儲信息)
運行時應用(三)——實現(xiàn)NSCoding的自動歸檔和自動解檔
當我們需要將一個對象進行歸檔時,都要讓該對象的類遵守NSCoding協(xié)議,再實現(xiàn)歸檔和接檔方法;
但當該類擁有上百個屬性時,那將會花費更多的功夫在重復代碼上,所以使用運行時runtime機制截取類的成員變量,進行賦值
補充: 在設計模式中: 如多態(tài)的一種適配器模式,就是使用的運行時,在程序過程中動態(tài)創(chuàng)建當前需要的類或者控制器, 也就是我們常說的封裝一個基類,后面的都繼承這個類,或者干脆在程序運行過程中動態(tài)創(chuàng)建;
詳解:
Object - C運行時應用(一)—— 攔截系統(tǒng)自帶的方法交換實現(xiàn)
一、什么是運行時
運行時是一套純C語言的API,編譯器最終都會將OC代碼轉化為運行時代碼。
二、運行時常用函數(shù)
1、<objc/runtime.h>
* 獲得某個類的類方法
Method class_getClassMethod(Class cls, SEL name)
* 獲得某個對象的對象方法
Method class_getInstanceMethod(Class cls, SEL name)
* 交換兩個方法的實現(xiàn)
void method_exchangeImplementations(Method m1, Method m2)
* 關聯(lián)對象(將值value與對象object關聯(lián)起來)
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
參數(shù)key:將來可以通過key取出這個存儲的值
參數(shù)policy:存儲策略(assign、copy、retain)
* 利用參數(shù)key將對象中存儲的對應值取出
id objc_getAssociatedObject(id object, const void *key)
* 獲得某個類的所有成員變量
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)(outCount會返回成員變量的總數(shù))
* 獲得成員變量的名字
const char *ivar_getName(Ivar v)
* 獲得成員變量的類型
const char *ivar_getTypeEncoding(Ivar v)
* 釋放內存
void free(void *)
(當C語言函數(shù)名中包含了copy、create、retain、new等詞語,那么就需要在最后釋放資源)
2、<objc/message.h>
* 給某個對象發(fā)送某個消息
void objc_msgSend(void)
Object - C運行時應用(二)—— 使用對象關聯(lián)為分類增加屬性(每個對象的屬性互不干擾)
一、對象的關聯(lián)方法有
// 將某個值與某個對象關聯(lián)起來,將某個值存儲到某個對象中
1、 void objc_setAssociatedObject(id object, const void *key, id value,objc_AssociationPolicy policy) ,
關聯(lián)對象(將值value與對象object關聯(lián)起來)
參數(shù)key:將來可以通過key取出這個存儲的值
參數(shù)policy:存儲策略(assign、copy、retain)
2、 id objc_getAssociatedObject(id object, const void *key) ,
利用參數(shù)key將對象中存儲的對應值取出
二、利用分類為每個對象添加屬性(可作為對象的標簽或存儲信息)聲明代碼:
@interface NSObject (CX)
/**
* 為每一個對象添加一個name屬性
*/
@property (nonatomic,copy) NSString *name;
/**
* 為每個對象添加一個數(shù)組屬性
*/
@property (nonatomic,strong) NSArray *books;
@end
實現(xiàn)代碼:
// 用一個字節(jié)來存儲key值,設置為靜態(tài)私有變量,避免外界修改
static char nameKey;
- (void)setName:(NSString *)name
{
// 將某個值與某個對象關聯(lián)起來,將某個值存儲到某個對象中
objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, &nameKey);
}
static char booksKey;
- (void)setBooks:(NSArray *)books
{
objc_setAssociatedObject(self, &booksKey, books, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSArray *)books
{
return objc_getAssociatedObject(self, &booksKey);
}
```
測試:
NSString *str = @"xx";
str.name = @"oo";
str.books = @[@"xxoo",@"ooxx"];
NSLog(@"%@,%@",str.name,str.books);
三、對象關聯(lián)的另一種作用:在既有類中使用關聯(lián)對象存放自定義數(shù)據(jù)
在ios開發(fā)時經常會用到UIAlertView類,該類提供了一種視圖向用戶展示警告信息。該類通過代理協(xié)議來處理用戶的點擊事件,但由于使用了代理就必須把創(chuàng)建警告的視圖和處理按鈕動作的代碼分開;
####**運行時應用(三)——實現(xiàn)NSCoding的自動歸檔和自動解檔**
當我們需要將一個對象進行歸檔時,都要讓該對象的類遵守NSCoding協(xié)議,再實現(xiàn)歸檔和接檔方法。
例如有一個Person類,該類有兩個成員變量
@property (nonatomic,copy) NSString name;
@property (nonatomic,assign) int age;
兩個協(xié)議的實現(xiàn)方法如下
/*
將對象寫入某個文件時需要調用,在該方法中說明哪些屬性需要存儲
*/
- (void)encodeWithCoder:(NSCoder )encoder{
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeInt:self.age forKey:@"age"];
}
/* 從文件中解析對象時會調用,在該方法中解析對象的屬性 */ - (id)initWithCoder:(NSCoder *)decoder{
if (self = [super init]) {
// 解析之后要賦值給屬性
_name = [decoder decodeObjectForKey:@"name"];
_age = [decoder decodeIntForKey:@"age"];
}
return self;
}
但當該類擁有上百個屬性時,那將會花費更多的功夫在重復代碼上,所以使用運行時runtime機制截取類的成員變量,進行賦值