五、APP生命周期
APP有5種狀態(tài),分別是:
1、Not running未運(yùn)行:app沒(méi)啟動(dòng)或被迫終止。
2、Inactive未激活:當(dāng)前應(yīng)用正在前臺(tái)運(yùn)行,但是并不接收事件(當(dāng)前或許正在執(zhí)行其它代碼)。一般每當(dāng)應(yīng)用要從一個(gè)狀態(tài)切換到另一個(gè)不同的狀態(tài)時(shí),中途過(guò)渡會(huì)短暫停留在此狀態(tài)。唯一在此狀態(tài)停留時(shí)間比較長(zhǎng)的情況是:當(dāng)用戶鎖屏?xí)r,或者系統(tǒng)提示用戶去響應(yīng)某些(諸如電話來(lái)電、有未讀短信等)事件的時(shí)候。
3、Active激活:當(dāng)前應(yīng)用正在前臺(tái)運(yùn)行,并且接收事件。這是應(yīng)用正在前臺(tái)運(yùn)行時(shí)所處的正常狀態(tài)。
4、Backgroud后臺(tái):程序在后臺(tái)而且能執(zhí)行代碼,大多數(shù)程序進(jìn)入這個(gè)狀態(tài)后會(huì)在在這個(gè)狀態(tài)上停留一會(huì)。時(shí)間到之后會(huì)進(jìn)入掛起狀態(tài)(Suspended)。經(jīng)過(guò)特殊的請(qǐng)求后可以長(zhǎng)期處于Backgroud狀態(tài)。
5、Suspended掛起:程序在后臺(tái)不能執(zhí)行代碼。系統(tǒng)會(huì)自動(dòng)把程序變成這個(gè)狀態(tài)而且不會(huì)發(fā)出通知。當(dāng)掛起時(shí),程序還是停留在內(nèi)存中的,當(dāng)系統(tǒng)內(nèi)存低時(shí),系統(tǒng)就把掛起的程序清除掉,為前臺(tái)程序提供更多的內(nèi)存。

applicationDidEnterBackground:方法允許最多有5秒的時(shí)間去完成任何任務(wù)然后返回。實(shí)際中,此方法應(yīng)該盡可能快的返回。如果在時(shí)間到期之后,此方法沒(méi)有返回,則應(yīng)用即被kill掉,并且清除所占用的內(nèi)存。如果你的應(yīng)用確實(shí)需要更多的時(shí)間去執(zhí)行任務(wù),可以調(diào)用beginBackgroundTaskWithExpirationHandler:方法請(qǐng)求后臺(tái)執(zhí)行時(shí)間,然后啟動(dòng)一個(gè)能長(zhǎng)期執(zhí)行任務(wù)的線程。無(wú)論你是否啟動(dòng)一個(gè)執(zhí)行后臺(tái)任務(wù)的線程,applicationDidEnterBackground:方法都必須在5秒后退出。
UIViewController生命周期,子視圖布局在哪里布局?是在哪個(gè)方法?方法是在什么時(shí)機(jī)調(diào)用
代碼調(diào)用順序
- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil
- (void)loadView;
- (void)viewDidLoad;
- (void)viewWillAppear:(BOOL)animated;
- (void)viewWillLayoutSubviews API_AVAILABLE(ios(5.0));
// Called just after the view controller's view's layoutSubviews method is invoked. Subclasses can implement as necessary. The default is a no-op.
addSubViews:會(huì)調(diào)用此方法
控制器將要布局子控件,默認(rèn)不進(jìn)行任何操作。你可以在LayoutSubviews之前重寫(xiě)此方法布局子視圖。
- (void)viewDidLayoutSubviews API_AVAILABLE(ios(5.0));
- (void)viewDidAppear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated; // Called when the view is dismissed, covered or otherwise hidden. Default does nothing
- (void)viewDidDisappear:(BOOL)animated;
- (void)didReceiveMemoryWarning; // Called when the parent application receives a memory warning. On iOS 6.0 it will no longer clear the view by default.
dealloc



六、講講runtime,有什么體現(xiàn)
Runtime的特性主要是消息(方法)傳遞,如果消息(方法)在對(duì)象中找不到,就進(jìn)行轉(zhuǎn)發(fā)


動(dòng)態(tài)方法解析
首先,Objective-C運(yùn)行時(shí)會(huì)調(diào)用 +resolveInstanceMethod:或者 +resolveClassMethod:,讓你有機(jī)會(huì)提供一個(gè)函數(shù)實(shí)現(xiàn)。如果你添加了函數(shù)并返回YES, 那運(yùn)行時(shí)系統(tǒng)就會(huì)重新啟動(dòng)一次消息發(fā)送的過(guò)程。
如果resolve方法返回 NO ,運(yùn)行時(shí)就會(huì)移到下一步:forwardingTargetForSelector。
完整消息轉(zhuǎn)發(fā)
如果在上一步還不能處理未知消息,則唯一能做的就是啟用完整的消息轉(zhuǎn)發(fā)機(jī)制了。首先它會(huì)發(fā)送-methodSignatureForSelector:消息獲得函數(shù)的參數(shù)和返回值類型。如果-methodSignatureForSelector:返回nil ,Runtime則會(huì)發(fā)出 -doesNotRecognizeSelector: 消息,程序這時(shí)也就掛掉了。如果返回了一個(gè)函數(shù)簽名,Runtime就會(huì)創(chuàng)建一個(gè)NSInvocation 對(duì)象并發(fā)送 -forwardInvocation:消息給目標(biāo)對(duì)象。
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if ([NSStringFromSelector(aSelector) isEqualToString:@"foo"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];//簽名,進(jìn)入forwardInvocation
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL sel = anInvocation.selector;
Person *p = [Person new];
if([p respondsToSelector:sel]) {
[anInvocation invokeWithTarget:p];
}
else {
[self doesNotRecognizeSelector:sel];
}
}
method 的實(shí)現(xiàn)機(jī)制
Method 是一個(gè)objc_method結(jié)構(gòu)體,objc_method是類的一個(gè)方法描述
SELOC在編譯的時(shí)候,會(huì)根據(jù)方法簽名(參數(shù)類型),生成一個(gè)用來(lái)區(qū)分這個(gè)方法的唯一的一個(gè)ID,本質(zhì)上就是一個(gè)字符串,這個(gè)ID就是SEL類型的,在運(yùn)行的時(shí)候是通過(guò)方法的ID來(lái)查找方法的,只要方法的簽名相同,那么它們的ID都是相同的;不管是超類還是子類,還是其他類,只要簽名相同那么ID就是一樣的
不同的類可以擁有相同的selector, 不同的類的實(shí)例對(duì)象performSelector相同的selector時(shí),會(huì)在各自的方法鏈表中根據(jù)selector去查找具體的方法實(shí)現(xiàn)IMP,然后用這個(gè)方法實(shí)現(xiàn)去執(zhí)行具體的實(shí)現(xiàn)代碼
1.在OC中想要得到方法的SEL可以直接使用@selector指示符,SEL act = @selector(setAage:)2.使用函數(shù) NSSelectorFromString(@“setAge:”)3.SEL類型的方法名使用函數(shù)(NSString *)NSStringFromSelector(SEL)4.SEL轉(zhuǎn)成函數(shù)指針 IMP imp_setAge = [self methodForSelector:@selector(setAge:)]
IMP一個(gè)函數(shù)指針,指向方法實(shí)現(xiàn)的首地址
通過(guò)取得IMP,我們可以跳過(guò)runtime的消息傳遞機(jī)制,直接執(zhí)行IMP指向的函數(shù)實(shí)現(xiàn),這樣省去了runtime消息傳遞過(guò)程中所做的一系列查找操作,會(huì)比直接向?qū)ο蟀l(fā)送消息的效率高一些
方法的調(diào)用流程
檢測(cè)selector是否需要忽略檢查target是否nil,如果是nil就直接cleanup,然后return在target的Class中根據(jù)selector去找IMP尋找IMP的過(guò)程:1、在當(dāng)前class的方法緩存里面尋找(cache methodLists)2、找到了跳到對(duì)應(yīng)的方法實(shí)現(xiàn),沒(méi)找到繼續(xù)往下執(zhí)行3、從當(dāng)前class的方法列表里查找(methodLists),找到了添加到緩存列表里,然后跳轉(zhuǎn)到對(duì)應(yīng)的方法實(shí)現(xiàn);沒(méi)找到繼續(xù)往下執(zhí)行4、從superClass的緩存列表和方法列表里查找,直到找到基類為止,不論是在cache methodLists還是methodLists中找到IMP,都會(huì)先存入當(dāng)前class的cache methodList在跳轉(zhuǎn)到對(duì)應(yīng)的方法實(shí)現(xiàn)5、以上步驟還找不到IMP,則進(jìn)入到消息動(dòng)態(tài)處理和消息轉(zhuǎn)發(fā)流程
iOS中內(nèi)省的幾個(gè)方法?class方法和objc_getClass方法有什么區(qū)別

struct category_t {
const char *name; //名字
classref_t cls; //類的引用
struct method_list_t *instanceMethods;//實(shí)例方法列表
struct method_list_t *classMethods;//類方法列表
struct protocol_list_t *protocols;//協(xié)議列表
struct property_list_t *instanceProperties;//實(shí)例屬性列表
struct property_list_t *_classProperties;//類屬性列表
};
分類的實(shí)現(xiàn)原理是將category中的方法,屬性,協(xié)議數(shù)據(jù)放在category_t結(jié)構(gòu)體中,然后將結(jié)構(gòu)體內(nèi)的方法列表拷貝到類對(duì)象的方法列表中。
Category可以添加屬性,但是并不會(huì)自動(dòng)生成成員變量及set/get方法。因?yàn)閏ategory_t結(jié)構(gòu)體中并不存在成員變量。通過(guò)之前對(duì)對(duì)象的分析我們知道成員變量是存放在實(shí)例對(duì)象中的,并且編譯的那一刻就已經(jīng)決定好了。而分類是在運(yùn)行時(shí)才去加載的。那么我們就無(wú)法再程序運(yùn)行時(shí)將分類的成員變量中添加到實(shí)例對(duì)象的結(jié)構(gòu)體中。因此分類中不可以添加成員變量。
self與super的區(qū)別


weak的實(shí)現(xiàn)原理

Runtime應(yīng)用
應(yīng)用場(chǎng)景。
- 關(guān)聯(lián)對(duì)象(Objective-C Associated Objects)給分類增加屬性
- 方法魔法(Method Swizzling)方法添加和替換和KVO實(shí)現(xiàn)
- 消息轉(zhuǎn)發(fā)(熱更新)解決Bug(JSPatch)
- 實(shí)現(xiàn)NSCoding的自動(dòng)歸檔和自動(dòng)解檔
- 實(shí)現(xiàn)字典和模型的自動(dòng)轉(zhuǎn)換(MJExtension)
在 iOS中可以直接調(diào)用某個(gè)對(duì)象的消息方式有兩種:
一種是performSelector:withObject;
再一種就是NSInvocation。
第一種方式比較簡(jiǎn)單,能完成簡(jiǎn)單的調(diào)用。但是對(duì)于>2個(gè)的參數(shù)或者有返回值的處理,那performSelector:withObject就顯得有點(diǎn)有心無(wú)力了,那么在這種情況下,我們就可以使用NSInvocation來(lái)進(jìn)行這些相對(duì)復(fù)雜的操作
// 方法簽名中保存了方法的名稱/參數(shù)/返回值,協(xié)同NSInvocation來(lái)進(jìn)行消息的轉(zhuǎn)發(fā)
// 方法簽名一般是用來(lái)設(shè)置參數(shù)和獲取返回值的, 和方法的調(diào)用沒(méi)有太大的關(guān)系
//1、根據(jù)方法來(lái)初始化NSMethodSignature
NSMethodSignature *signature = [ViewController instanceMethodSignatureForSelector:@selector(run:)];
// NSInvocation中保存了方法所屬的對(duì)象/方法名稱/參數(shù)/返回值
//其實(shí)NSInvocation就是將一個(gè)方法變成一個(gè)對(duì)象
//2、創(chuàng)建NSInvocation對(duì)象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
//設(shè)置方法調(diào)用者
invocation.target = self;
//注意:這里的方法名一定要與方法簽名類中的方法一致
invocation.selector = @selector(run:);
NSString *way = @"byCar";
//這里的Index要從2開(kāi)始,以為0跟1已經(jīng)被占據(jù)了,分別是self(target),selector(_cmd)
[invocation setArgument:&way atIndex:2];
//3、調(diào)用invoke方法
[invocation invoke];
//實(shí)現(xiàn)run:方法
- (void)run:(NSString *)method{
}
七、講講runloop
詳細(xì)鏈接
runloop,運(yùn)行循環(huán),可使線程能隨時(shí)處理時(shí)間但并不退出,這也就是手機(jī)app在運(yùn)行時(shí)不會(huì)退出的原因。當(dāng)沒(méi)有事件時(shí),runloop會(huì)進(jìn)入休眠狀態(tài),有事件發(fā)生時(shí),runloop再進(jìn)行相應(yīng)的處理事件。runloop可以讓線程在需要做事的時(shí)候忙起來(lái),不需要的時(shí)候讓線程休眠。
Runloop的底層數(shù)據(jù)結(jié)構(gòu)(NSRunLoop是CFRunLoop的封裝):
CFRunLoop,RunLoop對(duì)象
Mode,運(yùn)行模式
Source,輸入源/事件源
Timer,定時(shí)源
Observer,觀察者
系統(tǒng)默認(rèn)注冊(cè)了5個(gè)Mode常用的有3個(gè) 常見(jiàn)的幾種Mode:
Default : App的默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行
UITracking: 界面跟蹤Mode,用于ScrollView`追蹤觸摸滑動(dòng),保證界面滑動(dòng)時(shí)不受其他Mode影響。
Common :并不是一個(gè)真的模式,它只是一個(gè)標(biāo)記,如:被標(biāo)記的 Timer可以在Default模式和UITracking下運(yùn)行。
八、講講assign,weak區(qū)別,講講淺拷貝,深拷貝有什么區(qū)別
[NSArray copy] 淺copy
[NSArray mutableCopy] 深copy
[NSMutableArray copy] 深copy
[NSMutableArray mutableCopy] 深copy
九、將block和delegate的區(qū)別,__block有什么作用


1.當(dāng)回調(diào)函數(shù)多于3個(gè)的時(shí)候,采用代理比較好
2.使用代碼塊容易造成循環(huán)引用,代理不會(huì)出現(xiàn)該問(wèn)題
3.其他情況下優(yōu)先考慮代碼塊
1.從源頭上理解和區(qū)別block和delegate
delegate運(yùn)行成本低,block的運(yùn)行成本高。
block出棧需要將使用的數(shù)據(jù)從棧內(nèi)存拷貝到堆內(nèi)存,當(dāng)然對(duì)象的話就是加計(jì)數(shù),使用完或者block置nil后才消除。delegate只是保存了一個(gè)對(duì)象指針,直接回調(diào),沒(méi)有額外消耗。就像C的函數(shù)指針,只多做了一個(gè)查表動(dòng)作。
2.從使用場(chǎng)景區(qū)別block和delegate
有多個(gè)相關(guān)方法。假如每個(gè)方法都設(shè)置一個(gè) block, 這樣會(huì)更麻煩。而 delegate 讓多個(gè)方法分成一組,只需要設(shè)置一次,就可以多次回調(diào)。當(dāng)多于 3 個(gè)方法時(shí)就應(yīng)該優(yōu)先采用 delegate。當(dāng)1,2個(gè)回調(diào)時(shí),則使用block。
delegate更安全些,比如: 避免循環(huán)引用。使用 block 時(shí)稍微不注意就形成循環(huán)引用,導(dǎo)致對(duì)象釋放不了。這種循環(huán)引用,一旦出現(xiàn)就比較難檢查出來(lái)。而 delegate 的方法是分離開(kāi)的,并不會(huì)引用上下文,因此會(huì)更安全些。
delegate回調(diào)返回的參數(shù)被限制在了 NS 類的范圍內(nèi),數(shù)量也很有限(當(dāng)然可以用直接調(diào)用方法的形式在繞過(guò),并不推薦;也可以用 Array 套著傳, 不過(guò)這樣需要有文檔支持,不然不夠清晰,回調(diào)方法也需要獨(dú)立的驗(yàn)證,故也不推薦)。
通過(guò)上面的知識(shí),可以簡(jiǎn)單說(shuō)他們的區(qū)別,block適合少數(shù)回調(diào),需要運(yùn)行內(nèi)存,多次回調(diào)容易出現(xiàn)循環(huán)引用 delegate回調(diào)次數(shù)不限制,回調(diào)對(duì)象需要知道當(dāng)前回調(diào)對(duì)象,delegate很安全不會(huì)引用上下文。
1.分析,ARC如果在塊對(duì)象中使用了__block指定的變量,那么這個(gè)變量將會(huì)被copy到堆內(nèi)存中,并且原變量也會(huì)指向這個(gè)堆內(nèi)存中的空間
十、講講gcd是怎么開(kāi)辟線程,底層是怎么實(shí)現(xiàn)的
同步執(zhí)行方式是不創(chuàng)建新線程的,就在當(dāng)前線程嗨。
線程按執(zhí)行方式分為同步、異步,按隊(duì)列管理分為串行并行,這樣有四種組合,加上常說(shuō)的主線程主隊(duì)列,那么結(jié)合執(zhí)行方式就有六種組合。
同步串行,不創(chuàng)建線程,所以還是在當(dāng)前線程一個(gè)一個(gè)做
同步并行,不創(chuàng)建線程,所以就算是并行,也還是在當(dāng)前線程一個(gè)一個(gè)做
異步串行,開(kāi)辟多一條線程,任務(wù)在新開(kāi)辟的一條線程里面一個(gè)一個(gè)做
異步并行,開(kāi)辟多條線程,任務(wù)在新開(kāi)辟的線程里面一起做
同步主隊(duì),阻塞
異步主隊(duì),同異步串行,因?yàn)橹麝?duì)就是串行,但是不開(kāi)辟新線程,因?yàn)橹骶€程是全局的單例的
2>GCD 只支持 FIFO(先進(jìn)先出) 的隊(duì)列,NSOperationQueue 可以很方便地調(diào)整執(zhí) 行順序、設(shè)置最大并發(fā)數(shù)量
在異步線程中下載很多圖片,如果失敗了,該如何處理?請(qǐng)結(jié)合RunLoop來(lái)談?wù)劷鉀Q方案
1> 重新下載圖片
2>下載完畢, 利用 RunLoop 的輸入源(輸入源(input source)(傳遞異步事件))回到主線程刷新 UIImageVIUew
NSOperation是怎么處理最大并發(fā)數(shù)和線程依賴(用GCD實(shí)現(xiàn))
最大并發(fā)數(shù):用信號(hào)量控制最大數(shù),如果并發(fā)數(shù)設(shè)置為4,那信號(hào)量為3,執(zhí)行完了發(fā)送信號(hào)量不然就等著
線程依賴:使用調(diào)度組dispatch_group_create和GCD中的柵欄和wait也能實(shí)現(xiàn)同樣的效果
十一、講講ARC的原理
自動(dòng)的引用計(jì)數(shù)

如果放一張很大的圖在項(xiàng)目加載,怎么才能檢查到那個(gè)內(nèi)存暴漲,哪個(gè)方法出現(xiàn)內(nèi)存暴漲
利用Xcode自帶的instrument檢查內(nèi)存占用情況,并定位內(nèi)存不斷增大的原因
點(diǎn)擊profile。出現(xiàn)如下界面,選Allocations instrument
內(nèi)存泄露 Instruments之Leaks

十二、講講有哪些區(qū)?全局變量,局部變量,靜態(tài)變量存放在哪里
棧是先進(jìn)后出的隊(duì)列
堆都是動(dòng)態(tài)分配的,沒(méi)有靜態(tài)分配的堆。棧有兩種分配方式:靜態(tài)分 配和動(dòng)態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動(dòng) 態(tài)分配是有 alloc 函數(shù)進(jìn)行分配的
局部變量:棧區(qū)
局部靜態(tài)變量:靜態(tài)區(qū)
全局變量:靜態(tài)區(qū)的常量區(qū)
全局靜態(tài)變量:靜態(tài)區(qū)
內(nèi)存分四個(gè)區(qū):靜態(tài)區(qū),棧區(qū),堆區(qū),代碼區(qū)

d、一個(gè)有10個(gè)整型數(shù)的數(shù)組 inta[10];
e、一個(gè)有10個(gè)指針的數(shù)組,該指針是指向一個(gè)整型數(shù)的 inta[10];
f、一個(gè)指向有10個(gè)整型數(shù)數(shù)組的指針 int(a)[10];
十三、有關(guān)HTTP、TCP/UDP
OSI(Open System Interconnection)模型定制的七層標(biāo)準(zhǔn)模型分別是:
物理層:物理層是OSI參考模型的最低層,它利用傳輸介質(zhì)為數(shù)據(jù)鏈路層提供物理連接。它主要關(guān)心的是通過(guò)物理鏈路從一個(gè)節(jié)點(diǎn)向另一個(gè)節(jié)點(diǎn)傳送比特流,物理鏈路可能是銅線、衛(wèi)星、微波或其他的通訊媒介。它關(guān)心的問(wèn)題有:多少伏電壓代表1?多少伏電壓代表0?時(shí)鐘速率是多少?采用全雙工還是半雙工傳輸?總的來(lái)說(shuō)物理層關(guān)心的是鏈路的機(jī)械、電氣、功能和規(guī)程特性。主要有: 以太網(wǎng) · 調(diào)制解調(diào)器 · 電力線通信(PLC) · SONET/SDH · G.709 · 光導(dǎo)纖維 · 同軸電纜 · 雙絞線等
數(shù)據(jù)鏈路層:數(shù)據(jù)鏈路層是為網(wǎng)絡(luò)層提供服務(wù)的,解決兩個(gè)相鄰結(jié)點(diǎn)之間的通信問(wèn)題,傳送的協(xié)議數(shù)據(jù)單元稱為 數(shù)據(jù)幀。只要協(xié)議有:Wi-Fi( IEEE 802.11) · WiMAX( IEEE 802.16) ·ATM · DTM · 令牌環(huán) · 以太網(wǎng) ·FDDI · 幀中繼 · GPRS · EVDO ·HSPA · HDLC · PPP · L2TP ·PPTP · ISDN·STP 等
網(wǎng)絡(luò)層:網(wǎng)絡(luò)層是為傳輸層提供服務(wù)的,傳送的協(xié)議數(shù)據(jù)單元稱為 數(shù)據(jù)包或分組。該層的主要作用是解決如何使數(shù)據(jù)包通過(guò)各結(jié)點(diǎn)傳送的問(wèn)題,即通過(guò) 路徑選擇算法( 路由)將數(shù)據(jù)包送到目的地。另外,為避免 通信子網(wǎng)中出現(xiàn)過(guò)多的數(shù)據(jù)包而造成 網(wǎng)絡(luò)阻塞,需要對(duì)流入的數(shù)據(jù)包數(shù)量進(jìn)行控制( 擁塞控制)。當(dāng)數(shù)據(jù)包要跨越多個(gè)通信子網(wǎng)才能到達(dá)目的地時(shí),還要解決網(wǎng)際互連的問(wèn)題。IP (IPv4 · IPv6) · ICMP· ICMPv6·IGMP ·IS-IS · IPsec · ARP · RARP等
傳輸層:TCP · UDP · TLS · DCCP · SCTP · RSVP · OSPF 等
會(huì)話層:會(huì)話層主要功能是管理和協(xié)調(diào)不同主機(jī)上各種進(jìn)程之間的通信(對(duì)話),即負(fù)責(zé)建立、管理和終止應(yīng)用程序之間的會(huì)話。會(huì)話層得名的原因是它很類似于兩個(gè)實(shí)體間的會(huì)話概念。例如,一個(gè)交互的用戶會(huì)話以登錄到計(jì)算機(jī)開(kāi)始,以注銷結(jié)束。
表示層:表示層處理流經(jīng)結(jié)點(diǎn)的 數(shù)據(jù)編碼的表示方式問(wèn)題,以保證一個(gè)系統(tǒng)應(yīng)用層發(fā)出的信息可被另一系統(tǒng)的應(yīng)用層讀出。如果必要,該層可提供一種標(biāo)準(zhǔn)表示形式,用于將計(jì)算機(jī)內(nèi)部的多種 數(shù)據(jù)表示格式轉(zhuǎn)換成 網(wǎng)絡(luò)通信中采用的標(biāo)準(zhǔn)表示形式。數(shù)據(jù)壓縮和加密也是表示層可提供的轉(zhuǎn)換功能之一。

四次揮手:
所謂四次揮手(Four-Way Wavehand)即終止TCP連接,就是指斷開(kāi)一個(gè)TCP連接時(shí),需要客戶端和服務(wù)端總共發(fā)送4個(gè)包以確認(rèn)連接的斷開(kāi)。在socket編程中,這一過(guò)程由客戶端或服務(wù)端任一方執(zhí)行close來(lái)觸發(fā)。
(1)第一次揮手:客戶端發(fā)送一個(gè)FIN包,用來(lái)關(guān)閉客戶端和服務(wù)器的數(shù)據(jù)傳送,客戶端進(jìn)入FIN_WAIT_1狀態(tài)。
(2)第二次揮手:服務(wù)端收到FIN包后,發(fā)送一個(gè)ACK給客戶端,服務(wù)端進(jìn)入CLOSE_WAIT狀態(tài)。
(3)第三次揮手:服務(wù)端發(fā)送一個(gè)FIN包,用來(lái)關(guān)閉服務(wù)端到客服端的數(shù)據(jù)傳送,服務(wù)端進(jìn)入LAST_ACK狀態(tài)。
(4)第四次揮手:客戶端收到FIN包,客戶端進(jìn)入TIME_WAIT狀態(tài),接著發(fā)送一個(gè)ACK包給服務(wù)端,服務(wù)端進(jìn)入關(guān)閉狀態(tài),完成四次揮手。
實(shí)際上socket是對(duì)TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個(gè)調(diào)用接口(API),通過(guò)Socket,才能使用TCP/IP協(xié)議。
總結(jié):
1.HTTP是應(yīng)用層協(xié)議,定義的是傳輸數(shù)據(jù)的內(nèi)容以及格式的規(guī)范。
2.TCP是底層通訊協(xié)議,定義的是數(shù)據(jù)傳輸和連接方式的規(guī)范。
3.Socket可以支持不同的傳輸層協(xié)議(TCP/UDP),當(dāng)使用TCP協(xié)議進(jìn)行連接時(shí),該Socket連接就是一個(gè)TCP連接,Socket是發(fā)動(dòng)機(jī),提供了網(wǎng)絡(luò)通信的能力
Socket是傳輸控制層接口,WebSocket是應(yīng)用層協(xié)議。
一個(gè)完成的HTTP協(xié)議要包含三個(gè)部分: 請(qǐng)求行、請(qǐng)求頭、請(qǐng)求體
請(qǐng)求行:主要包含請(qǐng)求方法、請(qǐng)求路徑、HTTP協(xié)議版本
請(qǐng)求頭:主要包含了對(duì)客戶端環(huán)境的描述,客戶端請(qǐng)求的主機(jī)地址信息。
請(qǐng)求體:客戶端發(fā)給服務(wù)器的具體數(shù)據(jù),比如文件/數(shù)據(jù)
HTTP協(xié)議規(guī)定:1個(gè)完整的HTTP響應(yīng)中包含以下內(nèi)容:
狀態(tài)行:包含了HTTP協(xié)議版本、狀態(tài)嗎、狀態(tài)碼對(duì)應(yīng)的英文名稱HTTP/1.1 200 OK
響應(yīng)頭:包含了對(duì)服務(wù)器的描述,對(duì)返回?cái)?shù)據(jù)的描述。
實(shí)體內(nèi)容:服務(wù)器返回給客戶端的具體數(shù)據(jù)(圖片/html/文件...)
HTTP協(xié)議定義了很多方法對(duì)應(yīng)不同的資源操作,其中最常用的是GET 和 POST 方法.
GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH
增:PUT、刪:DELETE、改:POST、查:GET
GET 和 POST 都是和服務(wù)器提交參數(shù)/通訊的一種方式。GET 參數(shù)不能太長(zhǎng)<1024B POST 沒(méi)有限制<4G
GET 不能上傳文件, POST 可以上傳文件
(1)JSON底層原理:遍歷字符串中的字符,最終根據(jù)格式規(guī)定的特殊字符,比如{}、[]、:等進(jìn)行區(qū)分,{}號(hào)表示字典,[]號(hào)表示數(shù)組,:號(hào)是字典的鍵和值的分水嶺,最終仍是將JSON轉(zhuǎn)化為字典,只不過(guò)字典中的值可能是“字典、數(shù)組或者字符串而已”。
在網(wǎng)絡(luò)請(qǐng)求中如何提高性能

十四、數(shù)據(jù)持久化存儲(chǔ)方案有哪些?
1)plist 文件(屬性列表)
2)preference(偏好設(shè)置)
- NSKeyedArchiver(歸檔)
4)SQlite - CoreData
十五、計(jì)時(shí)器 NSTimer 循環(huán)引用
- 選擇合適的時(shí)機(jī)手動(dòng)釋放timer(該方法并不太合理)
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.timer invalidate];
self.timer=nil;
}
- timer使用block方式添加Target-Action
- 給self添加中間件proxy
考慮到循環(huán)引用的原因,改方案就是需要打破這些相互引用關(guān)系,因此添加一個(gè)中間件,弱引用self,同時(shí)timer引用了中間件,這樣通過(guò)弱引用來(lái)解決了相互引用,如圖:
使用NSProxy解決NSTimer、CADisplayLink等循環(huán)引用
#import <Foundation/Foundation.h>
@interface YHProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
@end
#import "YHProxy.h"
@implementation YHProxy
+ (instancetype)proxyWithTarget:(id)target
{
// NSProxy對(duì)象不需要調(diào)用init,因?yàn)樗緛?lái)就沒(méi)有init方法
YHProxy *proxy = [YHProxy alloc];
proxy.target = target;
return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
[invocation invokeWithTarget:self.target];
}
@end
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[YHProxy proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];
十六、如何減小一個(gè)應(yīng)用程序占用存儲(chǔ)空間?
檢查程序 去掉多余的 xib。iOS App Store 相關(guān)因素作為提交到 App Store 中 app 里的可執(zhí)行文件是被加過(guò)密的。加密的副作用是可執(zhí)行 文件的壓縮效果沒(méi)有之前的好了。Build Settings 編譯選項(xiàng),將 build setting 中的 Optimization Level 設(shè)置為 Fastest, Smallest [-Os]; 將 build setting 中 的 Strip Debug Symbols During Copy 設(shè) 置 為 YES(COPY_PHASE_STRIP = YES),這樣可以減小編譯出二進(jìn)制文件的尺
寸。Target 針對(duì)較少的 CPUs 對(duì)程序指定的特定 CPU 類型做優(yōu)化處理, 以生成相對(duì)于的可執(zhí)行文件。不同的硬件,將運(yùn)行不同的可執(zhí)行代碼。 雖然這樣優(yōu)化后的程序,只能針對(duì)某些設(shè)備運(yùn)行,但是這大大減小可 執(zhí)行程序的大小。要想只設(shè)定特定類型的CPUs,可以修改build setting 中的 Architectures,將其從 Standard $(ARCHS_STANDARD)修改為你希 望支持的列表中對(duì)應(yīng)的特定類型 CPU。有效的 CPU 名稱列在 Valid Architectures (VALID_ARCHS) build setting 中。請(qǐng)不要修改 Valid Architectures 設(shè)置項(xiàng),最好由 Xcode 管理。盡量使用 8-bit 圖片。使 用 8-bit 的 PNG 圖片,比 32-bit 的圖片能減少 4 倍的壓縮率。由于 8-bit 的圖片支持最多 256 種不同的顏色,所以 8-bit 的圖片一般只應(yīng)該用 于一小部分的顏色圖片。例如灰度圖片最好使用 8-bit。
十七、KVO、KVC
KVO


KVC

十八、怎么理解oc面向?qū)ο?,oc有多重繼承嗎?
面向?qū)ο蟮娜筇匦裕悍庋b、繼承和多態(tài)。
封裝就是把數(shù)據(jù)及其操作的實(shí)現(xiàn)細(xì)節(jié)隱藏起來(lái),對(duì)外公開(kāi)接口(即“合理隱藏,合理暴露”)。這樣可以保證數(shù)據(jù)安全性,外部不能隨便訪問(wèn)類的成員變量,只能通過(guò)(setter,getter)方法訪問(wèn)。
繼承的作用是抽取出了重復(fù)的代碼,建立了類和類之間的聯(lián)系
多態(tài):由繼承演變而來(lái),父類指針指向子類對(duì)象,即同一類型的對(duì)象調(diào)用同一方法,表現(xiàn)出不同行為
oc不能多繼承,但是可以通過(guò)其他方法實(shí)現(xiàn)“多繼承”效果
方法一:采用組合的模式來(lái)代替繼承模式。
方法二:
雖然OC在語(yǔ)法上禁止類使用多繼承,但是在協(xié)議的遵守上卻允許使用多繼承。所以可以用協(xié)議來(lái)實(shí)現(xiàn)多繼承。但是協(xié)議只能提供接口,而沒(méi)有提供實(shí)現(xiàn)方式,如果只是想多繼承基類的接口,那么遵守多協(xié)議無(wú)疑是最好的方法,而既需要多繼承接口,又要多繼承其實(shí)現(xiàn),那么協(xié)議是無(wú)能為力了。多協(xié)議遵守比較簡(jiǎn)單,具體的實(shí)現(xiàn)方式這里就不講了
方法三:給NSObject添加category
因?yàn)镹SObject是所有類的父類,給NSObject添加類別就相當(dāng)于給所有的類添加了這些方法,所有的類都可以使用這些方法。
十九、項(xiàng)目中有用到哪些組件化
1、常?的三種方案
1.1 URL Scheme
使 URL 處理本地的跳轉(zhuǎn)通過(guò)中間層進(jìn)?注冊(cè) & 調(diào)? (load方法里把被調(diào)用者注冊(cè)到中間層)-
代表是MGJRouter注冊(cè)表?需使用反射 非懶加載 / 注冊(cè)表的維護(hù) / 參數(shù)
MGJRouter就一個(gè)單例類,使用前需要通過(guò)注冊(cè)組件,調(diào)用方通過(guò)URL調(diào)用服務(wù)方頁(yè)面,通過(guò)路由表的映射關(guān)系進(jìn)行關(guān)聯(lián),調(diào)用方可以傳入復(fù) 雜的參數(shù)、對(duì)象
實(shí)現(xiàn)原理:
App啟動(dòng)時(shí)實(shí)例化各組件模塊,然后這些組件向ModuleManager注冊(cè)Url,有些時(shí)候不需要實(shí)例化,使用class注冊(cè)
當(dāng)組件A需要調(diào)用組件B時(shí),向ModuleManager傳遞URL,參數(shù)跟隨URL以GET方式傳遞,類似openURL。然后由ModuleManager負(fù)責(zé)調(diào)度組件B,最后完成任務(wù)。
1.2 Target - Action
抽離業(yè)務(wù)邏輯通過(guò)中間層進(jìn)行調(diào)?中間層使? runtime 反射中間層代碼優(yōu)化
CTMediator
原理是通過(guò)oc的runtime、category特性動(dòng)態(tài)獲取模塊,例如通過(guò)NSClassFromString獲取類并創(chuàng)建實(shí)例,通過(guò)performSelector + NSInvocation動(dòng)態(tài)調(diào)用方法。
實(shí)現(xiàn)原理:
1、利用分類為路由添加新接口,在接口中通過(guò)字符串獲取對(duì)應(yīng)的類
2、通過(guò)runtime創(chuàng)建實(shí)例,動(dòng)態(tài)調(diào)用實(shí)例的方法
1.3 Protocol - Class 匹配
增加 Protocol Wrapper層 (中間件先注冊(cè)Protocol和Class對(duì)應(yīng)關(guān)系,將protocol和對(duì)應(yīng)的類進(jìn)行字典匹配)中間件返回 Protocol 對(duì)應(yīng)的 Class,然后動(dòng)態(tài)創(chuàng)建實(shí)例解決硬編碼的問(wèn)題- BeeHive
- protocol比較典型的三方框架就是阿里的BeeHive。BeeHive借鑒了Spring Service、Apache DSO的架構(gòu)理念,采用AOP+擴(kuò)展App生命周期API形式,將業(yè)務(wù)功能、基礎(chǔ)功能模塊以模塊方式以解決大型應(yīng)用中的復(fù)雜問(wèn)題,并讓模塊之間以Service形式調(diào)用,將復(fù)雜問(wèn)題切分,以AOP方式模塊化服務(wù)。
- BeeHive 核心思想
- 1、各個(gè)模塊間調(diào)用從直接調(diào)用對(duì)應(yīng)模塊,變成調(diào)用Service的形式,避免了直接依賴。
- 2、App生命周期的分發(fā),將耦合在AppDelegate中邏輯拆分,每個(gè)模塊以微應(yīng)用的形式獨(dú)立存在。
二十、id和NSObject*的區(qū)別
1、id是objc_object的結(jié)構(gòu)體指針,定義是typedef struct objc_object id,所有的oc對(duì)象都可以用id指向,而且在編譯階段不作類型檢查。id對(duì)象調(diào)用這個(gè)對(duì)象存在的方法在編譯階段都不會(huì)報(bào)錯(cuò),但是調(diào)用不存在的方法會(huì)。
2、NSObject指向的必須是NSObject的子類,調(diào)用的方法也必須是NSObject子類的方法,否則必須作強(qiáng)制的類型轉(zhuǎn)換。
3、不是所有的oc對(duì)象都是NSObject的子類,比如說(shuō)有一些繼承自NSProxy,NSObject*可指向的對(duì)象是id的子集。