Runtime 學(xué)習(xí)筆記

Runtime

1.對(duì)象和類(lèi)

Objective-C類(lèi)是由Class類(lèi)型來(lái)表示的菌赖,它實(shí)際上是一個(gè)指向objc_class結(jié)構(gòu)體的指針鹰霍。它的定義如下:

typedef struct objc_class *Class;

在objc/runtime.h中挖炬,struct objc_class 的定義如下:

struct objc_class {
    Class isa;//元類(lèi)
    #if !__OBJC2__
    Class super_class//父類(lèi)                    OBJC2_UNAVAILABLE;
    long version//版本信息                      OBJC2_UNAVAILABLE;
    long info//類(lèi)信息                           OBJC2_UNAVAILABLE;
    long instance_size//實(shí)例變量大小             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//協(xié)議  OBJC2_UNAVAILABLE;
    #endif
} OBJC2_UNAVAILABLE;

雖然這個(gè)結(jié)構(gòu)體已經(jīng)過(guò)時(shí)了,但是還是有參考的意義怀樟,比起最新的版本更好理解绽慈。

由于 objc_class 也有 isa 指針,所以類(lèi)本身也是一個(gè)對(duì)象媒吗。

下面就根據(jù)runtime提供的一些辦法仑氛,使用簡(jiǎn)單的例子來(lái)探窺其究竟:

//首先創(chuàng)建一個(gè)測(cè)試類(lèi)
#import <Foundation/Foundation.h>

@interface MyRuntimeTestClass : NSObject

@property (nonatomic, strong) NSArray *array;
@property (nonatomic, copy) NSString *string;

- (void)method1;
- (void)method2;
+ (void)classMethod1;
@end

#import "MyRuntimeTestClass.h"

@interface MyRuntimeTestClass ()
{
    NSInteger _instance1;
    NSString *_instance2;
}

@property (nonatomic, assign) NSInteger *integer;

- (void)method3WithArg1:(NSInteger)arg1 arg2:(NSString *)arg2;

@end

@implementation MyRuntimeTestClass

+(void)classMethod1
{
    
}

-(void)method1
{
    NSLog(@"call the method1");
}

-(void)method2
{
    NSLog(@"call the method2");
}

- (void)method3WithArg1:(NSInteger)arg1 arg2:(NSString *)arg2 {
    NSLog(@"arg1 : %ld, arg2 : %@", arg1, arg2);
}

@end
//測(cè)試類(lèi)和對(duì)象
-(void)testMyRuntimeTestClass
{
    MyRuntimeTestClass *obj = [[MyRuntimeTestClass alloc]init];
    self.myRuntimeTestClass = obj;
    unsigned int outCount = 0;
    Class cls = obj.class;
    
    NSLog(@"class name :%s",class_getName(cls));
    NSLog(@"==========================================================");

    NSLog(@"super class name :%s",class_getName(class_getSuperclass(cls)));
    NSLog(@"==========================================================");
    
    Class metaClass = objc_getMetaClass(class_getName(cls));
    NSLog(@"%s metaClass name:%s",class_getName(cls),class_getName(metaClass));
    NSLog(@"==========================================================");
    
    NSLog(@"%s is %@ a metaClass",class_getName(cls),class_isMetaClass(cls) ? @"" : @"not");
    NSLog(@"==========================================================");
    
    NSLog(@"class size:%zu",class_getInstanceSize(cls));
    NSLog(@"==========================================================");
    
    // 成員變量
    Ivar *ivars = class_copyIvarList(cls, &outCount);//獲取整個(gè)成員變量列表
    for (int i = 0; i < outCount; i++) {
        Ivar ivar = ivars[i];
        NSLog(@"instance variable's name:%s at index:%d",ivar_getName(ivar),i);
    }
    free(ivars);
    
    Ivar array = class_getInstanceVariable(cls, "_array"); //獲取類(lèi)中指定名稱(chēng)實(shí)例成員變量的信息
    if (array != NULL) {
        NSLog(@"instance variable's %s",ivar_getName(array));
    }
    NSLog(@"==========================================================");
    
    // 屬性操作
    objc_property_t *properties = class_copyPropertyList(cls, &outCount);
    for (int i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        NSLog(@"property's name: %s",property_getName(property));
    }
    free(properties);
    
    objc_property_t string = class_getProperty(cls, "_string");
    if (string != NULL) {
        NSLog(@"property %s",property_getName(string));
    }
    NSLog(@"==========================================================");
    
    // 方法操作
    Method *methods = class_copyMethodList(cls, &outCount);
    for (int i = 0; i < outCount; i++) {
        Method method = methods[i];
        NSLog(@"method's signature:%s",sel_getName(method_getName(method)));
    }
    free(methods);
    
    Method method1 = class_getInstanceMethod(cls, @selector(method1));
    if (method1 != NULL) {
        NSLog(@"instand method %s",sel_getName(method_getName(method1)));
    }
    
    Method classMethod = class_getClassMethod(cls, @selector(classMethod1));
    if (classMethod != NULL) {
        NSLog(@"class method %s",sel_getName(method_getName(method1)));
    }
    
    IMP imp = class_getMethodImplementation(cls, @selector(method1));
    IMP imp2 = method_getImplementation(class_getInstanceMethod(cls, @selector(method1)));
    
    imp();
    imp2();
    NSLog(@"==========================================================");

    /**
     *  1.成員變量和屬性: (1) 成員變量?jī)?nèi)部使用,屬性外部使用闸英,屬性是為了讓類(lèi)外能夠訪(fǎng)問(wèn)到成員變量锯岖,即是屬性是外部訪(fǎng)問(wèn)成員變量的接口。
     (2)類(lèi)的變量包含成員變量和屬性甫何,成員變量就好似一個(gè)人的自己固有的屬性(如大腦出吹,眼睛等等),屬性是一個(gè)人的外部特征(如他的名字辙喂,職業(yè)等等)捶牢。
     (3)只要@property 聲明了成員變量,SDK自動(dòng)生成成員變量巍耗,不要需要手動(dòng)對(duì)應(yīng),是專(zhuān)用于從類(lèi)外部對(duì)其進(jìn)行調(diào)用或賦值的.
     (4)成員變量命名方式:_變量名
     2.@property:自動(dòng)創(chuàng)建setter and getter
     3.類(lèi)對(duì)象和類(lèi)的實(shí)例(即對(duì)象):
     */
}

根據(jù)上面的一些例子秋麸,我們來(lái)看看元類(lèi):

1413628797629491
1413628797629491
/**
 *  測(cè)試NSObject
 */
-(void)testNSObject
{
    NSObject *obj = [[NSObject alloc]init];
    Class cls = obj.class;//typedef struct objc_class *Class;
    
    NSLog(@"NSObject name is %s",class_getName(cls));
    NSLog(@"NSObject super class name is %s",class_getName(class_getSuperclass(cls)));// object super isa
    NSLog(@"NSObject metaClass name is %s",class_getName(objc_getMetaClass(class_getName(cls))));// object isa
}

2.方法和消息

selector:

常說(shuō)的方法或是選擇子,其實(shí)質(zhì)就是函數(shù)的指針炬太,根據(jù) selector 可以找到對(duì)應(yīng)的辦法灸蟆。Objective-C在編譯時(shí),會(huì)依據(jù)每一個(gè)方法的名字娄琉、參數(shù)序列次乓,生成一個(gè)唯一的整型標(biāo)識(shí)(Int類(lèi)型的地址),這個(gè)標(biāo)識(shí)就是SEL孽水。

IMP

IMP實(shí)際上是一個(gè)函數(shù)指針票腰,指向方法實(shí)現(xiàn)的首地址,是一個(gè)函數(shù)實(shí)現(xiàn)的入口女气。

辦法的調(diào)用:

Objective-C 語(yǔ)言中杏慰,消息直到運(yùn)行時(shí)才被綁定起來(lái)。編譯器會(huì)將消息表達(dá)式[receiver message]轉(zhuǎn)化為一個(gè)消息函數(shù)的調(diào)用,即objc_msgSend

這個(gè)函數(shù)完成了動(dòng)態(tài)綁定的所有事情:

  1. 首先它找到selector對(duì)應(yīng)的方法實(shí)現(xiàn)缘滥。因?yàn)橥粋€(gè)方法可能在不同的類(lèi)中有不同的實(shí)現(xiàn)轰胁,所以我們需要依賴(lài)于接收者的類(lèi)來(lái)找到的確切的實(shí)現(xiàn)。
  2. 它調(diào)用方法實(shí)現(xiàn)朝扼,并將接收者對(duì)象及方法的所有參數(shù)傳給它赃阀。
  3. 最后,它將實(shí)現(xiàn)返回的值作為它自己的返回值擎颖。
messaging1.gif

獲取辦法的地址

該方式就類(lèi)似 C 語(yǔ)言的函數(shù)調(diào)用榛斯,直接找到函數(shù)的地址。一般情況下不會(huì)使用該方式搂捧,只有在比較頻繁調(diào)用某個(gè)函數(shù)的時(shí)候才會(huì)使用該方式驮俗。即使 OC 中使用了辦法緩存機(jī)制,如果一個(gè)辦法頻繁調(diào)用允跑,根據(jù)緩存列表王凑,快速找到相應(yīng)的辦法和辦法實(shí)現(xiàn),也是有一定的時(shí)間的聋丝。

/**
 *  直接獲取辦法的地址:有cocoa框架提供索烹,并非 Objective-C 語(yǔ)言的特性 (一個(gè)辦法比較頻繁調(diào)用才會(huì)使用該辦法,相當(dāng)于直接調(diào)用函數(shù))
 */
-(void)testGetMethodAdress
{
    void (*setter)(id, SEL, BOOL);
    setter = (void (*)(id, SEL, BOOL))[MyRuntimeTestClass methodForSelector:@selector(method1)];
    for (int i = 0 ; i < 1000 ; i++)
        setter(self, @selector(method1), YES);
}

消息轉(zhuǎn)發(fā)

當(dāng)對(duì)象接收到無(wú)法解讀的消息后弱睦,就會(huì)啟動(dòng)”消息轉(zhuǎn)發(fā)“术荤。消息轉(zhuǎn)發(fā)分三個(gè)階段:動(dòng)態(tài)解析,備用接收者每篷,完整的消息轉(zhuǎn)發(fā)。

動(dòng)態(tài)解析:

該方式是當(dāng)對(duì)象接收到無(wú)法解讀的消息后端圈,會(huì)調(diào)用 +(BOOL)resolveInstanceMethod:(SEL)sel焦读,

+(BOOL)resolveClassMethod:(SEL)sel

這兩個(gè)辦法,這時(shí)候我們可以在該辦法處理對(duì)象無(wú)法解讀的消息舱权。

/**
 *  動(dòng)態(tài)解析:當(dāng)對(duì)象接收到無(wú)法識(shí)別的消息矗晃,首先會(huì)調(diào)用所屬類(lèi)的類(lèi)方法+resolveInstanceMethod:(實(shí)例方法)或者+resolveClassMethod:(類(lèi)方法)
 */
+(BOOL)resolveInstanceMethod:(SEL)sel
{
    NSLog(@"resolveInstanceMethod");
    NSLog(@"can not performSelector called: %@",NSStringFromSelector(sel));
    
    NSString *selectorString = NSStringFromSelector(sel);
    if ([selectorString isEqualToString:@"testMySendMsgOfDymanicMehod"]) {
        class_addMethod(self.class, @selector(testMySendMsgOfDymanicMehod), (IMP)functionForTestMySendMsgOfDymanicMehod, "@:");
    }
    return [super resolveInstanceMethod:sel];;
}
+(BOOL)resolveClassMethod:(SEL)sel
{
    NSLog(@"resolveClassMethod");
    NSLog(@"can not performSelector called: %@",NSStringFromSelector(sel));
    return [super resolveClassMethod:sel];
}
void functionForTestMySendMsgOfDymanicMehod(id self, SEL _cmd)
{
    NSLog(@"the IMP of functionForTestMySendMsgOfDymanicMehod");
}

備用接收者:

當(dāng)?shù)谝徊降膭?dòng)態(tài)解析也無(wú)法解讀未知的消息的時(shí)候,就會(huì)轉(zhuǎn)向備用接收者:-(id)forwardingTargetForSelector:(SEL)aSelector

其實(shí)質(zhì)就是尋找有沒(méi)有其他對(duì)象能解讀該對(duì)象宴倍,即是所謂的備用接收者张症。

/**
 *  備用接收者
 */
-(id)forwardingTargetForSelector:(SEL)aSelector
{
    NSLog(@"forwardingTargetForSelector");
    NSLog(@"can not performSelector called: %@",NSStringFromSelector(aSelector));
    NSString *selectorString = NSStringFromSelector(aSelector);
    if ([selectorString isEqualToString:@"method1"]) {
        
        return self.myRuntimeTestClass;
    }
    return [super forwardingTargetForSelector:aSelector];
}

完整消息轉(zhuǎn)發(fā):

當(dāng)前面兩種方式都不能解讀未知的消息,那就啟用最后一中方式鸵贬,即是將尚未處理的那條消息的有關(guān)的全部細(xì)節(jié)都封裝在 NSInvocation 中俗他,此對(duì)象包含選擇子,目標(biāo)以及參數(shù)阔逼。在觸發(fā) NSInvocation 對(duì)象時(shí)兆衅,“消息派發(fā)系統(tǒng)”將親自出馬,把消息指派給目標(biāo)對(duì)象。

/**
 *  由于完整的消息轉(zhuǎn)發(fā)需要將尚未處理的消息有關(guān)的全部細(xì)節(jié)封裝在NSInvocation中羡亩,故應(yīng)重寫(xiě)該辦法摩疑。
 */
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSLog(@"methodSignatureForSelector:");
    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
    if (!signature) {
        if ([MyRuntimeTestClass instancesRespondToSelector:aSelector]) {
            
            signature = [MyRuntimeTestClass instanceMethodSignatureForSelector:aSelector];
        }
    }
    return signature;
}
/**
 *  完整的消息轉(zhuǎn)發(fā)
 */
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSLog(@"forwardInvocation");
    if ([MyRuntimeTestClass resolveClassMethod:anInvocation.selector]) {
        
        anInvocation.target = self.myRuntimeTestClass;
    }
}

3.辦法交換

有時(shí)候我們需要替換系統(tǒng)的辦法時(shí),比如我想在每次調(diào)用

-(void)viewWillAppear:(BOOL)animated

都打印一段話(huà)畏铆。這樣每個(gè) VC 都碼上打印語(yǔ)句雷袋,未免效率有些不高,這時(shí)候我們就可以使用辦法交換辞居,將我們自己的辦法和系統(tǒng)的辦法交換楷怒。

/**
 *  第一次調(diào)用類(lèi)的類(lèi)方法或?qū)嵗椒ㄖ氨徽{(diào)用
 */
+(void)initialize
{
    NSLog(@"initialize");
}

/**
 *  在類(lèi)初始加載時(shí)調(diào)用
 */
+(void)load
{
    NSLog(@"load");
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class class = [self class];
        
        SEL originalSelector = @selector(viewWillAppear:);
        SEL swizzlingSelector = @selector(YYviewWillAppear:);
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzlingMethod = class_getInstanceMethod(class, swizzlingSelector);
        
        BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzlingMethod), method_getTypeEncoding(swizzlingMethod));
        
        if (didAddMethod) {
            
            //實(shí)現(xiàn)兩個(gè)辦法的實(shí)現(xiàn)部分交換
            class_replaceMethod(class, swizzlingSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        }else{
            
            method_exchangeImplementations(originalMethod, swizzlingMethod);
        }
    });
    
    /*
        1.Selector(typedef struct objc_selector *SEL):用于在運(yùn)行時(shí)中表示一個(gè)方法的名稱(chēng)。一個(gè)方法選擇器是一個(gè)C字符串速侈,它是在Objective-C運(yùn)行時(shí)被注冊(cè)的率寡。選擇器由編譯器生成,并且在類(lèi)被加載時(shí)由運(yùn)行時(shí)自動(dòng)做映射操作倚搬。
     
        2.Method(typedef struct objc_method *Method):在類(lèi)定義中表示方法的類(lèi)型
     
        3. Implementation(typedef id (*IMP)(id, SEL, ...)):這是一個(gè)指針類(lèi)型冶共,指向方法實(shí)現(xiàn)函數(shù)的開(kāi)始位置。這個(gè)函數(shù)使用為當(dāng)前CPU架構(gòu)實(shí)現(xiàn)的標(biāo)準(zhǔn)C調(diào)用規(guī)范每界。每一個(gè)參數(shù)是指向?qū)ο笞陨淼闹羔?self)捅僵,第二個(gè)參數(shù)是方法選擇器。然后是方法的實(shí)際參數(shù)眨层。
     */
}

#pragma mark -method swizzling

-(void)YYviewWillAppear:(BOOL)animated
{
    [self YYviewWillAppear:animated];
    NSLog(@"method had changed!");
}

注:辦法的交換永遠(yuǎn)都應(yīng)該在 load 辦法中實(shí)現(xiàn)庙楚,因?yàn)?load 辦法在類(lèi)初始化的時(shí)候就會(huì)調(diào)用,而 initialize 要在類(lèi)被發(fā)送消息的時(shí)候才會(huì)調(diào)用趴樱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末馒闷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子叁征,更是在濱河造成了極大的恐慌纳账,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捺疼,死亡現(xiàn)場(chǎng)離奇詭異疏虫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)啤呼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)卧秘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人官扣,你說(shuō)我怎么就攤上這事翅敌。” “怎么了醇锚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵哼御,是天一觀(guān)的道長(zhǎng)坯临。 經(jīng)常有香客問(wèn)我,道長(zhǎng)恋昼,這世上最難降的妖魔是什么看靠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮液肌,結(jié)果婚禮上挟炬,老公的妹妹穿的比我還像新娘。我一直安慰自己嗦哆,他們只是感情好谤祖,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著老速,像睡著了一般粥喜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上橘券,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天额湘,我揣著相機(jī)與錄音,去河邊找鬼旁舰。 笑死宪睹,一個(gè)胖子當(dāng)著我的面吹牛巾腕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播膳音,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼菠齿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蚪缀!你這毒婦竟也來(lái)了砰蠢?” 一聲冷哼從身側(cè)響起磅网,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竹捉,沒(méi)想到半個(gè)月后续担,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡活孩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乖仇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片憾儒。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖乃沙,靈堂內(nèi)的尸體忽然破棺而出起趾,到底是詐尸還是另有隱情,我是刑警寧澤警儒,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布训裆,位于F島的核電站眶根,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏边琉。R本人自食惡果不足惜属百,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望变姨。 院中可真熱鬧族扰,春花似錦、人聲如沸定欧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)砍鸠。三九已至扩氢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間爷辱,已是汗流浹背录豺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留托嚣,地道東北人巩检。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像示启,于是被迫代替她去往敵國(guó)和親兢哭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉夫嗓,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,682評(píng)論 0 9
  • 前言 runtime其實(shí)在我們?nèi)粘i_(kāi)發(fā)過(guò)程中很少使用到迟螺,尤其是像我現(xiàn)在比較初級(jí)的程序猿就更用不到了。但是去面試很多...
    WolfTin閱讀 615評(píng)論 0 2
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,544評(píng)論 33 466
  • 我們都知道OC是一門(mén)動(dòng)態(tài)語(yǔ)言舍咖,那么什么是動(dòng)態(tài)語(yǔ)言呢矩父?動(dòng)態(tài)語(yǔ)言,是指程序在運(yùn)行時(shí)可以改變其結(jié)構(gòu):新的函數(shù)可以被引進(jìn)排霉,...
    閆仕偉閱讀 521評(píng)論 0 4
  • 在Objective-C中窍株,消息直到運(yùn)行時(shí)才綁定到方法實(shí)現(xiàn)上。編譯器將消息表達(dá)式[receiver message...
    我系哆啦閱讀 424評(píng)論 0 15