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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Objective-C Runtime的数据类型

發布時間:2023/12/13 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Objective-C Runtime的数据类型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:http://www.cnblogs.com/whyandinside/archive/2013/02/26/2933552.html

Class

Objective-C是支持反射的,先來了解一下其如何表達一個類。在Objective-C的Runtime中有個類型是Class(只在Runtime環境中使用),用來表示Objective-C中的類,其定義為:

typedef struct objc_class *Class;

可以看出,其實Class類型是一個指針,指向struct ?objc_class,而struct ?objc_class才是保存真正數據的地方,再看struct ?objc_class的聲明(from http://www.opensource.apple.com/source/objc4/objc4-493.9/runtime/runtime.h):

struct objc_class {Class isa;#if !__OBJC2__Class super_class OBJC2_UNAVAILABLE;const char *name OBJC2_UNAVAILABLE;long version OBJC2_UNAVAILABLE;long info OBJC2_UNAVAILABLE;long instance_size OBJC2_UNAVAILABLE;struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;struct objc_method_list **methodLists OBJC2_UNAVAILABLE;struct objc_cache *cache OBJC2_UNAVAILABLE;struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; #endif} OBJC2_UNAVAILABLE;

其中包含了方法列表、父類等信息,詳細的可以稍后再看。

?

Method

是Runtime內部定義的方法,用來代表一個方法,其聲明如下:

typedef struct objc_method *Method;

而struct ?objc_method的聲明如下:

struct objc_method {SEL method_name OBJC2_UNAVAILABLE;char *method_types OBJC2_UNAVAILABLE;IMP method_imp OBJC2_UNAVAILABLE; }

SEL和IMP代表什么需要看下面的內容。如果你已經了解了SEL和IMP的含義,可以看看下面這段:根據Class和Method的定義來理解Objective C中的消息機制:

先看看objc_class中method list的在runtime(http://opensource.apple.com/source/objc4/objc4-437/runtime/objc-runtime-new.h)里的定義:

typedef struct method_list_t {uint32_t entsize_NEVER_USE; // low 2 bits used for fixup markers uint32_t count;struct method_t first; } method_list_t;typedef struct method_t {SEL name;const char *types;IMP imp; } method_t;

SEL相當于char*,可以認為objc_class中method list保存了一個SEL<->IMP的映射,看下面的代碼:

Bird * aBird = [[Bird alloc] init];[aBird fly];

其中對fly的調用,其實是由編譯器插入了一些代碼,根據SEL([aBird fly] 中的fly就是SEL)找到了IMP,從而進行調用的。下面看編譯器插入了什么樣的代碼。我們來看Objective C runtime中跟msg相關的函數:

id objc_msgSend(id theReceiver, SEL theSelector, ...)

這個函數發送消息給theReceiver,并將返回值返回。編譯器其實就是將[aBird fly]轉化成了對objc_msgSend的調用,從而實現消息機制的。objec_msgSend()函數將會使用theReceiver的isa指針來找到theReceiver的類空間結構并在類空間結構中查找theSelector所對應的方法。如果沒有找到,那么將使用指向父類的指針找到父類空間結構進行theSelector的查找。如果仍然沒有找到,就繼續往父類的父類一直找,直到找到為止。如果找不到怎么辦呢?關于消息機制,有一篇引用文章,介紹的更加詳細,這里就不贅述。

?

Ivar

Runtime中用來表示instance variable(實例變量,跟某個對象關聯,不能被靜態方法使用,與之想對應的是class variable),其聲明如下:

typedef struct objc_ivar *Ivar;

而struct objc_ivar的聲明如下:

struct objc_ivar {char *ivar_name OBJC2_UNAVAILABLE;char *ivar_type OBJC2_UNAVAILABLE;int ivar_offset OBJC2_UNAVAILABLE; #ifdef __LP64__int space OBJC2_UNAVAILABLE; #endif } OBJC2_UNAVAILABLE;

Category

Runtime中用來表示Category( link ?),其聲明為:

typedef struct objc_category *Category;

struct objc_category 的定義也在runtime.h文件中。

[]Catagory可以動態地為已經存在的類添加新的行為。這樣可以保證類的原始設計規模較小,功能增加時再逐步擴展。使用Category對類進行擴展時,不需要訪問其源代碼,也不需要創建子類。Category使用簡單的方式,實現了類的相關方法的模塊化,把不同的類方法分配到不同的分類文件中。下面看一個例子:

SomeClass.h @interface SomeClass : NSObject{ } -(void) print; @end

這是類SomeClass的聲明文件,其中包含一個實例方法print。如果我們想在不修改原始類、不增加子類的情況下,為該類增加一個hello的方法,只需要簡單的定義兩個文件SomeClass+Hello.h和SomeClass+Hello.m,在聲明文件和實現文件中用“()”把Category的名稱括起來即可。聲明文件代碼如下:

#import "SomeClass.h"@interface SomeClass (Hello) -(void)hello; @end

實現文件代碼如下:

#import "SomeClass+Hello.h" @implementationSomeClass (Hello) -(void)hello{NSLog (@"name:%@ ", @"Jacky"); } @end

其中Hello是Category的名稱,如果你用XCode創建Category,那么需要填寫的內容包括名稱和要擴展的類的名稱。這里還有一個約定成俗的習慣,將聲明文件和實現文件名稱統一采用“原類名+Category”的方式命名。
調用也非常簡單,毫無壓力,首先引入Category的聲明文件,然后正常調用即可:

#import "SomeClass+Hello.h"SomeClass * sc =[[SomeClass alloc] init]; [sc hello]

執行結果是:
name:Jacky?

Category的使用場景:
1、當你在定義類的時候,在某些情況下(例如需求變更),你可能想要為其中的某個或幾個類中添加方法。
2、一個類中包含了許多不同的方法需要實現,而這些方法需要不同團隊的成員實現
3、當你在使用基礎類庫中的類時,你可能希望這些類實現一些你需要的方法。

遇到以上這些需求,Category可以幫助你解決問題。當然,使用Category也有些問題需要注意,
1、Category可以訪問原始類的實例變量,但不能添加變量,如果想添加變量,可以考慮通過繼承創建子類。
2、Category可以重載原始類的方法,但不推薦這么做,這么做的后果是你再也不能訪問原來的方法。如果確實要重載,正確的選擇是創建子類。
3、和普通接口有所區別的是,在分類的實現文件中可以不必實現所有聲明的方法,只要你不去調用它。

用好Category可以充分利用Objective-C的動態特性,編寫出靈活簡潔的代碼。

?

SEL

Runtime中用來表示一個method selector,其聲明為:

typedef struct objc_selector *SEL;

沒有找到struct objc_selector的定義,有人說是編譯器定義的,GCC 和MacOSX的實現方式還不一樣,不想花時間找GCC的代碼,而且也沒那么重要,所以就先姑且相信這個說法吧。

IMP

IMP是一個函數指針,指向方法的實現,其定義為:

id (*IMP)(id, SEL, ...)

其所指向的方法,返回一個id(Cocoa 對象),需要傳入的第一個參數是self(指向某個對象,或者一個類),第二個參數是方法的SEL。

objc_property_t

objc_method_list

objc_cache

objc_protocol_list

id

在 Objective-C中id類型的對象可以轉換為任何一種對象,有點類似與void *指針類型的作用。下面簡要介紹一下id類型。

id標志符:通用對象類型。id類型是一個獨特的數據類型,可以轉換為任何數據類型,即id類型的變量可以存放任何數據類型的對象。id在objc.h中的定義為:

typedef struct objc_object {Class isa; } *id;

從上面的介紹,我們已經知道Class是struct ?objc_class的指針別名,所以id可以指向一個第一個元素是Class的struct;那么它為什么可以指向NSObject對象呢?下面看NSObject的定義:

@interface NSObject <NSObject> {Class isa; }

可以看出NSObject的第一個對象是Class類型的isa。因為第一個元素相同,也就意味著可以互相cast而不損失信息,下面是用C語言來演示的其實現原理:

#include <stdio.h> #include <stdlib.h> struct objc_class {int count;char * name; };typedef struct objc_class * Class; typedef struct objc_obj0 {Class isa; }*id;typedef struct objc_obj1 {Class isa;int a; }*id1;typedef struct objc_obj2 {Class isa;char *b; }*id2;int main(int argc, char **argv) {// id 的第一個元素與id1是一樣的,所以可以用id指向id1的元素,而不損失任何信息,不過后續使用的時候應該使用其實際類型id a = (struct objc_obj1 *)malloc(sizeof(struct objc_obj1)); id b = (struct objc_obj1 *)malloc(sizeof(struct objc_obj1)); }

實施上,通常而言,這樣使用時編譯器是要report warning的,我們可以在.m文件中加入下面的代碼來驗證:

typedef struct objc_object *id2;id2 = [[NSNumber alloc] initWithInt:(i*3)];

這時是會報incompatible pointer types initializing 'id2' (aka 'struct objc_object *') with an expression of type 'NSNumber *' 的,但id2和id的定義相同,為什么使用id時不會有這個warning呢?因為編譯器對id做了特殊處理,不報warning。這下對id有了更多了解了吧。后續而來的問題就是,為什么可以在id類型上調用一些NSNumber上才有的方法呢?這一部分留到Dynamic Typing and Dynamic binding時再說吧。?

?

http://unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html

http://www.cppblog.com/kesalin/archive/2011/08/15/objc_message.html

http://www.cnblogs.com/chijianqiang/archive/2012/06/22/objc-category-protocol.html

總結

以上是生活随笔為你收集整理的Objective-C Runtime的数据类型的全部內容,希望文章能夠幫你解決所遇到的問題。

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