初涉Runtime (一),初涉runtime
Objective-C 是一門動態語言,有很多東西都是運行時才確定的。
比如這句代碼首先聲明testObject是一個NSString,然後建立了一個NSData對象,並且將這個對象的記憶體位址儲存在test Object中。啟動並執行時候textObject只想的就是一個NSData對象。
NSString *testObject = [[NSData alloc]]init];
Runtime,是一套運行機制。是拿C語言一套比較底層的API,裡面於很多很好很強大的方法。我們平寫的OC的代碼轉成Runtime進行實現。就像我們初始化一個對象的時候
OC : [[Person alloc] init] runtime : objc_msgSend(objc_msgSend("Person" , "alloc"), "init")還有我們調用方法的時候,是這個樣子的 OC: [object method] Runtime: object_msgSend(obj,@selector(method));
既然Runtime是屬於OC的底層,name他就可以進行一些比較底層的操作。Objective-C能做的事情他能做,runtime能做的事情object-C就不一定能做到了,比如我們可以在程式啟動並執行時候添加一個類,遍曆一個類的成員,或者為某一個類添加一個屬性,修改屬性值之類的操作。
下面我們就舉個例子用Runtime遍曆模型屬性,對屬性進行歸檔結檔操作。
第一步我們需要倒入相關的標頭檔,運行時相關的標頭檔一般都存放在標頭檔的/objc中,比較常用的<objc/runtime.h>,<objc/message>。
1. 可以先做一個測試,我在控制器的viewDidLoad裡面寫了一段代碼,
- (void)viewDidLoad { [super viewDidLoad]; unsigned int count = 0; Ivar *ivars = class_copyIvarList([SQKPerson class], &count); for (int i = 0; i<count; i++) { // 取出i位置對應的成員變數 Ivar ivar = ivars[i]; // 查看成員變數 const char *name = ivar_getName(ivar); NSLog(@"%s", name); }
列印的結果是
2015-10-28 22:47:41.186 runtime[2312:108141] _age2015-10-28 22:47:41.186 runtime[2312:108141] _height2015-10-28 22:47:41.186 runtime[2312:108141] _name
3. 建立一個Person的類,聲明了三個屬性,age,height,name。
//// SQKPerson.m// runtime//// Created by SQK on 15/10/28.// Copyright © 2015年 SQK. All rights reserved.//#import "SQKPerson.h"#import <objc/runtime.h>/** * 進行歸檔接檔,需要遵守NSCoding協議 */@interface SQKPerson ()<NSCoding>//在這裡聲明了屬性@property (nonatomic, assign) int age;@property (nonatomic, assign) int height;@property (nonatomic, copy) NSString *name;@end@implementation SQKPerson- (void)encodeWithCoder:(NSCoder *)encode{ unsigned int count = 0; Ivar *ivars = class_copyIvarList([SQKPerson class], &count); for (int i = 0; i<count; i++) { //擷取Ivars成員變數 Ivar ivar = ivars[i]; //需要將name轉成URTF8類型的 const char *name = ivar_getName(ivar); NSString *key = [NSString stringWithUTF8String:name]; //歸檔 id value = [self valueForKey:key]; [encode encodeObject:value forKey:key]; } //需要管理記憶體 free(ivars);}-(instancetype)initWithCoder:(NSCoder *)decoder{ if (self= [super init]) { unsigned int count = 0; Ivar *ivars = class_copyIvarList([SQKPerson class], &count); for (int i = 0; i<count; i++) { //取出對應的成員變數 Ivar ivar = ivars[i]; const char *name = ivar_getName(ivar); //結檔 NSString *key = [NSString stringWithUTF8String:name]; //通過key取到成員變數(kvc) id value = [decoder decodeObjectForKey:key]; //設定value到成員變數身上 [self setValue:value forKey:key]; } free(ivars); } return self;}@end
如果我們模型中的屬性很多的話,那麼用這種方法進行操作是很方便的。
總之,runtime是很強大的一套語言庫。在蘋果的官方文檔中也給出了詳細的文檔,對各種進行詳細的解釋
class_getName
class_addIvar
class_copyIvarList
class_getProperty
class_getPropertyList
....................
總而言之,Runtime是很好的一套東西,希望我們都能對他有所瞭解。我寫這東西也是一邊學一邊寫,難免避免有錯誤的見解。希望能和大家共同進步!