Objective-C RunTime System (一、基本結構)

来源:http://www.cnblogs.com/Erma-king/archive/2016/04/20/5410921.html
-Advertisement-
Play Games

Objective C RunTime System (一、基本結構) === 寫OC也有一段時間了~之前一直在研究Objective C的RunTime,應該稱為Runtime系統,國內博客對Runtime的文章甚少,翻牆查閱文獻大量英文,書籍也翻閱甚多,因為近段時間家裡親人生病,一時很忙,文章斷 ...


Objective-C RunTime System (一、基本結構)

寫OC也有一段時間了~之前一直在研究Objective-C的RunTime,應該稱為Runtime系統,國內博客對Runtime的文章甚少,FQ查閱文獻大量英文,書籍也翻閱甚多,因為近段時間家裡親人生病,一時很忙,文章斷斷續續的一直在寫,博客也很久沒有更新~現在發表出來與大家分享~

一、什麼叫運行時?

電腦只能識別二進位的語言,0和1,高級語言在程式運行時需要執行的操作是編譯和鏈接,高級語言需要編譯為彙編語言,彙編語言再通過鏈接生成二進位的機器碼,也就是機器語言,電腦才能識別。程式在運行時執行的這兩步操作統稱為運行時。Runtime~

二、動態功能

程式在編譯和鏈接時確定對象類型和方法解析,這些操作都是在動態完成的,稱為動態功能。

三、對象消息

對象消息,也就是對象發送消息~在OC中對象發送消息用[ ],如下:

[person run]

中括弧之間前面為對象,後面為消息,對象也就是接收器,有的也叫作加法器,是消息傳遞的目的地。消息是由選擇器和參數構成,也可以說由加數構成。如下圖所示~

四、選擇器

在Objective-C的消息傳遞中,選擇器是一種文本字元串,用於指明調用對象或類中的哪個方法。選擇器是一種分為多段的文本字元串,每個字元串以冒號分割,冒號後接參數~

五 SEL類型

SEL是Objective-C中的一種特殊的數據類型,它叫做選擇器類型,SEL。用於編譯時替換選擇器的唯一標識~具有相同選擇器值的方法都擁有相同的SEL標識符,Objective-C在運行時會確保每一個選擇器標識的唯一性。

5.1 SEL類型的創建

使用關鍵字@selector創建SEL類型的變數,用於描述消息選擇器和參數的類型,例如~

SEL myMethod = @selector(myMethod)

5.2 SEL類型的用處

在Objective-C中,有一些方法需要用選擇器作為參數,這時候就需要用到SEL類型~如下:

[button addTarget:self action:@selector(didClickButton:) forControlEvents:UIControlEventTouchUpInside];

在這裡,SEL類型的選擇器@selector(didClickButton:)作為參數傳遞給方法addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents,以上例子也可以寫為如下:

SEL selector = NSSelectorFromString(didClickButton:)
[button addTarget:self action:selector forControlEvents:UIControlEventTouchUpInside];

六、方法簽名(method signature)

6.1 什麼是方法簽名?

SEL類型描述了選擇器和參數個數,可是還需要確定參數類型和返回值類型,這時候就有了方法簽名,定義方法輸入的參數類型和方法返回值的數據類型,叫做方法簽名~

6.2 運行時如何實現對象消息傳遞?

編譯器在編譯時會將對象消息轉換為聲明中含有方法簽名的C函數調用語句,,為了生成正確的對象消息傳遞代碼,編譯器將獲得選擇器和方法簽名,編譯器可以從對象消息中拿出SEL類型的選擇器和確定參數,但是編譯器沒有辦法確定參數類型和返回值類型,也就是沒有辦法獲取方法簽名。編譯器為了確定方法簽名,編譯器會根據自己已經解析好的方法聲明進行猜測,如果編譯器找不到方法簽名,或則編譯器從方法聲明中獲取到的方法簽名與運行時實際執行的方法不匹配,會導致程式出現崩潰狀態~下麵演示一個典型錯誤~

6.3 方法簽名不匹配典型錯誤~

下麵定義了兩個類,分別繼承於NSObject,其中都有方法setPersonAge:,當

@interface Person1 : NSObject
-(void)setPersonAge:(int)age;
@end

@interface Person2 : NSObject
-(void)setPersonAge:(NSInteger)age;
@end

七、對象發送消息

首先創建一個Calculator類繼承與NSObejct:

Calculator.h

#import <Foundation/Foundation.h>

@interface Calculator : NSObject

- (NSNumber *) sumAddend1:(NSNumber *)adder1 addend2:(NSNumber *)adder2;

- (NSNumber *) sumAddend1:(NSNumber *)adder1 :(NSNumber *)adder2;

@end

Calculator.m

@implementation Calculator

- (NSNumber *) sumAddend1:(NSNumber *)adder1 addend2:(NSNumber *)adder2 {
NSLog(@"Invoking method on ##%@## object with selector ##%@##",[self className],NSStringFromSelector(_cmd));
return [NSNumber numberWithInteger:(adder1.integerValue + adder2.integerValue)];
}

- (NSNumber *) sumAddend1:(NSNumber *)adder1 :(NSNumber *)adder2 {
NSLog(@"Invoking method on ##%@## object with selector ##%@##",[self className],NSStringFromSelector(_cmd));
return [NSNumber numberWithInteger:(adder1.integerValue + adder2.integerValue)];
}

@end

先解釋一下這句代碼~NSStringFromSelector(_cmd),使用Foundation框架的NSStringFromSelector函數可以獲得一個選擇器的字元串,這個函數輸入的參數是一個SEL類型的變數,這裡輸入的參數是_cmd,那麼其中的_cmd參數是從何而來的叻?_cmd是一個隱式參數(即無需聲明就存在於所有Objective-C方法中的參數),含有被髮送消息中的選擇器,所以~NSStringFromSelector(_cmd)返回被調用方法的選擇器文本字元串~

main.m

#import <Foundation/Foundation.h>
#import "Calculator.h"

int main(int argc, const char * argv[]) {
@autoreleasepool {

    Calculator *cal = [Calculator new];
    NSNumber *num1 = [NSNumber numberWithInteger:1];
    NSNumber *num2 = [NSNumber numberWithInteger:2];
    NSNumber *num3 = [NSNumber numberWithInteger:3];
    
    NSLog(@"%@",[cal sumAddend1:num1 addend2:num2]);
    NSLog(@"%@",[cal sumAddend1:num1 :num3]);
    
    
}
return 0;
}

控制台列印輸出~

2016-04-19 23:55:56.257 Test[2914:1095161] Invoking method on ##Calculator## object with selector ##sumAddend1:addend2:##
2016-04-19 23:55:56.258 Test[2914:1095161] 3
2016-04-19 23:55:56.258 Test[2914:1095161] Invoking method on ##Calculator## object with selector ##sumAddend1::##
2016-04-19 23:55:56.258 Test[2914:1095161] 4
Program ended with exit code: 0

使用performSelector:方法

main.m

#import <Foundation/Foundation.h>
    #import "Calculator.h"

int main(int argc, const char * argv[]) {
@autoreleasepool {

    Calculator *cal = [Calculator new];
    NSNumber *num1 = [NSNumber numberWithInteger:1];
    NSNumber *num2 = [NSNumber numberWithInteger:2];
    NSNumber *num3 = [NSNumber numberWithInteger:3];
    
    SEL selector1 = @selector(sumAddend1:addend2:);
    id sum1 = [cal performSelector:selector1 withObject:num1 withObject:num2];
    NSLog(@"%@",sum1);
    
    SEL selector2 = @selector(sumAddend1::);
    id sum2 = [cal performSelector:selector2 withObject:num1 withObject:num3];
    NSLog(@"%@",sum2);
    
}
return 0;
}

控制台列印~

2016-04-20 00:02:02.220 Test[3011:1117690] Invoking method on ##Calculator## object with selector ##sumAddend1:addend2:##
2016-04-20 00:02:02.221 Test[3011:1117690] 3
2016-04-20 00:02:02.221 Test[3011:1117690] Invoking method on ##Calculator## object with selector ##sumAddend1::##
2016-04-20 00:02:02.221 Test[3011:1117690] 4
Program ended with exit code: 0

在程式運行時,會出現兩條警告~PerformSelector may cause a leak because its selector is unknown,這句話的意思是如果找不到該選擇器,他就崩給你看~,如果您是處女座~您可以選擇選擇添加Pragma指令來去除這兩條警告~

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    
    SEL selector1 = @selector(sumAddend1:addend2:);
    id sum1 = [cal performSelector:selector1 withObject:num1 withObject:num2];
    NSLog(@"%@",sum1);
    
    SEL selector2 = @selector(sumAddend1::);
    id sum2 = [cal performSelector:selector2 withObject:num1 withObject:num3];
    NSLog(@"%@",sum2);
#pragma clang diagnostic pop

使用pragma指令clang diagnostic ignored可以禁用編譯器報出警告~,該指令語法為:#pragma clang diagnostic ignored "診斷功能的名稱",那問題來了~我們怎麼才知道這個診斷功能的名稱叻?OK ~ 看了下圖~你一切都明白了~

OK,Runtime 的基本構造就寫到這裡吧~最後發表一下小小的感言~做程式員多年~每天的工作都是坐著~大家有空沒空還是多多運動~健康很重要~突然想起了一句話~人生苦短~快用Python,哈哈,不是打廣告~最後祝大家身體健康~


Author

Programming by Erma
Blog Erma-king


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一,效果圖。 二,代碼。 RootViewController.m ...
  • 1:iOS 使用NJKWebViewProgress做webview進度條 2:解決輸入框UITextField關於拼音或部首被當作內容響應 這裡主要使用了兩個知識: 輸入法輸入時,拼音字母或者筆畫處於選中狀態,可以使用 markedTextRange 獲取到 普通輸入,以及將輸入法的待選字填入輸入 ...
  • 先把字元串轉換成時間NSDate 然後再把時間轉換成我們需要的時間格式的字元串 其中需要註意的是 EEE 和 MMM 所代表的含義 會隨著 NSDateForMatter 的 Locale 屬性的不同 而改變 當Locale 屬性為 ...
  • 最近在使用iOS的可變數組時出現了一個錯誤,報錯信息為: reason: '-[__NSCFArray removeObjectAtIndex:]: mutating method sent to immutable object' 字面的意思就是可變數組的方法發送給了一個不可變的對象。 聲明和初始 ...
  • 樣式和主題(Styles and Themes) 一個樣式(Style)是一個包含了指定樣子和格式的作用於視圖控制項(View)或者窗體(Window)屬性集合。一個style可以指定很多屬性,比如 高度,填充,字體顏色,字體尺寸,背景色等。一個Style在xml資源文件中定義,並且和在xml中指定的 ...
  • 源文件這裡有http://pan.baidu.com/s/1pLlDm6f UITableView與UISearchController搜索及上拉載入,下拉刷新 ...
  • Swift提供了類似C語言的流程式控制制結構,包括可以多次執行任務的for和while迴圈,基於特定條件選擇執行不同代碼分支的if和switch語句,還有控制流程跳轉到其他代碼的break和continue語句。 除了C裡面傳統的 for 條件遞增迴圈,Swift 還增加了 for-in 迴圈,用來更簡 ...
  • 需求一:將字典轉換成自己需的對象,對象的屬性是字典的key值,直接使用key值獲取數據存在兩個缺點,一是key值難以記憶,二是直接使用key值Xcode不會有智能提示,很容易導致未知的錯誤。使用模型時,可以直接通過點語法將需要的數據點出,保證數據準確無誤。使用模型的優點還在於存儲、傳值都比較方便,不 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...