歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Objective-C中的meta-class

討論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