iOS面試題合集-基礎(chǔ)理論

喜歡就關(guān)注我唄!


1.設(shè)計模式是什么? 你知道哪些設(shè)計模式,并簡要敘述?

設(shè)計模式是一種編碼經(jīng)驗,就是用比較成熟的邏輯去處理某一種類型的事情。

1). MVC模式:Model View Control,把模型 視圖 控制器 層進行解耦合編寫。

2). MVVM模式:Model View ViewModel 把模型 視圖 業(yè)務(wù)邏輯 層進行解耦和編寫。

3). 單例模式:通過static關(guān)鍵詞,聲明全局變量。在整個進程運行期間只會被賦值一次。

4). 觀察者模式:KVO是典型的通知模式,觀察某個屬性的狀態(tài),狀態(tài)發(fā)生變化時通知觀察者。

5). 委托模式:代理+協(xié)議的組合。實現(xiàn)1對1的反向傳值操作。

6). 工廠模式:通過一個類方法,批量的根據(jù)已有模板生產(chǎn)對象。

2.#import跟 #include 有什么區(qū)別,@class呢

1). #import是Objective-C導(dǎo)入頭文件的關(guān)鍵字,#include是C/C++導(dǎo)入頭文件的關(guān)鍵字,使用#import頭文件會自動只導(dǎo)入一次,不會重復(fù)導(dǎo)入。

2). @class告訴編譯器某個類的聲明,當執(zhí)行時,才去查看類的實現(xiàn)文件,可以解決頭文件的相互包含。

3.Objective-C的類可以多重繼承么?可以實現(xiàn)多個接口么?Category是什么?重寫一個類的方式用繼承好還是分類好?為什么?

答:Objective-C的類不可以多重繼承;可以實現(xiàn)多個接口(協(xié)議);Category是類別;一般情況用分類好,用Category去重寫類的方法,僅對本Category有效,不會影響到其他類與原有類的關(guān)系。

4.@property 的本質(zhì)是什么?ivar、getter、setter 是如何生成并添加到這個類中的

@property 的本質(zhì)是什么?

@property = ivar + getter + setter;

“屬性” (property)有兩大概念:ivar(實例變量)、getter+setter(存取方法)

“屬性” (property)作為 Objective-C 的一項特性,主要的作用就在于封裝對象中的數(shù)據(jù)。 Objective-C 對象通常會把其所需要的數(shù)據(jù)保存為各種實例變量。實例變量一般通過“存取方法”(access method)來訪問。其中,“獲取方法” (getter)用于讀取變量值,而“設(shè)置方法” (setter)用于寫入變量值。


5.什么情況使用 weak 關(guān)鍵字,相比 assign 有什么不同?

1.在 ARC 中,在有可能出現(xiàn)循環(huán)引用的時候,往往要通過讓其中一端使用 weak 來解決,比如: delegate 代理屬性。

2.自身已經(jīng)對它進行一次強引用,沒有必要再強引用一次,此時也會使用 weak,自定義 IBOutlet 控件屬性一般也使用 weak;當然,也可以使用strong。

IBOutlet連出來的視圖屬性為什么可以被設(shè)置成weak?

因為父控件的subViews數(shù)組已經(jīng)對它有一個強引用。

不同點:

assign 可以用非 OC 對象,而 weak 必須用于 OC 對象。

weak 表明該屬性定義了一種“非擁有關(guān)系”。在屬性所指的對象銷毀時,屬性值會自動清空(nil)。

6.淺拷貝和深拷貝的區(qū)別?

答:

淺拷貝:只復(fù)制指向?qū)ο蟮闹羔槪粡?fù)制引用對象本身。

深拷貝:復(fù)制引用對象本身。內(nèi)存中存在了兩份獨立對象本身,當修改A時,A_copy不變。

NSString *str = @"hello word!";

NSString *strCopy = [str copy] // 指針復(fù)制,strCopy與str的地址一樣

NSMutableString *strMCopy = [str mutableCopy] // 內(nèi)容復(fù)制,strMCopy與str的地址不一樣

7.寫一個 setter 方法用于完成 @property (nonatomic, retain) NSString*name,寫一個 setter 方法用于完成 @property (nonatomic, copy) NSString *name

答:

// retain

- (void)setName:(NSString *)str {

[str retain];

[_name release];

_name = str;

}

// copy

- (void)setName:(NSString *)str {

id t = [str copy];

[_name release];

_name = t;

}

8.@synthesize 和 @dynamic 分別有什么作用?

@property有兩個對應(yīng)的詞,一個是@synthesize(合成實例變量),一個是@dynamic。

如果@synthesize和@dynamic都沒有寫,那么默認的就是 @synthesize var = _var;

// 在類的實現(xiàn)代碼里通過 @synthesize 語法可以來指定實例變量的名字。(@synthesize var = _newVar;)

1. @synthesize 的語義是如果你沒有手動實現(xiàn)setter方法和getter方法,那么編譯器會自動為你加上這兩個方法。

2. @dynamic 告訴編譯器,屬性的setter與getter方法由用戶自己實現(xiàn),不自動生成(如,@dynamic var)。

9.id 聲明的對象有什么特性?

答:id 聲明的對象具有運行時的特性,即可以指向任意類型的Objcetive-C的對象。

10.Objective-C 中創(chuàng)建線程的方法是什么?如果在主線程中執(zhí)行代碼,方法是什么?如果想延時執(zhí)行代碼、方法又是什么?

答:線程創(chuàng)建有三種方法:使用NSThread創(chuàng)建、使用GCD的dispatch、使用子類化的NSOperation,然后將其加入NSOperationQueue;在主線程執(zhí)行代碼,方法是performSelectorOnMainThread,如果想延時執(zhí)行代碼可以用performSelector:onThread:withObject:waitUntilDone:

11.我們說的OC是動態(tài)運行時語言是什么意思?

答:主要是將數(shù)據(jù)類型的確定由編譯時,推遲到了運行時。簡單來說, 運行時機制使我們直到運行時才去決定一個對象的類別,以及調(diào)用該類別對象指定方法。

12.什么是 KVO 和 KVC?

1). KVC(Key-Value-Coding):鍵值編碼 是一種通過字符串間接訪問對象的方式(即給屬性賦值)

舉例說明:

stu.name = @"張三" // 點語法給屬性賦值

[stu setValue:@"張三" forKey:@"name"]; // 通過字符串使用KVC方式給屬性賦值

stu1.nameLabel.text = @"張三";

[stu1 setValue:@"張三" forKey:@"nameLabel.text"]; // 跨層賦值

2). KVO(key-Value-Observing):鍵值觀察機制 他提供了觀察某一屬性變化的方法,極大的簡化了代碼。

KVO只能被KVC觸發(fā),包括使用setValue:forKey:方法和點語法。

// 通過下方方法為屬性添加KVO觀察

- (void)addObserver:(NSObject *)observer

forKeyPath:(NSString *)keyPath

options:(NSKeyValueObservingOptions)options

context:(nullable void *)context;

// 當被觀察的屬性發(fā)送變化時,會自動觸發(fā)下方方法

- (void)observeValueForKeyPath:(NSString *)keyPath

ofObject:(id)object

change:(NSDictionary *)change

context:(void *)context{}

KVC 和 KVO 的 keyPath 可以是屬性、實例變量、成員變量。

13.KVC的底層實現(xiàn)?

當一個對象調(diào)用setValue方法時,方法內(nèi)部會做以下操作:

1). 檢查是否存在相應(yīng)的key的set方法,如果存在,就調(diào)用set方法。

2). 如果set方法不存在,就會查找與key相同名稱并且?guī)聞澗€的成員變量,如果有,則直接給成員變量屬性賦值。

3). 如果沒有找到_key,就會查找相同名稱的屬性key,如果有就直接賦值。

4). 如果還沒有找到,則調(diào)用valueForUndefinedKey:和setValue:forUndefinedKey:方法。

這些方法的默認實現(xiàn)都是拋出異常,我們可以根據(jù)需要重寫它們。

24.談?wù)?UITableView 的優(yōu)化

1). 正確的復(fù)用cell。

2). 設(shè)計統(tǒng)一規(guī)格的Cell

3). 提前計算并緩存好高度(布局),因為heightForRowAtIndexPath:是調(diào)用最頻繁的方法;

4). 異步繪制,遇到復(fù)雜界面,遇到性能瓶頸時,可能就是突破口;

4). 滑動時按需加載,這個在大量圖片展示,網(wǎng)絡(luò)加載的時候很管用!

5). 減少子視圖的層級關(guān)系

6). 盡量使所有的視圖不透明化以及做切圓操作。

7). 不要動態(tài)的add 或者 remove 子控件。最好在初始化時就添加完,然后通過hidden來控制是否顯示。

8). 使用調(diào)試工具分析問題。


14.delegate 和 notification 的區(qū)別

1). 二者都用于傳遞消息,不同之處主要在于一個是一對一的,另一個是一對多的。

2). notification通過維護一個array,實現(xiàn)一對多消息的轉(zhuǎn)發(fā)。

3). delegate需要兩者之間必須建立聯(lián)系,不然沒法調(diào)用代理的方法;notification不需要兩者之間有聯(lián)系。

15.您一般是怎么用 Instruments 的?

Time Profiler:性能分析

Zombies:檢查是否訪問了僵尸對象,但是這個工具只能從上往下檢查,不智能

Allocations:用來檢查內(nèi)存,寫算法的那批人也用這個來檢查

Leaks:檢查內(nèi)存,看是否有內(nèi)存泄露

Core Animation:

1)查看幀數(shù) <55就得優(yōu)化 ?優(yōu)化。

Core Animation工具中有幾個和離屏渲染相關(guān)的檢查選項:

2)Color Offscreen-Rendered Yellow

開啟后會把那些需要離屏渲染的圖層高亮成黃色,這就意味著黃色圖層可能存在性能問題。

3)Color Hits Green and Misses Red

如果shouldRasterize被設(shè)置成YES,對應(yīng)的渲染結(jié)果會被緩存,如果圖層是綠色,就表示這些緩存被復(fù)用;如果是紅色就表示緩存會被重復(fù)創(chuàng)建,這就表示該處存在性能問題了。



16.您開發(fā)常用的工具有哪些?

1).友盟統(tǒng)計

2).青花瓷:這個軟件還是蠻不錯的,可以用來過濾網(wǎng)絡(luò)請求,模擬低速網(wǎng)路,還可以修改網(wǎng)絡(luò)請求內(nèi)容這些

3).Reveal:調(diào)試頁面不錯,還有用來學(xué)習(xí)別人的demo時候可以拿來看UI層次結(jié)構(gòu),還可以用

17.您是怎么調(diào)試iOS程序的(談?wù)勀膇OS調(diào)試經(jīng)驗)

斷點調(diào)試,讓程序在執(zhí)行某一行代碼是停止下來,然后來檢查當前程序是否正常。斷點的種類很多,可以幫助我們快速定位到問題發(fā)生時的上下文。

- 普通斷點

- 符號斷點

- 異常斷點

- watch斷點

- 條件斷點

運行時變量:查看運行時變量值

運行時堆棧:查看函數(shù)的調(diào)用關(guān)系,順序

日志:通過在程序中添加NSLog代碼,在控件臺中輸出顯示日志。

靜態(tài)代碼檢查:通過對代碼靜態(tài)分析,找出代碼潛在的錯誤,如內(nèi)存泄漏、空引用、未使用函數(shù)等。

動態(tài)分析:通過Instruments工具跟蹤分析程序運行時的數(shù)據(jù)

18.有哪些常見的 Crash 場景?

訪問了僵尸對象

訪問野指針

訪問了不存在的方法

數(shù)組越界

在定時器下一次回調(diào)前將定時器釋放

19.如何調(diào)試BAD_ACCESS錯誤

1)重寫object的respondsToSelector方法,現(xiàn)實出現(xiàn)EXEC_BAD_ACCESS前訪問的最后一個object

2)通過 Zombie

3)設(shè)置全局斷點快速定位問題代碼所在行

4)Xcode 7 已經(jīng)集成了BAD_ACCESS捕獲功能:Address Sanitizer。 用法如下:在配置中勾選?

Enable Address Sanitizer

20.lldb(gdb)常用的調(diào)試命令?

breakpoint 設(shè)置斷點定位到某一個函數(shù)

n 斷點指針下一步

po打印對象

21.如果在Cocoa中發(fā)現(xiàn)一個Bug,你會如何處理?

復(fù)現(xiàn)bug,確認bug發(fā)生的軟硬件環(huán)境,詳細描述后發(fā)報告給Apple。

22.CocoaPods的原理

CocoaPods的原理是將所有的依賴庫都放到另一個名為Pods的項目中,然后讓主項目依賴Pods項目,這樣,源碼管理工作都從主項目移到了Pods項目中。Pods項目最終會編譯成一個名為libPods.a的文件,主項目只需要依賴這個.a文件即可。

23.請用預(yù)處理指令#define聲明一個常數(shù),用以表明1年中有多少秒(忽略閏年問題)

#define SECONDS_PER_YEAR (60*60*24*365)_U_LONG

24.volatile表示變量隨時可以改變

25.請談?wù)刓#include與\#import的區(qū)別、\#import與@class 的區(qū)別

#include和#import 其效果相同,都是導(dǎo)入類中定義的行為(方法);

#import 不會引起交叉編譯,確保頭文件只會被導(dǎo)入一次;

@class 表明只定義了類的名稱,而具體類的行為是未知的,一般用于.h 文件

@class比#import編譯效率更高。此外@class和#import的主要區(qū)別在于解決引用死鎖的問題。

26.什么是id類型,id 聲明的對象有什么特性?

id 聲明的對象具有運行時的特性,即可以指向任意類型的objcetive-c的對象;

27.請談一談關(guān)鍵字self、super的作用

self:當前消息的接收者。

super:向父類發(fā)送消息。

28.請解釋self = [super init]方法

容錯處理,當父類初始化失敗,會返回一個nil,表示初始化失敗。由于繼承的關(guān)系,子類是需要擁有父類的實例和行為,因此,我們必須先初始化父類,然后再初始化子類

29.請說明如何使用Instancetype及其重要性

instancetype,編譯器能正確的推斷出返回實例的實際類型!

instancetype只能用于返回值!

建議在返回self實例的方法中,用instancetype,別用id.

30.請問@property中有哪些屬性關(guān)鍵字?

原子性---atomic/nonatomic? 讀/寫權(quán)限---readwrite(讀寫)、readonly(只讀)? 、內(nèi)存管理語義---assign、strong、weak、unsafe_unretained、copy、方法名---getter=和setter=、不常用的:nonnull,null_resettable,nullable

31.ARC下,不顯式指定任何屬性關(guān)鍵字時,默認的關(guān)鍵字都有哪些?

atomic,readwrite,assign,strong

32.@protocol 和 category 中如何使用 @property

在 protocol 中使用 property 只會生成 setter 和 getter 方法聲明,我們使用屬性的目的,是希望遵守我協(xié)議的對象能實現(xiàn)該屬性

category 使用 @property 也是只會生成 setter 和 getter 方法的聲明,如果我們真的需要給 category 增加屬性的實現(xiàn),需要借助于運行時的兩個函數(shù):

objc_setAssociatedObject

objc_getAssociatedObject

33.這個寫法會出什么問題: @property (copy) NSMutableArray *array;

兩個問題:

添加,刪除,修改數(shù)組內(nèi)的元素的時候,程序會因為找不到對應(yīng)的方法而崩潰.因為 copy 就是復(fù)制一個不可變 NSArray 的對象;

使用了 atomic 屬性會嚴重影響性能 ;

34.@synthesize合成實例變量的規(guī)則是什么?假如property名為foo,存在一個名為_foo的實例變量,那么還會自動合成新變量么?

總結(jié)下 @synthesize 合成實例變量的規(guī)則,有以下幾點:

如果指定了成員變量的名稱,會生成一個指定的名稱的成員變量,

如果這個成員已經(jīng)存在了就不再生成了.

如果是 @synthesize foo;

還會生成一個名稱為foo的成員變量,也就是說:

如果沒有指定成員變量的名稱會自動生成一個屬性同名的成員變量,

如果是 @synthesize foo = _foo;

就不會生成成員變量了.

假如 property 名為 foo,存在一個名為 _foo的實例變量,那么還會自動合成新變量么? 不會。

34.如何為 Class 定義一個對外只讀對內(nèi)可讀寫的屬性?

在頭文件中將屬性定義為readonly, 在.m文件中將屬性重新定義為readwrite

35.在一個對象的方法里面:`self.name = @"object";`和`name =@"object";`有什么不同嗎?

self.name = @"object";會調(diào)用對象的setName()方法.

name =@"object";會直接把@"object"賦值給當前對象的name 屬性。

36.__block vs __weak

block 不能修改局部變量,如果需要修改需要加上block.

block 會對對象強引用,引起retain-cycle,需要使用weak

37.使用block有什么好處?請使用`NSTimer`寫出一個使用block顯示(在`UILabel`上)秒表的代碼

//iOS10 才有效

NSTimer*timer=[NSTimerscheduledTimerWithTimeInterval:1.0repeats:YEScallback:^(){weakSelf.secondsLabel.text=...} ? ?

[[NSRunLoopcurrentRunLoop]addTimer:timerforMode:NSRunLoopCommonModes];

38.談?wù)刡lock使用時的注意點?

在block內(nèi)部使用外部指針且會造成循環(huán)引用情況下,需要用weak修飾外部指針weak typeof(self) weakSelf = self;

在block內(nèi)部如果調(diào)用了延時函數(shù)還使用弱指針會取不到該指針,因為已經(jīng)被銷毀了,需要在block內(nèi)部再將弱指針重新強引用一下__strong typeof(self) strongSelf = weakSelf;

如果需要在block內(nèi)部改變外部變量的話,需要在用__block修飾外部變量

39.block和代理的區(qū)別,哪個更好?

代理回調(diào)更面向過程,block更面向結(jié)果。FBRetainCycleDetector? ?檢測循環(huán)引用。

如果你使用一些參數(shù)中可能含有 ivar 的系統(tǒng) api ,如 GCD 、NSNotificationCenter就要小心一點:比如GCD 內(nèi)部如果引用了 self,而且 GCD 的其他參數(shù)是 iva

_operationsQueue 這個

__weak__typeof__(self)weakSelf =self;dispatch_group_async(_operationsGroup, _operationsQueue, ^{? ? __typeof__(self)strongSelf= weakSelf;[strongSelfdoSomething];[strongSelfdoSomethingElse];} );


__weak__typeof__(self) weakSelf =self;_observer = [[NSNotificationCenterdefaultCenter] addObserverForName:@"testKey"object:nilqueue:nilusingBlock:^(NSNotification*note) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? __typeof__(self) strongSelf = weakSelf;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [strongSelf dismissModalViewControllerAnimated:YES];? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }];


40.類別和類擴展的區(qū)別

category和extensions的不同在于后者可以添加屬性。另外后者添加的方法是必須要實現(xiàn)的。

extensions可以認為是一個私有的Category。

41.分類的作用?分類和繼承的區(qū)別?

分類可以在不獲悉,不改變原來代碼的情況下往里面添加新的方法,只能添加,不能刪除修改,并且如果分類和原來類中的方法產(chǎn)生名稱沖突,則分類將覆蓋原來的方法,因為分類具有更高的優(yōu)先級。

繼承可以增加,修改或者刪除方法,并且可以增加屬性;但是分類只能添加方法,不能刪除修改,也不能增加屬性。


42.iOS Extension 是什么?能列舉幾個常用的 Extension 么?

Extension是Category的一個特例,沒有分類名字,可以擴展屬性,成員變量和方法。

常用的擴展是在.m文件中聲明私有屬性和方法,基本上我們天天都在用。

43.addObserver:forKeyPath:options:context:各個參數(shù)的作用分別是什么,observer中需要實現(xiàn)哪個方法才能獲得KVO回調(diào)?

// 添加鍵值觀察/*

1 觀察者,負責處理監(jiān)聽事件的對象

2 觀察的屬性

3 觀察的選項

4 上下文

*/[self.personaddObserver:selfforKeyPath:@"name"options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOldcontext:@"Person Name"];

// 所有的 kvo 監(jiān)聽到事件,都會調(diào)用此方法/*

1. 觀察的屬性

2. 觀察的對象

3. change 屬性變化字典(新/舊)

4. 上下文,與監(jiān)聽的時候傳遞的一致

*/- (void)observeValueForKeyPath:(NSString *)keyPathofObject:(id)objectchange:(NSDictionary *)changecontext:(void*)context;

44.如何手動觸發(fā)一個value的KVO

那么“手動觸發(fā)”的使用場景是什么?一般我們只在希望能控制“回調(diào)的調(diào)用時機”時才會這么做。

具體做法如下:

如果這個? value 是 表示時間的 self.now ,那么代碼如下:最后兩行代碼缺一不可。

@property (nonatomic, strong) NSDate *now;

- (void)viewDidLoad{ ??

?[super viewDidLoad]; ? ?

[self willChangeValueForKey:@"now"];// “手動觸發(fā)self.now的KVO”,必寫。

[self didChangeValueForKey:@"now"];// “手動觸發(fā)self.now的KVO”,必寫。

}

45.若一個類有實例變量NSString *_foo,調(diào)用setValue:forKey:時,可以以foo還是_foo作為key?

可以。kvc機制。

46.KVC的keyPath中的集合運算符如何使用?

必須用在集合對象上或普通對象的集合屬性上

簡單集合運算符有@avg, @count , @max , @min ,@sum,

格式 @"@sum.age"或 @"集合屬性.@max.age"

http://www.cnblogs.com/panda1024/p/6014399.html

47.KVC和KVO的keyPath一定是屬性么?

KVO支持實例變量

48.如何關(guān)閉默認的KVO的默認實現(xiàn),并進入自定義的KVO實現(xiàn)?

http://tech.glowing.com/cn/implement-kvo/

49.apple用什么方式實現(xiàn)對一個對象的KVO?

KVO 在實現(xiàn)中通過isa 混寫(isa-swizzling)把這個對象的 isa 指針 ( isa 指針告訴 Runtime 系統(tǒng)這個對象的類是什么 ) 指向這個新創(chuàng)建的子類,對象就神奇的變成了新創(chuàng)建的子類的實例

50.代理的作用?

代理的目的是改變或傳遞控制鏈。允許一個類在某些特定時刻通知到其他類,而不需要獲取到那些類的指針。可以減少框架復(fù)雜度。

另外一點,代理可以理解為java中的回調(diào)監(jiān)聽機制的一種類似。

51.OC有多繼承嗎?沒有的話用什么代替?

OC中沒有多繼承,可以用委托代理Protocol來實現(xiàn)

52.什么是 Protocol,Delegate 一般是怎么用的?

Protocol是協(xié)議,只有.h文件,甚至可以不獨立文件

使用時 遵守協(xié)議,在本類中實現(xiàn)方法就可以

協(xié)議有required和optional的,required是必須實現(xiàn)的協(xié)議方法。

協(xié)議聲明了可以被任何類實現(xiàn)的方法

協(xié)議不是類,它是定義了一個其他對象可以實現(xiàn)的接口

如果在某個類中實現(xiàn)了協(xié)議中的某個方法,也就是這個類實現(xiàn)了那個協(xié)議。

Delegate:它本身是一個設(shè)計模式,它的意思是委托別人去做某事。

53.為什么 NotificationCenter 要 removeObserver? 如何實現(xiàn)自動 remove?

如果不移除的話,萬一注冊通知的類被銷毀以后又發(fā)了通知,程序會崩潰.因為向野指針發(fā)送了消息

實現(xiàn)自動remove:通過自釋放機制,通過動態(tài)屬性將remove轉(zhuǎn)移給第三者,解除耦合,達到自動實現(xiàn)remove。

54.我們說的oc是動態(tài)運行時語言是什么意思?

OC的動態(tài)運行時,是指OC具有動態(tài)類型和動態(tài)綁定的特性。動態(tài)類型能使程序直到執(zhí)行時才確定對象的所屬類, 其具體引用的對象在運行時才能確定。 動態(tài)綁定能使程序直到運行時才確定調(diào)用對象的實際方法。

多態(tài)。 主要是將數(shù)據(jù)類型的確定由編譯時,推遲到了運行時。

這個問題其實淺涉及到兩個概念,運行時和多態(tài)。

簡單來說,運行時機制使我們直到運行時才去決定一個對象的類別,以及調(diào)用該類別對象指定方法。

多態(tài):不同對象以自己的方式響應(yīng)相同的消息的能力叫做多態(tài)。意思就是假設(shè)生物類(life)都用有一個相同的方法-eat;

那人類屬于生物,豬也屬于生物,都繼承了life后,實現(xiàn)各自的eat,但是調(diào)用是我們只需調(diào)用各自的eat方法。

也就是不同的對象以自己的方式響應(yīng)了相同的消息(響應(yīng)了eat這個選擇器)。

55.objc中向一個nil對象發(fā)送消息將會發(fā)生什么?

objc在向一個對象發(fā)送消息時,runtime庫會根據(jù)對象的isa指針找到該對象實際所屬的類,然后在該類中的方法列表以及其父類方法列表中尋找方法運行,然后在發(fā)送消息的時候,objc_msgSend方法不會返回值,所謂的返回內(nèi)容都是具體調(diào)用時執(zhí)行的。那么,回到本題,如果向一個nil對象發(fā)送消息,首先在尋找對象的isa指針時就是0地址返回了,所以不會出現(xiàn)任何錯誤。

56.objc中向一個對象發(fā)送消息[obj foo]和objc_msgSend()函數(shù)之間有什么關(guān)系?

[obj foo];在objc動態(tài)編譯時,會被轉(zhuǎn)意為:objc_msgSend(obj,@selector(foo));

57.為什么其他語言里叫函數(shù)調(diào)用,Object-C里則叫給我對象發(fā)消息

在OC中,方法調(diào)用是向類發(fā)送消息,如[bady cry]在運行時會轉(zhuǎn)換成objc_msgSend(bady,cry),向?qū)ο蟀l(fā)送消息時根據(jù)isa指針找到類,在根據(jù)類的調(diào)度表查找方法,沒找到方法則在父類中查找直至基類,如果始終沒有找到返回nil。

Objective-C 的 Runtime 鑄就了它動態(tài)語言的特性。Objc Runtime使得C具有了面向?qū)ο竽芰Γ诔绦蜻\行時創(chuàng)建,檢查,修改類、對象和它們的方法。可以使用runtime的一系列方法實現(xiàn)。

58.isMemberOfClass 和 isKindOfClass 聯(lián)系與區(qū)別

聯(lián)系:兩者都能檢測一個對象是否是某個類的成員

區(qū)別:isKindOfClass 不僅用來確定一個對象是否是一個類的成員,也可以用來確定一個對象是否派生自該類的類的成員 ,而isMemberOfClass 只能做到第一點。

舉例:如 ClassA派 生 自NSObject 類 , ClassA *a = [ClassA alloc] init];,[a isKindOfClass:[NSObject class]] 可以檢查出 a 是否是 NSObject派生類 的成員,但 isMemberOfClass 做不到。

59.什么時候會報unrecognized selector的異常?

簡單來說:

當調(diào)用該對象上某個方法,而該對象上沒有實現(xiàn)這個方法的時候,

可以通過“消息轉(zhuǎn)發(fā)”進行解決。

簡單的流程如下,在上一題中也提到過:

objc是動態(tài)語言,每個方法在運行時會被動態(tài)轉(zhuǎn)為消息發(fā)送,即:objc_msgSend(receiver, selector)。

objc在向一個對象發(fā)送消息時,runtime庫會根據(jù)對象的isa指針找到該對象實際所屬的類,然后在該類中的方法列表以及其父類方法列表中尋找方法運行,如果,在最頂層的父類中依然找不到相應(yīng)的方法時,程序在運行時會掛掉并拋出異常unrecognized selector sent to XXX 。但是在這之前,objc的運行時會給出三次拯救程序崩潰的機會:

Method resolution

objc運行時會調(diào)用+resolveInstanceMethod:或者 +resolveClassMethod:,讓你有機會提供一個函數(shù)實現(xiàn)。如果你添加了函數(shù),那運行時系統(tǒng)就會重新啟動一次消息發(fā)送的過程,否則 ,運行時就會移到下一步,消息轉(zhuǎn)發(fā)(Message Forwarding)。

Fast forwarding

如果目標對象實現(xiàn)了-forwardingTargetForSelector:,Runtime 這時就會調(diào)用這個方法,給你把這個消息轉(zhuǎn)發(fā)給其他對象的機會。

只要這個方法返回的不是nil和self,整個消息發(fā)送的過程就會被重啟,當然發(fā)送的對象會變成你返回的那個對象。否則,就會繼續(xù)Normal Fowarding。

這里叫Fast,只是為了區(qū)別下一步的轉(zhuǎn)發(fā)機制。因為這一步不會創(chuàng)建任何新的對象,但下一步轉(zhuǎn)發(fā)會創(chuàng)建一個NSInvocation對象,所以相對更快點。

Normal forwarding

這一步是Runtime最后一次給你挽救的機會。首先它會發(fā)送-methodSignatureForSelector:消息獲得函數(shù)的參數(shù)和返回值類型。如果-methodSignatureForSelector:返回nil,Runtime則會發(fā)出-doesNotRecognizeSelector:消息,程序這時也就掛掉了。如果返回了一個函數(shù)簽名,Runtime就會創(chuàng)建一個NSInvocation對象并發(fā)送-forwardInvocation:消息給目標對象。

60.一個objc對象的isa的指針指向什么?有什么作用?

指向他的類對象,從而可以找到對象上的方法

61._objc_msgForward函數(shù)是做什么的,直接調(diào)用它將會發(fā)生什么?

_objc_msgForward是 IMP 類型,用于消息轉(zhuǎn)發(fā)的:當向一個對象發(fā)送一條消息,但它并沒有實現(xiàn)的時候,_objc_msgForward會嘗試做消息轉(zhuǎn)發(fā)。

直接調(diào)用_objc_msgForward是非常危險的事,如果用不好會直接導(dǎo)致程序Crash,但是如果用得好,能做很多非常酷的事。

一旦調(diào)用_objc_msgForward,將跳過查找 IMP 的過程,直接觸發(fā)“消息轉(zhuǎn)發(fā)”,如果調(diào)用了_objc_msgForward,即使這個對象確實已經(jīng)實現(xiàn)了這個方法,你也會告訴objc_msgSend:“我沒有在這個對象里找到這個方法的實現(xiàn)”

62.能否向編譯后得到的類中增加實例變量?能否向運行時創(chuàng)建的類中添加實例變量?為什么?

不能向編譯后得到的類中增加實例變量;

能向運行時創(chuàng)建的類中添加實例變量;

原因如下:

因為編譯后的類已經(jīng)注冊在 runtime 中,類結(jié)構(gòu)體中的 objc_ivar_list 實例變量的鏈表 和 instance_size 實例變量的內(nèi)存大小已經(jīng)確定,同時runtime 會調(diào)用 class_setIvarLayout 或 class_setWeakIvarLayout 來處理 strong weak 引用。所以不能向存在的類中添加實例變量;

運行時創(chuàng)建的類是可以添加實例變量,調(diào)用 class_addIvar 函數(shù)。但是得在調(diào)用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上。

63.Objective-C 中,meta-class 指的是什么?

meta-class 是 Class 對象的類, 為這個Class類存儲類方法, 當一個類發(fā)送消息時,就去那個類對應(yīng)的meta-class中查找那個消息。

每個Class都有不同的meta-class, 所有的meta-class都使用基類的meta-class(假如類繼承NSObject,那么他所對應(yīng)的meta-class也是NSObject) 作為他們的類



63.Toll-Free Bridging 是什么?什么情況下會使用?

Toll-Free Bridging用于在Foundation對象與Core Foundation對象之間交換數(shù)據(jù),俗稱橋接

在ARC環(huán)境下,Foundation對象轉(zhuǎn)成 Core Foundation對象

使用__bridge橋接以后ARC會自動管理2個對象

使用__bridge_retained橋接需要手動釋放Core Foundation對象

在ARC環(huán)境下, Core Foundation對象轉(zhuǎn)成 Foundation對象

使用__bridge橋接,如果Core Foundation對象被釋放,Foundation對象也同時不能使用了,需要手動管理Core Foundation對象

使用__bridge_transfer橋接,系統(tǒng)會自動管理2個對象

63.iOS 是如何管理內(nèi)存的

Objective-C中的對象都是基于引用計數(shù)來管理生命周期的。簡單來說就是,我們在需要持有一個對象時,調(diào)用retain讓它的引用計數(shù)+1。不需要這個對象的時候,調(diào)用release讓它的引用計數(shù)-1。當一個對象引用計數(shù)為0的時候,這個對象就會被自動銷毀

64.ARC通過什么方式幫助開發(fā)者管理內(nèi)存?

ARC相對于MRC,不是在編譯時添加retain/release/autorelease這么簡單。應(yīng)該是編譯期和運行期兩部分共同幫助開發(fā)者管理內(nèi)存。

在編譯期,ARC用的是更底層的C接口實現(xiàn)的retain/release/autorelease,這樣做性能更好,也是為什么不能在ARC環(huán)境下手動retain/release/autorelease,同時對同一上下文的同一對象的成對retain/release操作進行優(yōu)化(即忽略掉不必要的操作);

ARC也包含運行期組件,這個地方做的優(yōu)化比較復(fù)雜,但也不能被忽略。

65.一個objc對象如何進行內(nèi)存布局?(考慮有父類的情況)


所有父類的成員變量和自己的成員變量都會存放在該對象所對應(yīng)的存儲空間中.

每一個對象內(nèi)部都有一個isa指針,指向他的類對象,類對象中存放著本對象的

對象方法列表(對象能夠接收的消息列表,保存在它所對應(yīng)的類對象中)

成員變量的列表,

屬性列表,

它內(nèi)部也有一個isa指針指向元對象(meta class),元對象內(nèi)部存放的是類方法列表,類對象內(nèi)部還有一個superclass的指針,指向他的父類對象。

每個 Objective-C 對象都有相同的結(jié)構(gòu),如下圖所示:

翻譯過來就是

ISA指針

根類的實例變量

倒數(shù)第二層父類的實例變量

...

父類的實例變量

類的實例變量

根對象就是NSobject,它的superclass指針指向nil

類對象既然稱為對象,那它也是一個實例。類對象中也有一個isa指針指向它的元類(meta class),即類對象是元類的實例。元類內(nèi)部存放的是類方法列表,根元類的isa指針指向自己,superclass指針指向NSObject類

66.不手動指定autoreleasepool的前提下,一個autorealese對象在什么時刻釋放?(比如在一個vc的viewDidLoad中創(chuàng)建)

分兩種情況:手動干預(yù)釋放時機、系統(tǒng)自動去釋放。

手動干預(yù)釋放時機 - 指定autoreleasepool就是所謂的:當前作用域大括號結(jié)束時釋放。

系統(tǒng)自動去釋放 - 不手動指定autoreleasepool

Autorelease對象出了作用域之后,會被添加到最近一次創(chuàng)建的自動釋放池中,并會在當前的 runloop 迭代結(jié)束時釋放。

如果在一個vc的viewDidLoad中創(chuàng)建一個 Autorelease對象,那么該對象會在 viewDidAppear 方法執(zhí)行前就被銷毀了。

67.蘋果是如何實現(xiàn)autoreleasepool的?

autoreleasepool 以一個棧的形式實現(xiàn),主要通過下列三個函數(shù)完成.

objc_autoreleasepoolPush

objc_autoreleasepoolPop

objc_aurorelease

看函數(shù)名就可以知道,對 autorelease 分別執(zhí)行 push,和 pop 操作。銷毀對象時執(zhí)行release操作。

68.請談?wù)剝?nèi)存的使用和優(yōu)化的注意事項

重用問題:如UITableViewCells、UICollectionViewCells、UITableViewHeaderFooterViews設(shè)置正確的reuseIdentifier,充分重用;

盡量把views設(shè)置為不透明:當opque為NO的時候,圖層的半透明取決于圖片和其本身合成的圖層為結(jié)果,可提高性能;

不要使用太復(fù)雜的XIB/Storyboard:載入時就會將XIB/storyboard需要的所有資源,包括圖片全部載入內(nèi)存,即使未來很久才會使用。那些相比純代碼寫的延遲加載,性能及內(nèi)存就差了很多;

選擇正確的數(shù)據(jù)結(jié)構(gòu):學(xué)會選擇對業(yè)務(wù)場景最合適的數(shù)組結(jié)構(gòu)是寫出高效代碼的基礎(chǔ)。比如,數(shù)組: 有序的一組值。使用索引來查詢很快,使用值查詢很慢,插入/刪除很慢。字典: 存儲鍵值對,用鍵來查找比較快。集合: 無序的一組值,用值來查找很快,插入/刪除很快。gzip/zip壓縮:當從服務(wù)端下載相關(guān)附件時,可以通過gzip/zip壓縮后再下載,使得內(nèi)存更小,下載速度也更快。

延遲加載:對于不應(yīng)該使用的數(shù)據(jù),使用延遲加載方式。對于不需要馬上顯示的視圖,使用延遲加載方式。比如,網(wǎng)絡(luò)請求失敗時顯示的提示界面,可能一直都不會使用到,因此應(yīng)該使用延遲加載。

數(shù)據(jù)緩存:對于cell的行高要緩存起來,使得reload數(shù)據(jù)時,效率也極高。而對于那些網(wǎng)絡(luò)數(shù)據(jù),不需要每次都請求的,應(yīng)該緩存起來,可以寫入數(shù)據(jù)庫,也可以通過plist文件存儲。

處理內(nèi)存警告:一般在基類統(tǒng)一處理內(nèi)存警告,將相關(guān)不用資源立即釋放掉重用大開銷對象:一些objects的初始化很慢,比如NSDateFormatter

和NSCalendar,但又不可避免地需要使用它們。通常是作為屬性存儲起來,防止反復(fù)創(chuàng)建。

避免反復(fù)處理數(shù)據(jù):許多應(yīng)用需要從服務(wù)器加載功能所需的常為JSON或者XML格式的數(shù)據(jù)。在服務(wù)器端和客戶端使用相同的數(shù)據(jù)結(jié)構(gòu)很重要;

使用Autorelease Pool:在某些循環(huán)創(chuàng)建臨時變量處理數(shù)據(jù)時,自動釋放池以保證能及時釋放內(nèi)存;

正確選擇圖片加載方式:詳情閱讀UIImage加載方式

69.dispatch_barrier_async的作用是什么?

在并行隊列中,為了保持某些任務(wù)的順序,需要等待一些任務(wù)完成后才能繼續(xù)進行,使用 barrier 來等待之前任務(wù)完成,避免數(shù)據(jù)競爭等問題。

dispatch_barrier_async 函數(shù)會等待追加到Concurrent Dispatch Queue并行隊列中的操作全部執(zhí)行完之后,然后再執(zhí)行 dispatch_barrier_async 函數(shù)追加的處理,等 dispatch_barrier_async 追加的處理執(zhí)行結(jié)束之后,Concurrent Dispatch Queue才恢復(fù)之前的動作繼續(xù)執(zhí)行。

70.蘋果為什么要廢棄dispatch_get_current_queue?

dispatch_get_current_queue容易造成死鎖

71.如何用GCD同步若干個異步調(diào)用?(如根據(jù)若干個url異步加載多張圖片,然后在都下載完成后合成一張整圖)

使用Dispatch Group追加block到Global Group Queue,這些block如果全部執(zhí)行完畢,就會執(zhí)行Main Dispatch Queue中的結(jié)束處理的block

dispatch_queue_tqueue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

dispatch_group_tgroup= dispatch_group_create();

dispatch_group_async(group,queue, ^{/*加載圖片1 */});

dispatch_group_async(group,queue, ^{/*加載圖片2 */});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{// 合并圖片});

73.什么是 Runloop?RunLoop都有些模式?為什么 UIScrollView 的滾動會導(dǎo)致 NSTimer 失效?


model 主要是用來指定事件在運行循環(huán)中的優(yōu)先級的,分為:

NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默認,空閑狀態(tài)

UITrackingRunLoopMode:ScrollView滑動時

UIInitializationRunLoopMode:啟動時

NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合

蘋果公開提供的 Mode 有兩個:

NSDefaultRunLoopMode(kCFRunLoopDefaultMode)

NSRunLoopCommonModes(kCFRunLoopCommonModes)

定時器里面有個runoop mode,一般定時器是運行在defaultmode上。但是如果滑動了這個頁面,主線程runloop會轉(zhuǎn)到UITrackingRunLoopMode中,這時候就不能處理定時器了,造成定時器失效,原因就是runroop mode選錯了,解決辦法有2個

一個是更改mode為NSRunLoopCommonModes(無論runloop運行在哪個mode,都能運行),

還有種辦法是切換到主線程來更新UI界面的刷新

74.UITableViewCell上有個UILabel,顯示NSTimer實現(xiàn)的秒表時間,手指滾動cell過程中,label是否刷新,為什么?

這是否刷新取決于timer加入到Run Loop中的Mode是什么。

75.猜想runloop內(nèi)部是如何實現(xiàn)的?

functionloop()

{ ? initialize();

do{

var message = get_next_message();? ? ??

? process_message(message);? ?

?}while(message != quit);}

int ? main(intargc,char* argv[]){

//程序一直運行狀態(tài)

while(AppIsRunning) {

//睡眠狀態(tài),等待喚醒事件

id whoWakesMe = SleepForWakingUp();

//得到喚醒事件

idevent= GetEvent(whoWakesMe);

//開始處理事件

HandleEvent(event);??

? }return0;}


76.runloop和線程有什么關(guān)系?

主線程的run loop默認是啟動的。

對其它線程來說,run loop默認是沒有啟動的,如果你需要更多的線程交互則可以手動配置和啟動,如果線程只是去執(zhí)行一個長時間的已確定的任務(wù)則不需要。

在任何一個 Cocoa 程序的線程中,都可以通過以下代碼來獲取到當前線程的 run loop 。

run loop和線程是緊密相連的,可以這樣說run loop是為了線程而生,沒有線程,它就沒有存在的必要。Run loops是線程的基礎(chǔ)架構(gòu)部分

77.iOS 7的多任務(wù)添加了哪兩個新的 API? 各自的使用場景是什么?

后臺獲取(Background Fetch):后臺獲取使用場景是用戶打開應(yīng)用之前就使app有機會執(zhí)行代碼來獲取數(shù)據(jù),刷新UI。這樣在用戶打開應(yīng)用的時候,最新的內(nèi)容將已然呈現(xiàn)在用戶眼前,而省去了所有的加載過程。

推送喚醒(Remote Notifications):使用場景是使設(shè)備在接收到遠端推送后讓系統(tǒng)喚醒設(shè)備和我們的后臺應(yīng)用,并先執(zhí)行一段代碼來準備數(shù)據(jù)和UI,然后再提示用戶有推送。這時用戶如果解鎖設(shè)備進入應(yīng)用后將不會再有任何加載過程,新的內(nèi)容將直接得到呈現(xiàn)。

78.請解釋一下Handoff是什么,并簡述它是如何實現(xiàn)iOS、Mac/網(wǎng)頁應(yīng)用互通的。

Handoff 是在 OS X 和 iOS 跨設(shè)備連續(xù)性的拓展的用戶體驗的功能。Handoff 使用戶可以在一臺設(shè)備中開始一個活動,然后切換到其他設(shè)備并在該設(shè)備恢復(fù)相同的活動。例如,某個用戶從 Safari 移到登陸了相同的 Apple ID 賬戶的 iOS 設(shè)備瀏覽一篇很長的文章,相同的頁面會在 iOS 的 Safari 打開,并且滾動條位置和啟始設(shè)備相同,Handoff 使這個體驗盡可能平穩(wěn)順暢。


79.內(nèi)存管理主要分兩種模式,MRC 和ARC

1、MRC MRC是手動管理內(nèi)存,xcode4.1以及一下版本沒有ARC

引用計數(shù)概念 retain +1 release -1

內(nèi)存釋放池Release Pool:把需要釋放的內(nèi)存統(tǒng)一放在一個池子中,當池子被抽干后(drain),池子中所有的內(nèi)存空間也被自動釋放掉。內(nèi)存池的釋放操作分為自動和手動。自動釋放受runloop機制影響。

2、ARC ACR是自動管理內(nèi)存,自動引用計數(shù) 重點:循環(huán)引用,用weak 修飾來釋放(block,delegate會出現(xiàn)這種情況)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

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

  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛閱讀 1,998評論 0 7
  • 多線程、特別是NSOperation 和 GCD 的內(nèi)部原理。運行時機制的原理和運用場景。SDWebImage的原...
    LZM輪回閱讀 2,025評論 0 12
  • 史上最全的iOS面試題及答案 iOS面試小貼士———————————————回答好下面的足夠了----------...
    Style_偉閱讀 2,373評論 0 35
  • 白夜行 東野圭吾 人間失格 太宰治 雪萊詩選 雪萊 天黑以后 村上春樹
    XMHuang閱讀 231評論 0 0
  • 對于標題這句話,我以前理解銷售更多的是一種溝通技巧,無關(guān)與科學(xué)和藝術(shù)。但是,經(jīng)過奇點學(xué)院初級班的學(xué)習(xí)后才明...
    和順家閱讀 530評論 0 0