国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

runtime 理解

2019-11-08 00:20:31
字體:
供稿:網(wǎng)友

大家知道OC是一門動態(tài)語言,他將一些靜態(tài)語言以及庫的鏈接的一些事情放在運行時來進行處理,這就給我們增加了編程的靈活性,比如可以隨意交換兩個方法的執(zhí)行,消息的轉(zhuǎn)發(fā)等等。這就是Runtime運行時。這個庫全部由C語言來編寫的,該對象用結(jié)構(gòu)體來表示,方法使用C函數(shù)來表示。當這些結(jié)構(gòu)體以及方法用runtime函數(shù)來修飾封裝后,我們就可以對類和對象進行創(chuàng)建、檢查、修改等操作了。

1、基本結(jié)構(gòu)

/// An opaque type that rePResents a method in a class definition.類中定義的方法

typedefstruct objc_method *Method;

/// An opaque type that represents an instance variable.類中定義的實例變量

typedefstruct objc_ivar *Ivar;

/// An opaque type that represents a category.類別

typedefstruct objc_category *Category;

/// An opaque type that represents an Objective-C declared property.類中聲明的屬性

typedefstruct objc_property *objc_property_t;

struct objc_class {

    Class isa  OBJC_ISA_AVAILABILITY; isa指針,通過它可以找到對象所述的類,isa指針在代碼運行時并不總是指向?qū)嵗鶎俚念?,因此不能通過其獲取類型,但是可以通過‘’-class來確定。KVO的實現(xiàn)機理就是通過isa指針指向一個中間類而不是真實類來實現(xiàn)的。

#if !__OBJC2__

    Class super_class                                        OBJC2_UNAVAILABLE;

    constchar *name                                         OBJC2_UNAVAILABLE;   ------類名

    long version                                             OBJC2_UNAVAILABLE;

    long info                                                OBJC2_UNAVAILABLE;

    long instance_size                                       OBJC2_UNAVAILABLE;

    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;  ------屬性列表

    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;------方法列表

    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;------緩存,一種優(yōu)化機制

    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;------協(xié)議列表

#endif

} OBJC2_UNAVAILABLE;

/* Use `Class` instead of `struct objc_class *` */

2、常用的獲取列表的屬性

unsigned int count; //獲取屬性列表 objc_property_t *propertyList = class_copyPropertyList([self class], &count); for (unsigned int i=0; i<count; i++) { const char *propertyName = property_getName(propertyList[i]); NSLog(@"property---->%@", [NSString stringWithUTF8String:propertyName]); } //獲取方法列表 Method *methodList = class_copyMethodList([self class], &count); for (unsigned int i; i<count; i++) { Method method = methodList[i]; NSLog(@"method---->%@", NSStringFromSelector(method_getName(method))); } //獲取成員變量列表 Ivar *ivarList = class_copyIvarList([self class], &count); for (unsigned int i; i<count; i++) { Ivar myIvar = ivarList[i]; const char *ivarName = ivar_getName(myIvar); NSLog(@"Ivar---->%@", [NSString stringWithUTF8String:ivarName]); } //獲取協(xié)議列表 __unsafe_unretained Protocol **protocolList = class_copyProtocolList([self class], &count); for (unsigned int i; i<count; i++) { Protocol *myProtocal = protocolList[i]; const char *protocolName = protocol_getName(myProtocal); NSLog(@"protocol---->%@", [NSString stringWithUTF8String:protocolName]); }3、消息轉(zhuǎn)發(fā)

在OC中調(diào)用方法一般是如下調(diào)用

id returnValue = [someObject messageName:parameter];,someObject是消息的接受者,messageName是一個選擇器,parameter則為參數(shù)。選擇器+參數(shù) 就是我們所稱為的消息。

其在底層中是將我們的消息轉(zhuǎn)換為標準的C語言函數(shù),Void objc_msgSend(id self , SEL cmd , .....)  ,self 為消息接收者,cmd為選擇器,省略號為參數(shù),表示可變長度參數(shù)。因此以上的消息方法會轉(zhuǎn)換為id returnValue = objc_msgSend( someObject , @selector(messageName:) , parameter);

之所以O(shè)bjc_msgsend方法總能找到正確的函數(shù)去執(zhí)行,原因是OC中每個類都有一張方法的列表存儲這個類的所有方法,當發(fā)出objc_msgsend時,會根據(jù)object的isa指針找到類結(jié)構(gòu)的方法,如果找不到則會到父類尋找該方法的實現(xiàn),直到NSObject類。上面有提到cach緩存機制,蘋果為了加快尋找速率,runtime 系統(tǒng)會緩存使用過的SEL 和方法地址。

通過object的isa指針找到他的類結(jié)構(gòu)class在在相應(yīng)操作的對象中的緩存方法列表中找調(diào)用的方法,如果找到,轉(zhuǎn)向相應(yīng)實現(xiàn)并執(zhí)行(IMP)如果沒找到,在相應(yīng)操作的對象中的方法列表中找調(diào)用的方法,如果找到,轉(zhuǎn)向相應(yīng)實現(xiàn)執(zhí)行(IMP)如果還未找到則會去父類中重復(fù)上面操作尋找如果最終還是未找到,則會調(diào)用實例方法調(diào)用+(bool)resolveInstanceMethod:(SEL)sel ;類方法調(diào)用:+(bool)resolveClassMethod:(SEL)sel;如果返回為YES,則會重啟一次消息發(fā)送過程,調(diào)用你自己添加的方法。

+ (BOOL)resolveInstanceMethod:(SEL)sel

{

    if (sel ==@selector(sendMessage:)) {

        class_addMethod([selfclass], sel,imp_implementationWithBlock(^(idself,NSString *Word) {

            NSLog(@"method resolution way : send message = %@", word);

        }), "v@*");

    }

    returnYES;

}

- (void)sendMessage:(NSString *)word

{

    NSLog(@"normal way : send message = %@", word);

}

如果返回NO,則會調(diào)用- (id)forwardingTargetForSelector:(SEL)aSelector方法,再次方法中可以將你調(diào)用的不存在的方法重定向到一個其他聲明了這個方法的類,只需要你返回一個有這個方法的target,

- (id)forwardingTargetForSelector:(SEL)aSelector

{

    if (aSelector ==@selector(sendMessage:)) {

        return [MessageForwardingnew];//新建的類,見下

    }

    returnnil;

}

#import <Foundation/Foundation.h>

@interface MessageForwarding :NSObject

- (void)sendMessage:(NSString *)word;

@end

如果return nil,則會- (void)forwardInvocation:(NSInvocation *)anInvocation將你調(diào)用的不存在的方法打包成NSInvocation傳給你。做完你自己的處理后,調(diào)用invokeWithTarget:方法讓某個target觸發(fā)這個方法。

- (void)forwardInvocation:(NSInvocation *)anInvocation

{

    MessageForwarding *messageForwarding = [MessageForwardingnew];

    if ([messageForwardingrespondsToSelector:anInvocation.selector]) {

        [anInvocationinvokeWithTarget:messageForwarding];

    }

}

#import <Foundation/Foundation.h>

@interface MessageForwarding :NSObject

- (void)sendMessage:(NSString *)word;

@end

4、runtime實際應(yīng)用

更改私有屬性 、給category添加屬性、歸檔解檔、AOP等等,具體事例請看本博客其他文章


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 醴陵市| 尖扎县| 德昌县| 甘洛县| 陇南市| 松原市| 广宗县| 静安区| 耿马| 镶黄旗| 湖南省| 张家口市| 湾仔区| 黄山市| 仙居县| 平阴县| 东阿县| 七台河市| 汉寿县| 长葛市| 明溪县| 永川市| 淮北市| 宝鸡市| 台前县| 沧州市| 五原县| 仪征市| 永城市| 蒙阴县| 隆回县| 多伦县| 榆林市| 南涧| 青河县| 道孚县| 铜山县| 海阳市| 常德市| 五华县| 松潘县|