iOS開發(fā) -- Runtime 的幾個小例子

一、什么是 Runtime(也就是所謂的“運行時”欢伏,因為是在運行時實現(xiàn)的曲聂。)

  • 1.Runtime 是一套底層的c語言API(包括很多強大實用的c語言類型,c語言函數(shù)); [runtime運行系統(tǒng)]
  • 2.實際上,平時我們編寫的oc代碼,底層都是基于 Runtime 實現(xiàn)的; [OC語言的動態(tài)性]

運行時系統(tǒng) (runtime system),對于C語言访惜,使用“靜態(tài)綁定”,函數(shù)的調(diào)用在編譯的時候就會決定運行時調(diào)用哪個函數(shù)腻扇。對于OC的函數(shù)债热,屬于“動態(tài)調(diào)用”過程,在編譯的時候并不能決定真正調(diào)用哪個函數(shù)幼苛,只有在真正運行的時候才會根據(jù)函數(shù)的名稱找到對應的函數(shù)來調(diào)用窒篱,甚至可以在運行時改變方法的調(diào)用。Runtime就是OC辛苦的幕后工作人員舶沿。(編譯器會自動幫助我們編譯成 Runtime 代碼墙杯。
動態(tài)特性:使得它在語言層面上支持程序的可擴展性。只有在程序運行時括荡,才會去確定對象的類型畸冲,并調(diào)用類與對象相應的方法。利用runtime機制讓我們可以在程序運行時動態(tài)修改類的具體實現(xiàn)恕沫、包括類中的所有私有屬性婶溯、方法偷霉。這也是本文runtime例子的出發(fā)點类少。
我們所敲入的代碼轉化為運行時的runtime函數(shù)代碼硫狞,最終在程序運行時轉成了底層的runtime的c語言代碼;
舉例
當某個對象使用語法[receiver message]來調(diào)用某個方法時残吩,其實[receiver message]被編譯器轉化為:

id objc_msgSend ( id self, SEL op, ... ); 

也就是說,我們平時編寫的oc代碼泣侮,方法調(diào)用的本質(zhì)活尊,就是在編譯階段,編譯器轉化為向對象發(fā)送消息深胳。


【本次開發(fā)環(huán)境: Xcode:7.2 iOS Simulator:iphone6 By: 啊左
本文Demo下載鏈接:runtime-Demo

二舞终、runtime的幾種使用方法

我們通過繼承于NSObject的person類权埠,來對runtime進行學習。
本文共有6個關于runtime機制方法的小例子龙屉,分別是:

  • 1.獲取person類的所有變量;
  • 2.獲取person類的所有方法唆垃;
  • 3.改變person類的私有變量name的值辕万;
  • 4.為person的category類增加一個新屬性渐尿;
  • 5.為person類添加一個方法砖茸;
  • 6.交換person類的2個方法的功能凉夯;

(個人習慣劲够,喜歡為6個例子添加按鈕各自的行為方法再沧,并分別執(zhí)行相應的行為炒瘸,以此看清各個runtime函數(shù)的具體功能所帶來的效果顷扩。)

首先隘截,創(chuàng)建新的項目婶芭,并在項目中新建一個普通的OC類:person類(繼承于NSObject)犀农,為了避免后面與其他方法函數(shù)搞混呵哨,我們把完整的person類編寫齊全孟害,用于后面使用runtime的幾種方法:
person.h如下:

#import <Foundation/Foundation.h>
@interface person : NSObject
@property (nonatomic,assign)int age;  //屬性變量
-(void)func1;
-(void)func2;
@end

person.m如下:

#import "person.h"
@implementation person{ 
  NSString *name; //實例變量
}
//初始化person屬性
-(instancetype)init{ 
self = [super init]; 
if(self) { 
  name = @"Tom"; 
  self.age = 12; 
} 
return self;
}
//person的2個普通方法
-(void)func1{ 
  NSLog(@"執(zhí)行func1方法挨务。");
}-(void)func2{ 
  NSLog(@"執(zhí)行func2方法谎柄。");
}
//輸出person對象時的方法:
-(NSString *)description{ 
return [NSString stringWithFormat:@"name:%@ age:%d",name,self.age];
}
@end

從person類的描述中,我們可以看到person類含有一個可供外類使用的共有屬性age绒障,以及一個外界不可以訪問私有屬性name,但是庐镐,有木有想過变逃,其實在外類,name也是可以訪問的名眉。OC里面损拢,通過runtime系統(tǒng)荆姆,蘋果允許不受這些私有屬性的限制胆筒,對私有屬性私有方法等進行訪問决乎、添加派桩、修改铆惑、甚至替換系統(tǒng)的方法员魏。
那么,為項目的故事板添加6個按鈕碌补;


在使用runtime的地方厦章,我們都需要包含頭文件:

#import <objc/runtime.h>  //(在需要使用runtime的實現(xiàn)文件.m中包含即可.)

1.獲取person類的所有變量

將第一個按鈕關聯(lián)到ViewController.h袜啃,添加行為并命名其方法為:“getAllVariable”:

- (IBAction)getAllVariable:(UIButton *)sender; //獲取所有變量

在ViewController.m中的實現(xiàn)如下:

/*1.獲取person所有的成員變量*/
- (IBAction)getAllVariable:(UIButton *)sender {
unsigned int count = 0; 
//獲取類的一個包含所有變量的列表群发,IVar是runtime聲明的一個宏熟妓,是實例變量的意思. 
Ivar *allVariables = class_copyIvarList([person class], &count); 
for(int i = 0;i<count;i++) 
{ 
//遍歷每一個變量浪蹂,包括名稱和類型(此處沒有星號"*") 
Ivar ivar = allVariables[i]; 
const char *Variablename = ivar_getName(ivar); //獲取成員變量名稱 
const char *VariableType = ivar_getTypeEncoding(ivar); //獲取成員變量類型 
NSLog(@"(Name: %s) ----- (Type:%s)",Variablename,VariableType); 
}
}

點擊按鈕后告材,得到的輸出如下:(i表示類型為int)

2016-05-18 17:17:10.502 runtime運行時[10164:452725] (Name: name) ----- (Type:@"NSString")
2016-05-18 17:17:10.503 runtime運行時[10164:452725] (Name: _age) ----- (Type:i) 

分析Ivar坤次,一個指向objc_ivar結構體指針,包含了變量名、變量類型等信息斥赋。
可以看到缰猴,私有屬性name能夠訪問到了。 在有些項目中疤剑,為了對某些私有屬性進行隱藏滑绒,某些.h文件中沒有出現(xiàn)相應的顯式創(chuàng)建闷堡,而是如上面的person類中,在.m中進行私有創(chuàng)建,但是我們可以通過runtime這個有效的方法,訪問到所有包括這些隱藏的私有變量。
拓展
class_copyIvarList能夠獲取一個含有類中所有成員變量的列表,列表中包括屬性變量和實例變量。需要注意的是,如果如本例中,age返回的是"_age",但是如果在person.m中加入:@synthesize age;
那么控制臺第二行返回的是"(Name: age) ----- (Type:i) ;"
(因為@property是生成了"_age"箭昵,而@synthesize是執(zhí)行了"@synthesize age = _age;",關于OC屬性變量與實例變量的區(qū)別、@property蝇棉、@synthesize的作用等具體的知識板辽,有興趣的童鞋可以自行了解邑跪。)

如果單單需要獲取屬性列表的話,可以使用函數(shù):class_copyPropertyList();只是返回的屬性變量僅僅是“age”,做為實例變量的name是不被獲取的视粮。
class_copyIvarList()函數(shù)則能夠返回實例變量和屬性變量的所有成員變量。

2.獲取person類的所有方法

將第二個按鈕關聯(lián)到ViewController.h瞬铸,添加行為并命名其方法為:“getAllMethod”:

- (IBAction)getAllMethod:(UIButton *)sender;  //獲取所有方法

在ViewController.m中的實現(xiàn)如下:

/*2.獲取person所有方法*/
- (IBAction)getAllMethod:(UIButton *)sender {
unsigned int count;
//獲取方法列表,所有在.m文件顯式實現(xiàn)的方法都會被找到,包括setter+getter方法菊值; 
Method *allMethods = class_copyMethodList([person class], &count); 
for(int i =0;i<count;i++)
{ 
//Method趟薄,為runtime聲明的一個宏,表示對一個方法的描述 
Method md = allMethods[i]; 
//獲取SEL:SEL類型,即獲取方法選擇器@selector() 
SEL sel = method_getName(md); 
//得到sel的方法名:以字符串格式獲取sel的name也切,也即@selector()中的方法名稱 
const char *methodname = sel_getName(sel); NSLog(@"(Method:%s)",methodname); 
}
}

點擊按鈕后旬痹,控制臺輸出:

2016-05-19 17:05:19.880 runtime運行時[14054:678124] (Method:func1)
2016-05-19 17:05:19.881 runtime運行時[14054:678124] (Method:func2)
2016-05-19 17:05:19.881 runtime運行時[14054:678124] (Method:setAge:)
2016-05-19 17:05:19.881 runtime運行時[14054:678124] (Method:age)
2016-05-19 17:05:19.881 runtime運行時[14054:678124] (Method:.cxx_destruct) 
2016-05-19 17:05:19.882 runtime運行時[14054:678124] (Method:description)
2016-05-19 17:05:19.882 runtime運行時[14054:678124] (Method:init)

控制臺輸出了包括setget等方法名稱〗谠常【備注:.cxx_destruct方法是關于系統(tǒng)自動內(nèi)存釋放工作的一個隱藏的函數(shù)滨嘱,當ARC下囊扳,且本類擁有實例變量時弧轧,才會出現(xiàn);】
分析Method是一個指向objc_method結構體指針,表示對類中的某個方法的描述滑频。在API中的定義:typedef struct objc_method Method;
而objc_method結構體如下:

truct objc_method { 
SEL method_name OBJC2_UNAVAILABLE; 
char *method_types OBJC2_UNAVAILABLE; 
IMP method_imp OBJC2_UNAVAILABLE;
} 
  • method_name :方法選擇器@selector()捡偏,類型為SEL。 相同名字的方法下峡迷,即使在不同類中定義银伟,它們的方法選擇器也相同。
  • method_types:方法類型绘搞,是個char指針彤避,存儲著方法的參數(shù)類型和返回值類型。
  • method_imp:指向方法的具體實現(xiàn)的指針夯辖,數(shù)據(jù)類型為IMP琉预,本質(zhì)上是一個函數(shù)指針。 在第五個按鈕行為“增加一個方法”部分會提到蒿褂。

SEL:數(shù)據(jù)類型圆米,表示方法選擇器,可以理解為對方法的一種包裝啄栓。在每個方法都有一個與之對應的SEL類型的數(shù)據(jù)娄帖,根據(jù)一個SEL數(shù)據(jù)“@selector(方法名)”就可以找到對應的方法地址,進而調(diào)用方法昙楚。
因此可以通過:獲取 Method結構體->得到SEL選擇器名稱->得到對應的方法名 近速,這樣的方式,便于認識OC中關于方法的定義桂肌。

3.改變person對象的私有變量name的值.

將第三個按鈕關聯(lián)到ViewController.h数焊,添加行為并命名其方法為:“changeVariable”:

- (IBAction)changeVariable:(UIButton *)sender;//改變其中name變量

在ViewController.m中創(chuàng)建一個person對象,記得初始化

@implementation ViewController{ 
  person *per; //創(chuàng)建一個person實例
}
- (void)viewDidLoad { 
  [super viewDidLoad]; 
  per = [[person alloc]init]; //記得要初始化...不然后果自己嘗試下
}

在ViewController.m中的實現(xiàn)如下:

/*3.改變person的name變量屬性*/
- (IBAction)changeVariable:(UIButton *)sender {

NSLog(@"改變前的person:%@",per); 

unsigned int count = 0;
Ivar *allList = class_copyIvarList([person class], &count); 
Ivar ivv = allList[0]; //從第一個例子getAllVariable中輸出的控制臺信息崎场,我們可以看到name為第一個實例屬性佩耳。 
object_setIvar(per, ivv, @"Mike"); //name屬性Tom被強制改為Mike。 

NSLog(@"改變之后的person:%@",per);
}

點擊按鈕后谭跨,控制臺輸出:

2016-05-19 22:45:05.125 runtime運行時[1957:34730] 改變前的person:name:Tom age:12
2016-05-19 22:45:05.126 runtime運行時[1957:34730] 改變之后的person:name:Mike age:12

4.為person的category類增加一個新屬性:

如何在不改動某個類的前提下干厚,添加一個新的屬性呢李滴?
答:可以利用runtime為分類添加新屬性
在iOS中蛮瞄,category所坯,也就是分類,是不可以為本類添加新的屬性的挂捅,但是在runtime中我們可以使用對象關聯(lián)芹助,為person類進行分類的新屬性創(chuàng)建:
(其實實際上并不會創(chuàng)建實例變量,只是通過 Runtime 為該類提供屬性的setter/getter 方法)
①新建一個新的OC類:

命名為:PersonCategory 闲先,點擊next


在出現(xiàn)的新類“person+PersonCategory.h”中状土,添加“height”:

#import "person.h"
@interface person (PersonCategory)
@property (nonatomic,assign)float height; //新屬性@end

person+PersonCategory.m”類的代碼如下:

#import "person+PersonCategory.h"
#import <objc/runtime.h> //runtime API的使用需要包含此頭文件

const char * str = "myKey"; //做為key,字符常量 必須是C語言字符串伺糠;

@implementation person (PersonCategory)

-(void)setHeight:(float)height{ 
NSNumber *num = [NSNumber numberWithFloat:height]; 
/* 
第一個參數(shù)是需要添加屬性的對象蒙谓; 
第二個參數(shù)是屬性的key; 
第三個參數(shù)是屬性的值,類型必須為id,所以此處height先轉為NSNumber類型训桶; 
第四個參數(shù)是使用策略累驮,是一個枚舉值,類似@property屬性創(chuàng)建時設置的關鍵字舵揭,可從命名看出各枚舉的意義谤专; 
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
*/ 
objc_setAssociatedObject(self, str, num, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

//提取屬性的值: 
-(float)height{ 
NSNumber *number = objc_getAssociatedObject(self, str);
return [number floatValue];
}
@end

接下來,我們可以在ViewController.m中對person的一個對象進行height的訪問了琉朽,
將第四個按鈕關聯(lián)到ViewController.h添加行為并命名其方法為:“addVariable:”(記得:#import "person+PersonCategory.h"

- (IBAction)addVariable:(UIButton *)sender;

在ViewController.m中的實現(xiàn)如下:

/* 4.添加新的屬性*/
- (IBAction)addVariable:(UIButton *)sender { 
per.height = 12;           //給新屬性height賦值 
NSLog(@"%f",[per height]); //訪問新屬性值
}

點擊按鈕毒租、再點擊按鈕獲取類的屬性箱叁、方法。

2016-05-20 15:39:54.432 runtime運行時[4605:178974] 12.000000
2016-05-20 15:39:56.295 runtime運行時[4605:178974] (Name: name) ----- (Type:@"NSString")
2016-05-20 15:39:56.296 runtime運行時[4605:178974] (Name: _age) ----- (Type:i)
2016-05-20 15:39:57.195 runtime運行時[4605:178974] (Method:func1)
2016-05-20 15:39:57.196 runtime運行時[4605:178974] (Method:func2)
2016-05-20 15:39:57.196 runtime運行時[4605:178974] (Method:setAge:)
2016-05-20 15:39:57.196 runtime運行時[4605:178974] (Method:age)
2016-05-20 15:39:57.196 runtime運行時[4605:178974] (Method:.cxx_destruct)
2016-05-20 15:39:57.197 runtime運行時[4605:178974] (Method:description)
2016-05-20 15:39:57.197 runtime運行時[4605:178974] (Method:init)
2016-05-20 15:39:57.197 runtime運行時[4605:178974] (Method:height)
2016-05-20 15:39:57.197 runtime運行時[4605:178974] (Method:setHeight:)

分析:可以看到分類的新屬性可以在per對象中對新屬性height進行訪問賦值惕医。
獲取到 person 類屬性時耕漱,依然沒有 height 的存在,但是卻有 height 和
setHeight 這兩個方法抬伺;因為在分類中螟够,即使使用 @property 定義了,也只是生成 set+get 方法峡钓,而不會生成_變量名妓笙,分類中是不允許定義變量的。
使用 runtime 中 objc_setAssociatedObject()
objc_getAssociatedObject() 方法能岩,本質(zhì)上只是為對象per添加了對height的屬性關聯(lián)寞宫,但是達到了新屬性的作用;
使用場景:假設 imageCategory 是 UIImage 類的分類拉鹃,在實際開發(fā)中辈赋,我們使用 UIImage 下載圖片或者操作過程需要增加一個 URL 保存一段地址鲫忍,以備后期使用。這時可以嘗試在分類中動態(tài)添加新屬性 MyURL 進行存儲钥屈。

5.為 person 類添加一個新方法悟民;

將第五個按鈕關聯(lián)到ViewController.h,添加行為并命名其方法為:“addMethod”:

- (IBAction)addMethod:(UIButton *)sender;

在ViewController.m中的實現(xiàn)如下:

/*5.添加新的方法試試(這種方法等價于對 Father 類添加 Category 對方法進行擴展):*/
- (IBAction)addMethod:(UIButton *)sender { 
/* 動態(tài)添加方法: 
  第一個參數(shù)表示Class cls 類型篷就; 
  第二個參數(shù)表示待調(diào)用的方法名稱射亏; 
  第三個參數(shù)(IMP)myAddingFunction,IMP一個函數(shù)指針竭业,這里表示指定具體實現(xiàn)方法myAddingFunction鸦泳; 
  第四個參數(shù)表方法的參數(shù),0代表沒有參數(shù)永品; 
*/ 
  class_addMethod([per class], @selector(NewMethod), (IMP)myAddingFunction, 0); 
  //調(diào)用方法 【如果使用[per NewMethod]調(diào)用方法做鹰,在ARC下會報“no visible @interface"錯誤】 
  [per performSelector:@selector(NewMethod)];
}

//具體的實現(xiàn)(方法的內(nèi)部都默認包含兩個參數(shù)Class類和SEL方法,被稱為隱式參數(shù)鼎姐。)
int myAddingFunction(id self, SEL _cmd){ 
  NSLog(@"已新增方法:NewMethod"); 
  return 1;
}

點擊按鈕后钾麸,控制臺輸出:

2016-05-20 14:08:55.822 runtime運行時[1957:34730] 已新增方法:NewMethod

6.交換person類的2個方法的功能:

將第六個按鈕關聯(lián)到ViewController.h,添加行為并命名其方法為:“replaceMethod”:

- (IBAction)replaceMethod:(UIButton *)sender;

在ViewController.m中的實現(xiàn)如下:

/* 6.交換兩種方法之后(功能對調(diào))炕桨,可以試試讓蘋果亂套... */
- (IBAction)replaceMethod:(UIButton *)sender { 
Method method1 = class_getInstanceMethod([person class], @selector(func1)); 
Method method2 = class_getInstanceMethod([person class], @selector(func2)); 

//交換方法 
method_exchangeImplementations(method1, method2); 
[per func1]; //輸出交換后的效果饭尝,需要對比的可以嘗試下交換前運行func1;
}

點擊按鈕后献宫,控制臺輸出:

2016-05-20 14:11:57.381 runtime運行時[1957:34730] 執(zhí)行func2方法钥平。

交換方法的使用場景:項目中的某個功能,在項目中需要多次被引用姊途,當項目的需求發(fā)生改變時涉瘾,要使用另一種功能代替這個功能,且要求不改變舊的項目(也就是不改變原來方法實現(xiàn)的前提下)捷兰。那么立叛,我們可以在分類中,再寫一個新的方法(符合新的需求的方法)贡茅,然后交換兩個方法的實現(xiàn)秘蛇。這樣,在不改變項目的代碼顶考,而只是增加了新的代碼的情況下赁还,就完成了項目的改進,很好地體現(xiàn)了該項目的封裝性與利用率驹沿。
:交換兩個方法的實現(xiàn)一般寫在類的load方法里面艘策,因為load方法會在程序運行前加載一次。


(轉載請標明原文出處甚负,謝謝支持 ~ - ~)
? by:啊左~

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柬焕,一起剝皮案震驚了整個濱河市审残,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌斑举,老刑警劉巖搅轿,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異富玷,居然都是意外死亡璧坟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門赎懦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雀鹃,“玉大人,你說我怎么就攤上這事励两±杈ィ” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵当悔,是天一觀的道長傅瞻。 經(jīng)常有香客問我,道長盲憎,這世上最難降的妖魔是什么嗅骄? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮饼疙,結果婚禮上溺森,老公的妹妹穿的比我還像新娘。我一直安慰自己窑眯,他們只是感情好屏积,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著伸但,像睡著了一般肾请。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上更胖,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音隔显,去河邊找鬼却妨。 笑死,一個胖子當著我的面吹牛括眠,可吹牛的內(nèi)容都是我干的彪标。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼掷豺,長吁一口氣:“原來是場噩夢啊……” “哼捞烟!你這毒婦竟也來了薄声?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤题画,失蹤者是張志新(化名)和其女友劉穎默辨,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苍息,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡缩幸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了竞思。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片表谊。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖盖喷,靈堂內(nèi)的尸體忽然破棺而出爆办,到底是詐尸還是另有隱情,我是刑警寧澤课梳,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布距辆,位于F島的核電站,受9級特大地震影響惦界,放射性物質(zhì)發(fā)生泄漏挑格。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一沾歪、第九天 我趴在偏房一處隱蔽的房頂上張望漂彤。 院中可真熱鬧,春花似錦灾搏、人聲如沸挫望。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽媳板。三九已至,卻和暖如春泉哈,著一層夾襖步出監(jiān)牢的瞬間蛉幸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工丛晦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留奕纫,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓烫沙,卻偏偏與公主長得像匹层,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锌蓄,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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

  • iOS開發(fā)-- Runtime的幾個小例子 字數(shù)2756閱讀1867評論22喜歡88 一升筏、什么是runtime(也...
    K_Gopher閱讀 367評論 0 0
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,125評論 29 470
  • 1撑柔、截取字符串”20 | http://www.baidu.com”中,”|”字符前面和后面的數(shù)據(jù)您访,分別輸出它們 ...
    強子ly閱讀 2,920評論 8 46
  • 對于從事 iOS 開發(fā)人員來說铅忿,所有的人都會答出【runtime 是運行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,697評論 7 64
  • 介紹 函數(shù)本身也是對象,可以賦值給一個新的函數(shù)洋只。如果想在不改變原有函數(shù)的基礎上辆沦,又希望能夠增加一些功能,就可以使用...
    AlexSun1995閱讀 356評論 0 0