iOS-runtime

什麼是Objective-C runtime?
簡單來說,Objective-C runtime是一個實現Objective-C語言的C庫。對象可以用C語言中的結構體表示,而方法(methods)可以用C函數實現。事實上,他們 差不多也是這麼幹了,另外再加上了一些額外的特性。這些結構體和函數被runtime函數封裝後,Objective-C程序員可以在程序運行時創建,檢 查,修改類,對象和它們的方法。
除了封裝,Objective-C runtime庫也負責找出方法的最終執行代碼。當程序執行[object doSomething]時,不會直接找到方法並調用。相反,一條消息(message)會發送給對象(在這兒,我們通常叫它接收者)。runtime庫 給次機會讓對象根據消息決定該作出什麼樣的反應。Alan Kay反覆強調消息傳遞(message-passing)是Smalltalk最重要的部分,而不是對象。

Objective-C runtime可以有效的幫助我們爲程序增加很多動態的行爲。一些開發者除了使用method swizzling幫助調試程序,並不會在實際程序中使用它,但runtime編程的確有很多功能,它應該成爲實際應用代碼編寫的重要工具。

在使用tuntime時候,注意在使用之前,要包含 #import <objc/message.h>、#import<objc/runtime.h>


1.ios runtime 動態向類添加方法


一個Objective-C方法本質上是一個擁有至少兩個參數(self和_cmd)的C函數,我們可以利用class_addMethod向一個類添加一個方法。比如對於下面的函數:

/************************************************/  
void dynamicMethodIMP(id self, SEL _cmd) {  
     // implementation ….   
}  
/************************************************/  

我們可以利用resolveInstanceMethod:將它添加成一個方法(比如叫resolveThisMethodDynamically):
/************************************************/  
@implementation MyClass  
+ (BOOL)resolveInstanceMethod:(SEL)aSEL  
{  
     if (aSEL == @selector(resolveThisMethodDynamically)) {  
          class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");  
          return YES;  
     }  
     return [super resolveInstanceMethod:aSEL];  
}  
@end  
/************************************************/  

動態決議和發送消息並不衝突,在消息機制起作用之前,一個類是有機會動態決議一個方法的。當respondsToSelector:或者instancesRespondToSelector:被激活時,dynamic method resolver會優先有個機會爲這個selector提供一份實現。如果實現了resolveInstanceMethod:,對於不想動態決議而想讓其遵循消息轉發機制的selectors,返回NO即可。Objective-C程序可以在運行時鏈接新的類和category。動態加載可以用來做很多不同的事情。


2.獲得屬性聲明(只能獲取本類的,父類的無法獲取,而且無法得到類的成員變量)

當編譯器遇到屬性聲明時,它會生成一些可描述的元數據(metadata),將其與相應的類、category和協議關聯起來。存在一些函數可以通過名稱在類或者協議中查找這些metadata,通過這些函數,我們可以獲得編碼後的屬性類型(字符串),複製屬性的attribute列表(C字符串數組)。因此,每個類和協議的屬性列表我們都可以獲得。
與類型編碼類似,屬性類型也有相應的編碼方案,比如readonly編碼爲R,copy編碼爲C,retain編碼爲&等。
通過property_getAttributes函數可以後去編碼後的字符串,該字符串以T開頭,緊接@encode type和逗號,接着以V和變量名結尾。比如:

@property char charDefault;  
描述爲:Tc,VcharDefault

@property(retain)ididRetain;  
描述爲:T@,&,VidRetain

Property結構體定義了一個指向屬性描述符的不透明句柄:typedef struct objc_property *Property;。
通過class_copyPropertyList和protocol_copyPropertyList函數可以獲取相應的屬性數組:

objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)  
objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)  
通過property_getName函數可以獲取屬性名稱。
通過class_getProperty和protocol_getProperty可以相應地根據給定名稱獲取到屬性引用:

通過property_getName函數可以獲取屬性名稱。
通過class_getProperty和protocol_getProperty可以相應地根據給定名稱獲取到屬性引用:

objc_property_t class_getProperty(Class cls, const char *name)  
objc_property_t protocol_getProperty(Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty)  

通過property_getAttributes函數可以獲取屬性的@encode type string:
const char *property_getAttributes(objc_property_t property);


/************************************************/  
#import <UIKit/UIKit.h>


@interface ViewController : UIViewController
@property (nonatomic,strong) UILabel * Mylabel;
@end


@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    id LenderClass = objc_getClass("ViewController");
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        fprintf(stdout, "%s      %s\n", property_getName(property), property_getAttributes(property));
    }


}
@end

/************************************************/  
viewdidload代碼段打印的結果是:
Mylabel      T@"UILabel",&,N,V_Mylabel
開始是屬性名字,後面 T開始,V結束,中間是這個property的各種屬性,如nonatomic等,後面會緊跟屬性的實例名。


3.類中所有的成員變量聲明

#import <UIKit/UIKit.h>

@interface SLViewController : UIViewController
{
    UILabel * _mylabel1;
    UIView *  _myView;
}
@end
/************************************************/  
@implementation SLViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self getInstanceText];
}

- (void)getPropertyText
{
    id LenderClass = objc_getClass("SLViewController");
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        fprintf(stdout, "%s      %s\n", property_getName(property), property_getAttributes(property));
    }
}

@end
打印結果:
---_mylabel1--@"UILabel"
---_myView--@"UIView"
可見,通過上面幾句簡單的代碼就可以獲取到某個類中所有變量的名稱和類型,然後通過object_setIvar()方法爲具體某個對象的某個成員變量賦值。

    例子Demo  : http://download.csdn.net/detail/u011883764/7399291

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章