詳解Objective-C的meta-class

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

比較簡單的一篇英文,重點是講解meta-class。翻譯下,加深理解。

原文標題:What is a meta-class in Objective-C?

原文地址:http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html

?

本篇將會探討一個在Objective-C中相對陌生的概念 -- meta-class。OC中的每一個類都會有一個與之相關聯的meta class,但是你卻幾乎永遠也不會直接使用到,它們始終籠罩著一層神秘的面紗。筆者將以運行時動態創建一個class為引,通過剖析創建的class pair來弄明白到底meta-class是什么以及更深入的了解它對于OC中對象、類的意義。

?

在運行時創建類

以下代碼演示運行時創建一個NSError的子類,同時添加一個實例方法給它:

Class newClass =  objc_allocateClassPair([NSError class], "RuntimeErrorSubclass", 0);  
class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:");  
objc_registerClassPair(newClass);

函數ReportFunction就是添加的實例方法的具體實現,如下:

void?ReportFunction(id?self,?SEL?_cmd)??
{??NSLog(@"This?object?is?%p.",self);??NSLog(@"Class?is?%@,?and?super?is?%@.",[self?class],[self?superclass]);??Class?currentClass?=?[self?class];??for(?int?i?=?1;?i?<?5;?++i?)??{??NSLog(@"Following?the?isa?pointer?%d?times?gives?%p",i,currentClass);??currentClass?=?object_getClass(currentClass);??}??NSLog(@"NSObject's?class?is?%p",?[NSObject?class]);??NSLog(@"NSObject's?meta?class?is?%p",object_getClass([NSObject?class]));??
}??


看起來一切都很簡單,運行時創建類只需要三步:
1、為"class pair"分配空間(使用objc_allocateClassPair).
2、為創建的類添加方法和成員(上例使用class_addMethod添加了一個方法)。

3、注冊你創建的這個類,使其可用(使用objc_registerClassPair)。

?

估計讀者馬上就要問:什么是“class pair"? objc_allocateClassPair只返回一個值:Class。那么pair的另一半在哪里呢?

是的,估計你已經猜到了這個另一半就是meta-class,也就是這篇短文的標題,但是要解釋清楚它是什么,為什么需要它,還需要交代下OC的對象與類的相關背景。

?

一個數據結構何以成為一個對象?

每個對象都會有一個它所屬的類。這是面向對象的基本概念,但是在OC中,這對所有數據結構有效。任何數據結構,只要在恰當的位置具有一個指針指向一個class,那么,它都可以被認為是一個對象。
在OC中,一個對象所屬于哪個類,是由它的isa指針指向的。這個isa指針指向這個對象所屬的class。

實際上,OC中對象的定義是如下的樣子:


typedef?struct?objc_object?{??Class?isa;??
}*id;?

?

這個定義表明:任何以一個指向Class的指針作為首個成員的數據結構都可以被認為是一個objc_object.

最重要的特性就是,你可以向OC中的任何對象發送消息,如下這樣:

【@”stringValue"?writeToFile:@"/file.txt?atomically:YES?
encoding:?NSUTF8StringEncoding?error:NULL];??

?

運行原理就是,當你向一個OC對象發送消息時(上文的@“stringValue”),運行時庫會根據對象的isa指針找到這個對象所屬的類(上文為例,會找到NSCFString類).這個類會包含一個所有實例方法的列表及一個指向superclass的指針以便可以找到父類的實例方法。運行時庫會在類的方法列表以及父類(們)的方法列表中尋找符合這個selector(上文為例,這個selector是"writeToFile:atomically:encoding:error")的方法。找到后即運行這個方法。關鍵點就是類要定義這個你發送給對象的消息。


什么是meta-class?
至此,你可能已經知道,一個OC的類其實也是一個對象,意思就是你可以向一個類發送消息。

NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];


在這個例子中,defaultStringEncoding 被發送給了NSString類。因為每一個OC的類本身也是一個對象。也就是說Class的數據結構必然也是以isa指針開始的在二進制級別上與objc_object是完全兼容的。然后一個類結構的下一個字段一定是一個指向super class的指針(或者指向nil,對于基類而言)。
一個類如何定義有很多方法,依賴于你的運行時庫版本,但是不管哪種方法,他們都是以一個isa作為第一個字段,接著是superclass字段。


typedef?struct?objc_class?*Class;??
struct?objc_class{??Class?isa;??Class?super_class;??/*followed?by?runtime?specific?details...*/??
};??

?

為了可以調用類方法,這個類的isa指針必須指向一個包含這些類方法的類結構體。
這樣就引出了meta-class的概念:meta-class是一個類對象的類。
簡單解釋下:
? ? ? ?當你向一個對象發送消息時,runtime會在這個對象所屬的那個類的方法列表中查找。
? ? ? ?當你向一個類發送消息時,runtime會在這個類的meta-class的方法列表中查找。
meta-class之所以重要,是因為它存儲著一個類的所有類方法。每個類都會有一個單獨的meta-class,因為每個類的類方法基本不可能完全相同。


meta-class的類又是什么呢?


meta-class,就像Class一樣,也是一個對象。你依舊可以向它發送消息調用函數,自然的,meta-class也會有一個isa指針指向其所屬類。所有的meta-class使用基類的meta-class作為他們的所屬類。具體而言,任何NSObject繼承體系下的meta-class都使用NSObject的meta-class作為自己所屬的類。
根據這個規則,所有的meta-class使用基類的meta-class作為它們的類,而基類的meta-class也是屬于它自己,也就是說基類的meta-class的isa指針指向它自己。(譯:完美的閉環)


類和meta-class的繼承


就像一個類使用super_class指針指向自己的父類一樣,meta-class的super_class會指向類的super_class的meta-class。一直追溯到基類的meta-class,它的super_class會指向基類自身。(譯:萬物歸根)
這樣一來,整個繼承體系中的實例、類和meta-class都派生自繼承體系中的基類。對于NSObject繼承體系來說,NSObject的實例方法對體系中所有的實例、類和meta-class都是有效的;NSObject的類方法對于體系中所有的類和meta-class都是有效的。
用文字描述總會讓人迷糊,Greg Parker給出了一份精彩的圖譜來展示這些關系:
點擊打開鏈接


實驗證明:


為了證實以上的論述,讓我們查看下開篇代碼中ReportFunction的輸出。這個函數的目的就是沿著isa指針進行打印。
為了運行ErportFunction,我們需要創建一個實例,并調用report方法。


id?instanceOfNewClass?=?[[newClass?alloc]initWithDomain:@"some?Domain"?code:0?userInfo:nil];??
[instanceOfNewClass?performSelector:@"report)];??
[instanceOfNewClass?release];??



因為我們并沒有對report方法進行聲明,所以我們使用performSelector進行調用,這樣避免編譯器警告。

然后ReportFunction函數會沿著isa進行檢索,來告訴我們class,meta-class以及meta-class的class是什么樣的情況:

?

【注:ReportFunction使用object_getClass來獲取isa指針指向的類,因為isa指針是一個受保護成員,你不能直接訪問其他對象的isa指針。ReportFunction沒有使用class方法是因為在一個類對象上調用這個方法是無法獲得meta-class的,它只是返回這個類而已。(所以[NSString class]只是返回NSString類,而不是NSString的meta-class]
以下是程序的輸出:


This?object?is?0x10010c810.??
Class?is?RuntimeErrorSubclass,?and?super?is?NSError.??
Followingthe?isa?pointer?1times?gives?0x10010c600??
Followingthe?isa?pointer?2times?gives?0x10010c630??
Followingthe?isa?pointer?3times?gives?0x7fff71038480??
Followingthe?isa?pointer?4times?gives?0x7fff71038480??
NSObject's?class?is?0x7fff710384a8??
NSObject's?meta?class?is?0x7fff71038480??

?

觀察通過isa獲得的地址:
對象的地址是 ? ? ?0x10010c810.
類的地址是 ? ? ? ? 0x10010c600.
類的meta-class地址是 ?0x10010c630.
類的meta-class的類地址是 ? ? ? ? ? ? ? ? 0x7fff71038480.(即NSOjbect的meta-class)
NSObject的meta-class的類地址是它自身。
這些地址的值并不重要,重要的是它們說明了文中討論的從類到meta-class到NSObject的meta-class的整個流程。


結論:


meta-class是類對象的類,每個類都有自己單獨的meta-class。所有的類對象并不會屬于同一個meta-class。
meta-class要保證類對象具有繼承體系中基類的所有實例和類方法,以及繼承體系中的所有中間類方法。對于所有NSObject繼承體系下的類,NSObject的實例方法和協議方法對他們和他們meta-class的對象都要有效。
所有的meta-class使用基類的meta-class作為自己的基類,對于頂層基類的meta-class也是一樣,只是它指向自己而已

轉載于:https://my.oschina.net/mexiaobai1315/blog/878712

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282367.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282367.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282367.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Nginx 模塊的使用

Nginx模塊的使用,就是在Nginx配置文件中的http、server、location中添加參數&#xff0c;進行多一項或幾項處理一、 實現響應內容替換 1、sub_module二、Nginx的請求限制 1、連接頻率限制 limit_conn_module 2、請求頻率限制 limit_req_module 注: HTTP請求建立在一次…

Question | 網站被黑客掃描撞庫該怎么應對防范?

本文來自網易云社區在安全領域向來是先知道如何攻&#xff0c;其次才是防。針對題主的問題&#xff0c;在介紹如何防范網站被黑客掃描撞庫之前&#xff0c;先簡單介紹一下什么是撞庫。撞庫是黑客通過收集互聯網已泄露的用戶和密碼信息&#xff0c;生成對于的字典表&#xff0c;…

十倍程序員 | 使用 Source Generator 將 JSON 轉換成 C# 類

前言有時候&#xff0c;我們需要將通過 WebAPI 接收 JSON 字符串轉換成 C# 代碼。Visual Studio 提供了一個功能菜單可以輕松實現&#xff1a;執行完成后&#xff0c;它會將生成的代碼放在打開的的代碼窗口中。但是&#xff0c;如果有多個 JSON 字符串需要轉換&#xff0c;這個…

Delphi對話框初始地址InitialDir

我的電腦&#xff1a;SaveDialog1.InitialDir : ::{20D04FE0-3AEA-1069-A2D8-08002B30309D};// My Computer {20D04FE0-3AEA-1069-A2D8-08002B30309D}// Network Neighborhood {208D2C60-3AEA-1069-A2D7-08002B30309D}// Recycled {645FF040-5081-101B-9F08-00AA002F954E} 另外…

[python] 解決pip install download速度過慢問題 更換豆瓣源

""" python建立pip.ini.py 2016年4月30日 03:35:11 codegay """import osini"""[global] index-url https://pypi.doubanio.com/simple/ [install] trusted-hostpypi.doubanio.com """ pippathos.environ["…

Maven組件通過命令上傳本地和私有倉庫

安裝本地包到本地倉庫&#xff1a;mvn install:install-file -DgroupIdcom.xxx -DartifactIdmqtt-server-client -Dversion1.0.1 -Dpackagingjar -DfileE:\__vdt\MVVP\mqtt-server-client-1.0.1.jar -DpomFileE:\__vdt\MVVP\pom.xml安裝本地包到私有倉庫&#xff1a;mvn deploy…

Nginx -靜態資源Web服務

一、靜態資源類型 注&#xff1a;非服務器動態生成的文件 1、瀏覽器端渲染 HTML、css、js 2、圖片 jpeg、gif、png 3、視頻 flv、MPEG 4、文件 TXT、等任意下載文件二、靜態資源服務配置1、配置語法-文件讀取 syntax&#xff1a;sendfile on|off default&#xff1a;sendfi…

微軟Microsoft Azure 機器學習工作室的案例之Image Classification using DenseNet

點擊上方藍字關注我們&#xff08;本文閱讀時間&#xff1a;10分鐘)Microsoft Azure Machine Learning Studio是微軟強大的機器學習平臺&#xff0c;在設計器中&#xff0c;微軟內置了15個場景案例&#xff0c;但網上似乎沒有對這15個案例深度刨析的分析資料&#xff0c;所以我…

java小基礎之instanceof運算符

instanceof主要用來判斷一個類是否實現了某個接口&#xff0c;或者判斷一個實例對象是否屬于一個類。 1. 判斷一個對象是否屬于一個類 boolean result p instanceof Student; 2. 對象類型強制轉換前的判斷 Person p new Student(); //判斷對象p是否為Student類的實例 if(p in…

音樂分類

代碼&#xff1a; 1 import numpy as np2 from scipy import fft3 from scipy.io import wavfile4 from sklearn.linear_model import LogisticRegression5 import random6 """7 使用logistic regression處理音樂數據&#xff0c;音樂數據訓練樣本的獲得是使…

Problem C: 類的初體驗(III)

Description 定義一個類Data&#xff0c;只有一個double類型的屬性和如下4個方法&#xff1a; 1. 缺省構造函數&#xff0c;將屬性初始化為0&#xff0c;并輸出“Initialize a data 0”。 2. 帶參構造函數&#xff0c;將屬性初始化為指定參數&#xff0c;并輸出“Initialize…

Nginx- 實現跨域訪問

一、什么是跨域 跨域&#xff1a;由于瀏覽器的同源策略&#xff0c;即屬于不同域的頁面之間不能相互訪問各自的頁面內容。詳細見下表&#xff1a; 注&#xff1a;同源策略&#xff0c;單說來就是同協議&#xff0c;同域名&#xff0c;同端口 URL說明是否允許通信http://www.a…

不管對不對,先把鬧鐘關了再說

小榆提前關閉早上鬧鐘&#xff0c;幾乎工作日的早晨都是被這魔怔的鈴聲給拉扯醒&#xff0c;無論有多么不愿還是痛苦&#xff0c;可對這鬧鐘也無可奈何&#xff0c;就算一時果斷掐掉接下來是另一回麻煩事。最后一天&#xff0c;已經顧不得多少&#xff0c;沒什么令人懼怕的人或…

pycharm(windows)安裝及其設置中文菜單

pycharm&#xff08;windows&#xff09;安裝及其設置中文菜單 1.下載 在官網&#xff08;http://www.jetbrains.com/pycharm/download/#sectionwindows&#xff09;進行下載 或者到百度云進行下載 專業版&#xff1a;鏈接&#xff1a;http://pan.baidu.com/s/1bSSRds 密碼&…

Tomcat定義虛擬主機案例

Tomcat定義虛擬主機案例 作者&#xff1a;尹正杰 版權聲明&#xff1a;原創作品&#xff0c;謝絕轉載&#xff01;否則將追究法律責任。 一.準備環境 1>.創建web程序的根目錄 [rootyinzhengjie ~]# mkdir -pv /home/yinzhengjie/data/www/webapps/ROOT mkdir: created direc…

node服務成長之路

我們的系統也從第一代平臺開始到現在第四代平臺更換中&#xff0c;對這四代平臺做一個簡單的介紹&#xff1a; 第一代平臺&#xff0c;主要是集中式&#xff0c;以快速上線為目的&#xff1b;第二代平臺主要是分布式改造&#xff0c;緩解各服務壓力&#xff1b;第三代平臺主要做…

將域名綁定到ip上,并實現訪問不同二級子域名對應不同目錄

一、將域名綁定到ip上1、環境介紹&#xff1a;阿里云服務器ESC&#xff08;美國硅谷&#xff09; 2、購買域名 3、備案 注&#xff1a;由于我買的是美國地區服務器&#xff0c;所以不用備案&#xff0c;如果買的國內服務器&#xff0c;這里需要添加一個備案操作。 4、域名實名認…

ABP vNext微服務架構詳細教程(補充篇)——單層模板(中)

框架搭建2聚合服務這里我們將聚合服務命名為Domain.Core和基礎服務層一致&#xff0c;我們先通過命令創建單層模板項目Domain.Core&#xff0c;這里我們刪除wwwroot、Data、Entities、Localization、ObjectMapping文件夾及其所有子文件&#xff0c;并刪除package.json文件和Ser…

談一談synchronized關鍵詞

1.使用 java中的每一個對象都可以作為synchronized的鎖進行代碼同步&#xff0c;常見的形式 同步代碼塊鎖是synchronized括號內的對象普通成員方法上&#xff0c;鎖是當前的對象&#xff0c;synchronized(this)靜態方法上&#xff0c;鎖是當前類的Class對象2. 原理 synchronize…

系統學習redis之二——redis集群搭建

redis單點部署&#xff1a; 安裝命令&#xff1a; # cd /usr/local/ # wget http://download.redis.io/releases/redis-4.0.1.tar.gz #下載安裝包 # yum -y install gcc psmisc #安裝依賴包 # tar xf redis-4.0.1.tar.gz # cd /usr/lo…