歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Objective-C中的meta-class

Objective-C中的meta-class

日期:2017/3/1 9:43:55   编辑:Linux編程

討論Objective-C的一個奇怪的概念 meta-class

在Objective-C中的每個類,都有它自己相關的meta-class,但因為你很少直接使用meta-class,所以顯得很神秘。

在運行時建立一個類

下面的代碼在運行時創建一個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]));
}

表面上,這都很簡單。在運行時創建一個新類,只需要3步

1)為 class pair分配存儲空間 (使用objc_allocateClassPair)

2)增加需要的方法和ivars(使用class_addMethod來添加方法)

3) 注冊這個類,以便它能被別人使用(objc_registerClassPair)

現在的問題是,什麼是class pair, 函數objc_allocateClassPair只返回一個值:the class

那麼pair的另外一半在哪裡呢?你可能已經猜到另外一般就是meta-class(也就是本文的主題)

一個數據結構需要哪些東西才能成為一個對象

每個對象都有一個類,這是一個基本的面向對象的概念。

在Objective-C中,任何數據結構,如果在正確的位置有一個指向類的指針,就能被視為一個對象。

在Objective-C中,一個對象的類,由它的isa指針決定。這個isa指針指向 對象的類。

事實上,一個對象的基本定義是這樣的:

typedef struct objc_object {

Class isa;

} *id;

這就是說,任何以一個指向Class結構的指針開始的結構,都能被當作objc_object

對象最重要的特性,就是你可以給它們發送消息:

[@"stringValue"

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


當你發送消息給一個Objective-C對象時(比如這裡的NSCFString), 運行時(runtime) 通過對象的isa指針得到對象的Class(這裡是NSCFString類),而Class裡含有那些可以應用這個類的所有對象上的所有方法的列表,以及指向superclass的指針。運行時通過類的方法列表和超類,來發現一個能同消息選擇子匹配的方法(上面的例子中,就是在NSString類中的writeToFile:atomically:encoding:error方法)。

要點就是:類定義了那些消息,你只能發送那些已經定義好的消息給它的對象

什麼是meta-class

現在,你可能已經知道,在Objective-C中,一個類也是一個對象。這意味著,你也可以發送消息給一個類

NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];

在這種情況下, defaultStringEncoding被發送給NSString類

在Objective-C 中,每個類,都是一個對象。也就是說,類結構也必須以isa指針開始,這樣,它才同objc_object結構二進制兼容

在結構裡的第2個項目,必須是superclass的指針(如果是基類,沒有父類的話,設置為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是一個類對象的類

簡單地說,

當你發送一條消息給一個對象時,這條消息會在對象的類的方法列表裡查找

當你發送一條消息給一個類時,就會在類的meta-class的方法列表理查找消息

meta-class是必不可少的,因為它存儲了一個類的類 方法。每個類都必須只有唯一的meta-class,因為每個類都只可能有一個唯一的類方法列表。

meta-class的類又是什麼呢?

meta-class,跟 類一樣,它也是一個對象。這意味著,你也可以在它上面調用方法。自然地,這意味這,它也必須有一個類。

所有的meta-class都使用基類的meta-class(在它們的繼承體系中,最頂層的類的meta-class)作為它們自己的類。這意味著,所有從NSObject繼承來的類,它們的meta-class都將NSObject的meta-class作為自己的類

遵循這個規則,所有的meta-class使用基類的meta-class作為它們自己的類,任何base meta-class都將是它自己的類(它們的isa指針指向它們自己)。也就是說,在 NSObject的meta-class的isa指針將指向它自己(它是自己的一個實例)

類和 meta-class的繼承

同樣的方式,類用super_class 指針指向超類,meta-class使用它自己的super_class指向 類的super-class的meta-class

巧合地是,基類的meta-class設置它的 super_class 為基類自己。


用實驗來驗證我們的想法

為了確認這些情況,我們看看ReportFunctional的輸出。 這個函數的目的是 追蹤isa指針,並記錄在哪裡找到的它。

為了運行ReportFunction,我們需要建立這個動態創建的類的實例,然後調用它的report方法

id instanceOfNewClass =

[[newClass alloc] initWithDomain:@”someDomain” code:0 userInfo:nil];

[instanceOfNewClass performSelector:@selector(report)];

[instanceOfNewClass release];

因為沒有report方法的聲明,我使用performSelector:來調用它,所以編譯不會給出什麼警告

ReportFunction將遍歷isa指針,告訴我們那些對象被當成類,meta-class,以及meta-class的類 來使用

取得一個對象的類:ReportFunction將使用object_getClass來追蹤isa指針, 因為isa指針是類的一個被保護的成員(你不能直接訪問其他類的isa指針)

ReportFunction不使用類方法來實現這個,因為調用一個類對象的類方法,將不會返回meta-class. 而是再次返回這個類(所以[NSString class]將返回NSString類,而不是NSString的meta-class)

結論:

meta-class是類對象的類。每個類都有它自己唯一的meta-class(因為每個類都有它自己唯一的方法列表)

Objective-C中@property的所有屬性詳解 http://www.linuxidc.com/Linux/2014-03/97744.htm

Objective-C 和 Core Foundation 對象相互轉換的內存管理總結 http://www.linuxidc.com/Linux/2014-03/97626.htm

使用 Objective-C 一年後我對它的看法 http://www.linuxidc.com/Linux/2013-12/94309.htm

10個Objective-C基礎面試題,iOS面試必備 http://www.linuxidc.com/Linux/2013-07/87393.htm

Objective-C適用C數學函數 <math.h> http://www.linuxidc.com/Linux/2013-06/86215.htm

Copyright © Linux教程網 All Rights Reserved