日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

objc语言的运行时处理

發布時間:2023/10/18 编程问答 85 如意码农
生活随笔 收集整理的這篇文章主要介紹了 objc语言的运行时处理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在Objective-C中,消息是通過objc_msgSend()這個runtime方法及相近的方法來實現的。這個方法需要一個target,selector,還有一些參數。理論上來說,編譯器只是把消息分發變成objc_msgSend來執行。比如下面這兩行代碼是等價的。

1 [array insertObject:foo atIndex:5];
2 objc_msgSend(array, @selector(insertObject:atIndex:), foo, 5);

class的方法列表其實是一個字典,key為selectors,IMPs為value。一個IMP是指向方法在內存中的實現。很重要的一點是,selector和IMP之間的關系是在運行時才決定的,而不是編譯時。這樣我們就能玩出些花樣。

IMP通常是指向方法的指針,第一個參數是self,類型為id,第二個參數是_cmd,類型為SEL,余下的是方法的參數。這也是self_cmd被定義的地方。下面演示了Method和IMP

1 - (id)doSomethingWithInt:(int)aInt{}
2 id doSomethingWithInt(id self, SEL _cmd, int aInt){}

objc中存在一些用于修改和自省的方法,這些方法差不多都是以特定的前綴開頭,如

class_addIvar, class_addMethod,class_addProperty和class_addProtocol

允許重建classes,

class_copyIvarList,class_copyMethodList, class_copyProtocolList和class_copyPropertyList

能拿到一個class的所有內容,而

class_getClassMethod, class_getClassVariable, class_getInstanceMethod,class_getInstanceVariable, class_getMethodImplementation和class_getProperty

返回單個內容。也有些用于自省的方法,如

class_conformsToProtocol, class_respondsToSelector,class_getSuperclass。

最后,你可以使用class_createInstance來創建一個object。

比較基礎的一個動態特性是通過String來生成Classes和Selectors。Cocoa提供了NSClassFromStringNSSelectorFromString方法,使用起來很簡單

1 Class stringclass = NSClassFromString(@"NSString");
2 NSString *myString = [stringclass stringWithString:@"Hello World"];

為什么要這么做呢,直接使用class不是更方便,通常情況下,但有些場景有會很能有用,首先可以得知某個class是否存在,因為不存在的話NSClassFromString會返回nil,用于檢查。另一個常見的場景是根據不同的輸入返回不同的class跟method。在解析數據的時候,下面是一個例子

- (void)parseObject:(id)object {
for (id data in object) {
if ([[data type] isEqualToString:@"String"]) {
[self parseString:[data value]];
} else if ([[data type] isEqualToString:@"Number"]) {
[self parseNumber:[data value]];
} else if ([[data type] isEqualToString:@"Array"]) {
[self parseArray:[data value]];
}
}
}
- (void)parseObjectDynamic:(id)object {
for (id data in object) {
[self performSelector:NSSelectorFromString([NSString stringWithFormat:@"parse%@:", [data type]]) withObject:[data value]];
}
}
- (void)parseString:(NSString *)aString {}
- (void)parseNumber:(NSString *)aNumber {}
- (void)parseArray:(NSString *)aArray {}

可以看到用了后者的話可以把代碼行數降下來,將來如果有新的類型,只需要增加實現方法即可,而不用去添加新的else if.

在objc中,方法由兩部分組成,selector相當于一個方法的id,IMP是方法的實現,這樣分開的一個便利之處就是selector和IMP之間的對應關系可以被改變。這就是Method Swizzling的存在處,交換兩個方法的實現,下面是代碼實現:

 1 void MethodSwizzle(Class aClass, SEL orig_sel, SEL alt_sel){
2 Method orig_method = nil, alt_method = nil;
3 // First, look for the methods
4 orig_method = class_getInstanceMethod(aClass, orig_sel);
5 alt_method = class_getInstanceMethod(aClass, alt_sel);
6 // If both are found, swizzle them
7 if ((orig_method != nil) && (alt_method != nil)){
8 char *temp1;
9 IMP temp2;
10 temp1 = orig_method->method_types;
11 orig_method->method_types = alt_method->method_types;
12 alt_method->method_types = temp1;
13 temp2 = orig_method->method_imp;
14 orig_method->method_imp = alt_method->method_imp;
15 alt_method->method_imp = temp2;
16 }
17 }

當然,上面的第八行開始到十五行之間的代碼可以用如下進行替換。

method_exchangeImplementations(orig_method,alt_method)

上面我們談到了方法交換,但是當你發送了一個object無法處理的消息時會發生什么呢?這里首先會是動態方法處理

1 resolveInstanceMethod && resolveClassMethod

在這兩個重寫的地方運用class_addMethod,同時記得返回YES,下面是一個例子

1 + (BOOL)resolveInstanceMethod:(SEL)aSelector {
2 if (aSelector == @selector(myDynamicMethod)) {
3 class_addMethod(self, aSelector, (IMP)myDynamicIMP, "v@:");
4 return YES;
5 }
6 return [super resolveInstanceMethod:aSelector];
7 }

如果resolve method返回了NO,那么運行時就進入下一個步驟--消息轉發。首先會調用-forwardingTargetForSelector:,如果只是把消息發送到另一個object,那么就用這個方法,但是如果你想修改消息,那么就要使用-forwardInvocation:,將消息打包成NSInvocation,調用invokeWithTarget:

整個文章下來,可以看到objc表面看起來跟c#,java等語言在方法調用上沒什么區別,但最關鍵的是objc的運行時消息處理,我們可以在消息處理上添加更多的自由,其優勢在于在不擴展語言本身的情況下做很多事,比如KVO,提供了優雅的API來與已有的代碼進行無疑結合。

下面就結合運行時來談談KVO的內部真正實現。當你第一次觀察某個object時,runtime會創建一個新的繼承原先class的subclass。在這個新的class中,它重寫了所有被觀察的key,然后將object的isa指針指向新創建的class(這個指針告訴Objective-C運行時某個object到底是哪種類型的object)。所以object神奇地變成了新的子類的實例。

總結

以上是生活随笔為你收集整理的objc语言的运行时处理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。