這個(gè)欄目將持續(xù)更新--請(qǐng)iOS的小伙伴關(guān)注!
為什么我要寫這篇文章呢?
首先是為了提升自己,因?yàn)樽约涸谛」荆幌胱兂杉儤I(yè)務(wù)型程序員;
然后是公司閑暇時(shí)間多,有時(shí)間去了解并整理這些;
其實(shí)是自己有一個(gè)開(kāi)發(fā)群,很容易收集問(wèn)題;
最后是把整個(gè)文章當(dāng)成一個(gè)筆記的作用,時(shí)不時(shí)的翻閱。
問(wèn)題列表匯總,你可以復(fù)制其中的問(wèn)題全文搜索找到對(duì)應(yīng)的答案。
有記錄面試題, 希望對(duì)你們有幫助~! 少走一些彎路!
問(wèn)題目錄
- 面向?qū)ο笤O(shè)計(jì)原則
- iOS應(yīng)用導(dǎo)航模式有哪些
- iOS持久化方式有哪些NSClassFromString加載靜態(tài)庫(kù)中的類什么情況是nilid和NSObject*的區(qū)別
- 簡(jiǎn)單描述一下Runtime
- Runtime給類添加屬性、成員變量
- KVO原理
- Property修飾符
- 程序內(nèi)存分區(qū)extern的作用
- 指針函數(shù)/函數(shù)指針/Block
- __weak、__strong、__block理解
- 事件傳遞鏈/事件響應(yīng)鏈
- 簡(jiǎn)述RunLoopNSTimer原理
- 簡(jiǎn)述GCD
- 自動(dòng)釋放池
- iOS中的定時(shí)器UIView/UILayer關(guān)系
- 簡(jiǎn)述你了解的鎖
- ISO七層、TCP/IP四層協(xié)議
- 什么是ARC
- iOS類和結(jié)構(gòu)體有什么區(qū)別
- iOS通知和協(xié)議的區(qū)別
- iOS內(nèi)存使用注意事項(xiàng)和優(yōu)化
- ViewController完整生命周期
- frame和bounds區(qū)別@synthesize和@dynamic的作用
- SDWebImage作用
- XML解析方式
- AFNetWorking作用
- Http協(xié)議特點(diǎn),GET/POST請(qǐng)求區(qū)別
- Socket連接和Http連接區(qū)別
- Tcp三次握手、四次揮手
- performSelector傳三個(gè)參數(shù)(未解答)
- main方法前過(guò)程
- 線程安全方法NSOperationQueue和GCD區(qū)別聯(lián)系
- iOS常用設(shè)計(jì)模式
- 簡(jiǎn)述Block
- 消息動(dòng)態(tài)處理/轉(zhuǎn)發(fā)流程weak變量怎么置為nil對(duì)nil發(fā)消息會(huì)發(fā)生什么
- 安全區(qū)域的理解UITableView優(yōu)化方法
- ssl/tls證書作用
- MVC、MVP、MVVM
———————————————————————————————————————————————
由于答案太多,我做了一個(gè)PDF文檔,由于簡(jiǎn)書不能上傳文件,需要答案可以加小編我的iOS交流群761407670,密碼‘000‘’在里面獲取文檔,也歡迎招聘者,找工作的來(lái),提供一個(gè)更大的平臺(tái)
回答 答案↓↓↓↓↓
面向?qū)ο笤O(shè)計(jì)原則
單一職責(zé)原則,開(kāi)閉原則,依賴倒置原則(面向接口編程),迪米特原則,里氏替換原則,接口隔離原則。
了解更多
談?wù)劽嫦驅(qū)ο笤O(shè)計(jì)(OOD)原則
iOS應(yīng)用導(dǎo)航模式有哪些
這個(gè)問(wèn)題更多是設(shè)計(jì)人員考慮的,不過(guò)我們也需要了解,不然我們都不知道UITabBarController和UINavigationController等存在的意義是啥。
iOS應(yīng)用屬于客戶端應(yīng)用,問(wèn)題其實(shí)是問(wèn)下面兩個(gè)部分:
1:什么是導(dǎo)航模式?客戶端導(dǎo)航模式有哪些常見(jiàn)的?
2:iOS中存在哪些導(dǎo)航模式?
導(dǎo)航模式
導(dǎo)航模式:將信息以最優(yōu)的方式組織起來(lái)展現(xiàn)給用戶。
客戶端常見(jiàn)模式:tab、抽屜、列表、平鋪/輪播、宮格和懸浮icon等。
注:不要太在意名稱,你會(huì)在網(wǎng)上搜到一種模式有多種名稱。
了解更多
移動(dòng)端導(dǎo)航的七種設(shè)計(jì)模式
8種移動(dòng)APP導(dǎo)航設(shè)計(jì)模式大對(duì)比
iOS中導(dǎo)航模式
這里并不是問(wèn)你哪些控件/控制器對(duì)應(yīng)這些導(dǎo)航模式,所以iOS具有上面提到的所有導(dǎo)航模式。
iOS持久化方式有哪些
首先這里的持久化指的是數(shù)據(jù)持久化,目前客戶端的持久化也只有這一個(gè)含義。
為何要持久化:iOS開(kāi)發(fā)可以沒(méi)有持久化,持久化更多的是業(yè)務(wù)需求;比如記錄用戶是否登陸,下次進(jìn)應(yīng)用不需要再登陸。
因?yàn)閕OS的沙盒機(jī)制,所以持久化分為兩類:沙盒內(nèi)和沙盒外。
沙盒內(nèi)
NSKeyedArchiver
只要遵循了NSCoding協(xié)議并正確實(shí)現(xiàn)了initWithCoder和encodeWithCoder方法的類都可以通過(guò)NSKeyedArchiver來(lái)序列化。
歸檔使用archiveRootObject,解歸檔使用unarchiveObjectWithFile;需要指定文件路徑。
NSUserDefaults
[NSUserDefaults standardUserDefaults]獲取NSUserDefaults對(duì)象,以key-value方式進(jìn)行持久化操作。
plist
寫入使用writeToFile,讀取使用xxxWithContentsOfFile;需要指定文件路徑。
數(shù)據(jù)庫(kù)
數(shù)據(jù)庫(kù)無(wú)疑是大量數(shù)據(jù)最好的持久化方案,數(shù)據(jù)庫(kù)目前有:sqlite、CoreData和Realm等。這里就不用回答FMDB它只是封裝了sqlite而已。
文件
這里要和plist區(qū)分一下,plist方式是字典/數(shù)組數(shù)據(jù)格式寫入文件;而這里的文件方式不限數(shù)據(jù)格式。
沙盒外
KeyChain
沙盒內(nèi)的方式在應(yīng)用被刪除后數(shù)據(jù)都會(huì)丟失,如果想要不丟失則需要使用KeyChain。
KeyChain本質(zhì)是一個(gè)sqlite數(shù)據(jù)庫(kù),其保存的所有數(shù)據(jù)都是加密過(guò)的。
KeyChain分為私有和公有,公有則需要指定group,一個(gè)group中的應(yīng)用可以共享此KeyChain。
使用KeyChain過(guò)程中要理解下面幾個(gè)問(wèn)題:
1:自己使用的KeyChain和系統(tǒng)自帶的KeyChain數(shù)據(jù)是隔離的,內(nèi)部應(yīng)該是不同數(shù)據(jù)庫(kù)文件;
2:KeyChain數(shù)據(jù)可備份到iCloud中;
3:不需要聯(lián)網(wǎng),也不用登陸iCloud賬號(hào);一個(gè)設(shè)備一個(gè)sqlite數(shù)據(jù)庫(kù),但是不同應(yīng)用組不共享數(shù)據(jù);
4:要在另一臺(tái)設(shè)備上使用當(dāng)前設(shè)備存儲(chǔ)的KeyChain信息,需要當(dāng)前設(shè)備進(jìn)行數(shù)據(jù)備份,
再在另一設(shè)備上復(fù)原數(shù)據(jù);比較常用的是iCloud備份方式;
5:系統(tǒng)自帶的KeyChain中賬號(hào)密碼分類數(shù)據(jù)可在系統(tǒng)設(shè)置->賬號(hào)與密碼里面看到,
你退出iCloud賬號(hào)還是存在,只是iCloud會(huì)幫你備份如果你設(shè)置了的話;這個(gè)和照片是一樣的道理。
了解更多
持久化
iOS 數(shù)據(jù)持久化的幾種方法
聊聊iOS KeyChain
NSClassFromString加載靜態(tài)庫(kù)中的類什么情況是nil
NSClassFromString動(dòng)態(tài)加載是OC中runtime的一個(gè)方法,用來(lái)從字符串得到一個(gè)class對(duì)象,當(dāng)系統(tǒng)給應(yīng)用分配的運(yùn)行內(nèi)存中沒(méi)有這個(gè)類時(shí)會(huì)返回nil;靜態(tài)庫(kù)在鏈接階段會(huì)被寫入到執(zhí)行文件,這里要注意了,如果工程中沒(méi)有用到靜態(tài)庫(kù)中的某些類,那么這些類是不會(huì)寫入到執(zhí)行文件的,自然系統(tǒng)給應(yīng)用分配的運(yùn)行內(nèi)存中沒(méi)有這個(gè)類。所以NSClassFromString返回nil只在工程中沒(méi)有使用到該類的情況下。
有人可能會(huì)問(wèn)了,那我可以在運(yùn)行的時(shí)候手動(dòng)加載庫(kù)到運(yùn)行內(nèi)存嗎?動(dòng)態(tài)庫(kù)是可以的,這樣就是插件化了;靜態(tài)庫(kù)因?yàn)樽詈蟠虬陌餂](méi)有這個(gè)文件了,所以沒(méi)辦法獲取到該靜態(tài)庫(kù)。而動(dòng)態(tài)庫(kù)在工程General的Embedded Binaries中加入該動(dòng)態(tài)庫(kù),則打包后包內(nèi)有一個(gè)framework文件夾專門放動(dòng)態(tài)庫(kù),則可以實(shí)現(xiàn)手動(dòng)加載。
又有人問(wèn)了,General的Linked Frameworks and Libraries又是什么作用呢?好吧一般我們都忽略這個(gè)了,因?yàn)橥先霂?kù)到工程默認(rèn)就會(huì)把該庫(kù)加入到此處,如果不加且你工程直接使用了該類則build通不過(guò);使用workspace設(shè)置工程依賴實(shí)現(xiàn)組件化等為了解決相應(yīng)問(wèn)題而使用此實(shí)現(xiàn)思路情況下,要在適當(dāng)?shù)膒roject的此處手動(dòng)添加被依賴庫(kù),如果不加且你工程直接使用了該類則build通不過(guò)。
了解更多
NSClassFromString類的動(dòng)態(tài)加載
iOS中的庫(kù)
id和NSObject*的區(qū)別
這個(gè)問(wèn)題沒(méi)有固定的答案,只需要答到比較重要的點(diǎn)就可以了。
你可以從<objc .h="" style="box-sizing: border-box;">中看到如下的內(nèi)容。
id的定義:</objc>
typedef struct objc_object {
struct objc_class *isa; } *id;
NSObject的定義:
@interface NSObject { struct objc_class *isa;
}
開(kāi)始分析得先知道這樣一個(gè)事實(shí),iOS中不是所有的類都繼承自NSObject:
@interface NSProxy { struct objc_class *isa;
}
所以也就得出了答案:id可以指向oc中的任何對(duì)象,而NSObject*只能指向NSObject及子類對(duì)象。
了解更多
簡(jiǎn)單描述一下Runtime
Runtime是一個(gè)運(yùn)行時(shí)系統(tǒng),用來(lái)執(zhí)行編譯鏈接后的可執(zhí)行文件;它將很多靜態(tài)語(yǔ)言在編譯和鏈接時(shí)期做的事放到了運(yùn)行時(shí)來(lái)處理。這種我們寫代碼更具靈活性,如我們可以把消息轉(zhuǎn)發(fā)給我們想要的對(duì)象,或者隨意交換一個(gè)方法的實(shí)現(xiàn)等。
objc_class的定義:
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
Class _Nullable super_class OBJC2_UNAVAILABLE; const char * _Nonnull name OBJC2_UNAVAILABLE; long version OBJC2_UNAVAILABLE; long info OBJC2_UNAVAILABLE; long instance_size OBJC2_UNAVAILABLE; struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;};
從中可以看出,我們可以修改一些值達(dá)到運(yùn)行時(shí)改變?cè)行袨榈哪康模槐热缃o對(duì)象調(diào)用方法是從methodLists查找方法實(shí)現(xiàn)等。
延伸內(nèi)容舉個(gè)例子:Runtime是怎么對(duì)對(duì)象發(fā)送消息的呢?
先需要了解object_class中isa和super_class指的是什么。
其中圖最左邊列表示類的實(shí)例對(duì)象,中間列表示類,右邊列表示元類。
最左邊實(shí)例對(duì)象只存在一個(gè)objc_object結(jié)構(gòu)體;
類則有objc_object和objc_class兩個(gè)結(jié)構(gòu)體,因?yàn)轭愂窃惖膶?shí)例對(duì)象;
元類則只有一個(gè)objc_class結(jié)構(gòu)體;
對(duì)類、實(shí)例對(duì)象調(diào)用方法都是從objc_object中isa查找。
接下來(lái)我們來(lái)分析MyClass *myClass = [[MyClass alloc] init];[myClass test]。
首先我們要拆分成MyClass *myClass = [MyClass alloc];myClass = [myClass init];[myClass test]。
1:先會(huì)執(zhí)行[MyClass alloc]語(yǔ)句,這是對(duì)MyClass類調(diào)用類方法,MyClass也是MyClass元類的實(shí)例對(duì)象,
同樣也有objc_object結(jié)構(gòu)體,objc_object結(jié)構(gòu)體中isa指向MyClass元類;MyClass元類也是一個(gè)類,
在其objc_class中的methodLists中并沒(méi)有發(fā)現(xiàn)alloc方法;
2:則從MyClass元類的objc_class中super_class進(jìn)行遞歸查找,最終在NSObject元類中找到alloc方法;
3:[MyClass alloc]返回MyClass的實(shí)例對(duì)象myClass,這樣myClass就有了一個(gè)objc_object結(jié)構(gòu)體,
objc_object是通過(guò)alloc中class_createInstance創(chuàng)建的,isa指針指向MyClass類;
4:對(duì)myClass調(diào)用init,因?yàn)閙yClass的objc_object中isa指向MyClass類,所以會(huì)在MyClass類的
objc_class中methodLists進(jìn)行查找,發(fā)現(xiàn)沒(méi)有,則去MyClass類的objc_class中
super_class進(jìn)行遞歸查找,最終在NSObject類中找到init方法,init只是做一個(gè)初始化的操作,
返回自身;這里要注意是從類中不是元類中去查找,因?yàn)槭菍?duì)實(shí)例對(duì)象調(diào)用方法;
5:這樣實(shí)例對(duì)象分配空間和初始化就完成了,接下來(lái)是對(duì)myClass調(diào)用test方法,
因?yàn)閠est就是MyClass類中定義的,前面說(shuō)了myClass的objc_object中isa指向MyClass類,所以直接
就在MyClass的objc_class中methodLists找到了test方法,直接執(zhí)行test;
6:整個(gè)過(guò)程執(zhí)行完畢。
那么我怎么獲取objc_class中isa和super_class指向誰(shuí)呢?
可以用objc_getClass獲取isa,用class_getSuperclass獲取super_class,class方法則只會(huì)返回類本身。
//ClassTwo : ClassOne,ClassOne : NSObject
//獲取ClassTwo對(duì)應(yīng)的元類的super_class
Class currentClass = objc_getMetaClass("ClassTwo"); //打印這些元類的super_class ClassTwo ClassOne NSObject NSObject nil
//基元類的super_calss指向基類 基類的super_class為nil 形成閉環(huán)
for (int i = 0; i < 5; i++) { NSLog(@"Following the super_class pointer %d times gives %p", i, currentClass);
currentClass = class_getSuperclass(currentClass);
} //打印ClassTwo類的super_class指向 ClassTwo ClassOne NSObject nil
currentClass = [ClassTwo class]; for (int i = 0; i < 4; i++) { NSLog(@"Following the super_class pointer %d times gives %p", i, currentClass);
currentClass = class_getSuperclass(currentClass);
} //打印ClassTwo的isa指向 ClassTwo nil nil nil 任何元類的isa指向基類的元類,就是nil
currentClass = [ClassTwo class]; for (int i = 0; i < 4; i++) { NSLog(@"Following the isa pointer %d times gives %p", i, currentClass);
currentClass = objc_getClass((__bridge void *)currentClass);
}
了解更多
Objective-C Runtime 運(yùn)行時(shí)之一:類與對(duì)象
Objective-C對(duì)象模型及應(yīng)用
iOS中isa的深層理解
Objective-C 中的元類(meta class)是什么?
iOS底層原理總結(jié) - 探尋Class的本質(zhì)
Runtime給類添加屬性、成員變量
添加屬性
可以給任意類添加屬性,用class_addProperty。
這里需要注意了,如果我們?cè)陬惗x中加的屬性,那么編譯器會(huì)默認(rèn)生成一個(gè)成員變量和getter/setter方法,如果我們動(dòng)態(tài)加屬性,則只是表示這是一個(gè)屬性罷了,我們需要再添加對(duì)應(yīng)的成員變量和getter/setter方法才能正常使用。
添加成員變量
只能給動(dòng)態(tài)添加類添加成員變量,用class_addIvar;該類不能是元類。
添加關(guān)聯(lián)對(duì)象
可以給任意類添加關(guān)聯(lián)對(duì)象達(dá)到添加"屬性"作用,用objc_setAssociatedObject。
//設(shè)置objc_setAssociatedObject(self, (const void *)"key", @(1), OBJC_ASSOCIATION_ASSIGN);//獲取id object =objc_getAssociatedObject(self, (const void *)"key");
了解更多
對(duì)象關(guān)聯(lián)的使用objc_setAssociatedObject
Ivar 詳解
KVO原理
要了解KVO,我們得知道KVC和KeyPath。
KeyPath:鍵路徑;運(yùn)行時(shí)系統(tǒng)根據(jù)鍵路徑找到最后的屬性/成員變量/關(guān)聯(lián)對(duì)象進(jìn)行相應(yīng)的操作。
KVC:允許開(kāi)發(fā)者通過(guò)Key名直接訪問(wèn)對(duì)象的屬性/成員變量/關(guān)聯(lián)對(duì)象;并有一組api供開(kāi)發(fā)者使用,像操作字典一樣操作對(duì)象屬性/成員變量/關(guān)聯(lián)對(duì)象。
...
- (void)setValue:(nullable id)value forKey:(NSString *)key
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath
...
為什么說(shuō)是屬性/成員變量/關(guān)聯(lián)對(duì)象呢?
聲明屬性編譯器默認(rèn)會(huì)給我們生成對(duì)應(yīng)的私有成員變量,其實(shí)屬性就是私有成員變量+getter+setter罷了;
這里我們不考慮幺蛾子情況,比如聲明了兩個(gè)屬性year和month,你又寫了這樣的代碼@synthesize year =
month;那么不好意思,這樣的話編譯器不會(huì)生成_month和_year成員變量了,也不會(huì)生成month的getter和setter方法,只會(huì)生成一個(gè)month成員變量和year的getter和setter方法,操作self.year
就相當(dāng)于操作了month成員變量;
成員變量是自己寫在類擴(kuò)展、類定義或類實(shí)現(xiàn)后成員變量聲明區(qū)中的變量;類定義中聲明的默認(rèn)是受保護(hù)
類型,類擴(kuò)展和類實(shí)現(xiàn)聲明的默認(rèn)是私有類型;任何類型的變量都可以被子類繼承;
也可用Runtime修改/獲取值。
關(guān)聯(lián)對(duì)象是如果在分類中聲明了"屬性"且本類中沒(méi)聲明,如果本類中聲明了那么操作的將會(huì)是本類中的屬性,
編譯器不會(huì)生成對(duì)應(yīng)的成員變量,只是生成了getter和setter罷了;KeyPath了分類中的"屬性"其實(shí)是調(diào)用了分類中對(duì)應(yīng)"屬性"重寫的getter和setter罷了,
內(nèi)部實(shí)現(xiàn)一般是設(shè)置/返回關(guān)聯(lián)對(duì)象的值。
這里需要注意了。如果我們聲明一個(gè)屬性為year,那么你下面兩種方式都可以修改到y(tǒng)ear的值,理由上面已經(jīng)說(shuō)過(guò)了。
[xxx setValue:@(10) forKey:@"year"];
[xxx setValue:@(20) forKey:@"_year"];
如果你聲明了屬性year,你又添加了一個(gè)成員變量year,那么將會(huì)有year和_year兩個(gè)成員變量,self.year操作的_year成員變量。你可以加@synthesize year = year告訴編譯器year屬性使用year成員變量而不用再生成_year;那么下面的這句話就會(huì)崩潰。
[xxx setValue:@(20) forKey:@"_year"];
KVO:鍵值對(duì)觀察者,在監(jiān)聽(tīng)屬性值變化時(shí)發(fā)出一個(gè)通知給監(jiān)聽(tīng)者。
...
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options context:(nullable void *)context
...
系統(tǒng)提供的接口,在新/舊值一樣時(shí)也會(huì)發(fā)出通知。
實(shí)現(xiàn)KVO方式很多種,我們看看系統(tǒng)KVO的內(nèi)部大概實(shí)現(xiàn)思路。
假設(shè)有一個(gè)Person類,該類有一個(gè)name屬性。執(zhí)行下面語(yǔ)句的時(shí)候。
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
其實(shí)系統(tǒng)動(dòng)態(tài)創(chuàng)建了一個(gè)子類NSKVONotifying_Person,并把person的isa指針指向了NSKVONotifying_Person;如果我們打印出NSKVONotifying_Person所以方
法,可以得到這么幾個(gè):setName:、class、dealloc和_isKVOA。重點(diǎn)是setName:方法,我們打印
setName:的內(nèi)容為:(Foundation`_NSSetObjectValueAndNotify);這個(gè)是一個(gè)私有方法,不過(guò)我們
不難猜到通知是從這個(gè)方法發(fā)出來(lái)的。那么當(dāng)我們改變person的name屬性時(shí),其實(shí)是走了NSKVONotifying_Person的setName:方法,該方法先調(diào)用Person的setName:方法給name賦值后
發(fā)出一個(gè)通知給監(jiān)聽(tīng)者。
我看了一些網(wǎng)上自己實(shí)現(xiàn)KVO的做法,網(wǎng)上的大部分實(shí)現(xiàn)只能給實(shí)例添加一個(gè)監(jiān)聽(tīng)對(duì)象、不支持實(shí)例變量添加KVO、不支持keyPath;要自己仿寫KVO其實(shí)是非常困難。
了解更多
iOS開(kāi)發(fā)技巧系列---詳解KVC(我告訴你KVC的一切)
iOS KVO的底層實(shí)現(xiàn)原理
KVO 的內(nèi)部實(shí)現(xiàn)
Property修飾符
這里我們講ARC環(huán)境下;修飾符主要分為下面的幾類。
原子性
nonatomic:原子性訪問(wèn),對(duì)屬性賦值的時(shí)候不加鎖,多線程并發(fā)訪問(wèn)會(huì)提高性能。
atomic:屬性默認(rèn)為atomic,提供多線程安全,在多線程環(huán)境下,原子操作是必要的,否則有可能引起錯(cuò)誤的結(jié)果。
在iOS開(kāi)發(fā)中,幾乎所有屬性都聲明為 nonatomic。
atomic的作用只是給getter和setter加了個(gè)鎖,atomic只能保證代碼進(jìn)入getter或者setter函數(shù)內(nèi)部時(shí)是安全的,一旦出了getter和setter,多線程安全只能靠程序員自己保障了。
讀/寫
readwrite:同時(shí)產(chǎn)生setter/getter方法。
readonly:只產(chǎn)生簡(jiǎn)單的getter,沒(méi)有setter。
有的朋友會(huì)問(wèn)怎么沒(méi)有writeonly?因?yàn)閷憴?quán)限包含了讀權(quán)限。
引用計(jì)數(shù)
copy:目標(biāo)對(duì)象引用計(jì)數(shù)不變,拷貝一份引用計(jì)數(shù)為1的對(duì)象,該屬性指向拷貝對(duì)象。
weak:目標(biāo)對(duì)象引用計(jì)數(shù)不變,該屬性指向目標(biāo)對(duì)象地址,當(dāng)目標(biāo)對(duì)象銷毀時(shí),該屬性置為nil。
strong:目標(biāo)對(duì)象引用計(jì)數(shù)+1,該屬性指向目標(biāo)對(duì)象地址。
對(duì)于NSString對(duì)象需要單獨(dú)考慮。
NSString *a = @"abc";//@"abc"被放到常量區(qū),對(duì)a對(duì)象copy和strong引用計(jì)數(shù)不會(huì)變化,a是NSCFConstantString類型。NSString *a = [NSString stringWithFormat:@"abc"];//在堆上分配內(nèi)存得到的a是NSCFString對(duì)象,對(duì)a對(duì)象copy和strong都只是引用計(jì)數(shù)+1。
對(duì)于可變對(duì)象賦值給copy屬性時(shí)會(huì)變成不可變對(duì)象。
能否為空
nonnull:對(duì)象不應(yīng)該為nil;當(dāng)賦值為nil時(shí)編譯器會(huì)給出警告。
NS_ASSUME_NONNULL_BEGIN//之間的屬性都被認(rèn)為是nonnull的NS_ASSUME_NONNULL_END
nullable:對(duì)象可以為nil;屬性默認(rèn)是nullable的。
了解更多
iOS中property的關(guān)鍵字(史上最詳解)
iOS屬性常用關(guān)鍵字解析
NSString特性分析學(xué)習(xí)
iOS多線程到底不安全在哪里?
程序內(nèi)存分區(qū)
以下是比較常用的五分區(qū)方式,當(dāng)然也不排除網(wǎng)上有其他的分區(qū)方式。
棧
棧的大小在編譯時(shí)就已經(jīng)確定了,一般是2M;棧是一塊從高到低地址的連續(xù)區(qū)域,存放臨時(shí)變量和執(zhí)行函數(shù)時(shí)的內(nèi)存等。棧內(nèi)存分配分為動(dòng)態(tài)和靜態(tài),靜態(tài)如自動(dòng)變量(局部變量)等,動(dòng)態(tài)如alloc等。
堆
堆是從低到高地址的不連續(xù)區(qū)域,類似鏈表;用來(lái)存放malloc或new申請(qǐng)的內(nèi)存。
全局/靜態(tài)
存放靜態(tài)/全局變量;全局區(qū)細(xì)分為未初始化/初始化區(qū)。
常量
存放常量;程序中使用的常量會(huì)到常量區(qū)獲取。
可以看看這個(gè)例子來(lái)理解一下。
...int a;//a在全局未初始化區(qū)int a = 10;//a在全局初始化區(qū) 10在常量區(qū)static int a = 10;//a在靜態(tài)區(qū) 10在常量區(qū)//程序入口int main(...) { int a = 10;//a在棧區(qū) 10在常量區(qū)
static int a = 10;//a在靜態(tài)區(qū) 10在常量區(qū)
char *a = (char *)malloc(10); //a在棧區(qū) malloc后的內(nèi)存在堆區(qū)
...
}
代碼
存放二進(jìn)制代碼,運(yùn)行程序就是執(zhí)行代碼,代碼要執(zhí)行就要加載進(jìn)內(nèi)存(RAM運(yùn)行內(nèi)存)。
了解更多
iOS程序中的內(nèi)存分配分區(qū)
iOS基礎(chǔ)全局變量·靜態(tài)變量·局部變量·自動(dòng)變量
extern的作用
告訴編譯器,這個(gè)全局變量在本文件找不到就去其他文件去找。如有必要需要使用#import "x.h"這樣編譯器才知道到哪里去找。
//.hint age = 10;//error 不能.h此處聲明全局非靜態(tài)變量,.m中可以extern int age = 10;//error 和int age = 10;等價(jià)extern static int age = 10;//全局靜態(tài)變量聲明不和extern一起用@interface Class : NSObject...@end//.mextern static int age = 10;//全局靜態(tài)變量聲明不和extern一起用@implementation Class { int age;//成員變量不能用作extern;}
- (void)test { extern int age = 10;//error 因?yàn)檫@并不是全局變量
static int age = 10;//error 因?yàn)檫@并不是全局變量
extern int age;//error 因?yàn)檫@并不是全局變量}
...@end
使用extern前要保證對(duì)應(yīng)變量被編譯過(guò)
//.hextern int age;//error extern在聲明前extern static int age;//error extern沒(méi)有static@interface Class : NSObject...@end//.mstatic int age = 10;@implementation Class ...@end
//.hstatic int age = 10;extern int age;//正確 @interface Class : NSObject...@end//.m@implementation Class ...
- (void)test { extern int age;//正確 聲明和extern可以在不同文件中}@end
全局非靜態(tài)變量
//.hextern int age;//正確@interface Class : NSObject...@end//.mint age = 10;@implementation Class ...@end
了解更多
iOS開(kāi)發(fā)中的關(guān)鍵字const/static/extern
指針函數(shù)/函數(shù)指針/Block
指針函數(shù)
C語(yǔ)言的概念;本質(zhì)是函數(shù),返回指針。
char *fun() { char *p = ""; return p;
}
函數(shù)指針
C語(yǔ)言的概念;本質(zhì)是指針,指向函數(shù)。
int fun(int a,int b) { return a + b;
}int (*func)(int,int);
func = fun;
func(1,2);//3
Block
OC語(yǔ)言的概念;表示一個(gè)代碼塊,OC中視為對(duì)象;挺像C函數(shù)指針的。
//typedeftypedef int (^SumBlock)(int a,int b);
SumBlock sumBlock = ^(int a,int b) { return a + b;
};
sumBlock(1,2);//3//普通
int (^sumBlock)(int a,int b) = ^(int a,int b) { return a + b;
};
sumBlock(1,2);//3
了解更多
指針函數(shù)與函數(shù)指針(C語(yǔ)言)
iOS開(kāi)發(fā)-由淺至深學(xué)習(xí)block
__weak、__strong、__block理解
我們基本都是ARC環(huán)境,所以回答以ARC角度。
__block
講這個(gè)之前,我們需要搞清楚一個(gè)概念,這個(gè)block存在內(nèi)存什么區(qū)域的?
如果這個(gè)block內(nèi)部沒(méi)有訪問(wèn)棧、堆的變量,那么這個(gè)block存在代碼區(qū);反之存在堆區(qū)。block內(nèi)部修改棧區(qū)的變量,該變量需要加__block修飾,這樣會(huì)將變量從棧上復(fù)制到堆上。棧上那個(gè)變量會(huì)指向復(fù)制到堆上的變量。block內(nèi)部修改堆區(qū)的變量不用加__block。
因?yàn)槎褏^(qū)不斷有變量創(chuàng)建和銷毀,block作為屬性時(shí)我們需要加copy或者strong修飾。
__weak
__weak我們就在block和聲明屬性中看到過(guò)。
如block是被self強(qiáng)引用的。
@property (nonatomic, copy) void (^Block)(void);
那么在Block內(nèi)部使用self時(shí),Block內(nèi)部又會(huì)對(duì)self進(jìn)行一次強(qiáng)引用;這就形成了循環(huán)引用,所以需要對(duì)self進(jìn)行__weak。
__weak typeof(self) weakSelf = self;
弱引用不會(huì)影響對(duì)象的釋放,當(dāng)對(duì)象被釋放時(shí),所有指向它的弱引用都會(huì)自定被置為nil。
當(dāng)然了,self沒(méi)有強(qiáng)引用block時(shí)是不需要__weak的。
- (void)func() { void (^Block)(void) = ^(void) {
[self test];
};
}
__strong
對(duì)self進(jìn)行了__weak,那么在block執(zhí)行時(shí)weakSelf隨時(shí)可能被釋放,所以內(nèi)部需要對(duì)weakSelf進(jìn)行__strong讓self不被釋放。
__strong typeof(self) strongSelf = weakSelf;
在block執(zhí)行完成后,strongSelf會(huì)被釋放,不會(huì)造成循環(huán)引用。
了解更多
iOS中block塊的存儲(chǔ)位置&內(nèi)存管理
__block & __weak & __strong
事件傳遞鏈/事件響應(yīng)鏈
事件傳遞鏈
當(dāng)點(diǎn)擊一個(gè)按鈕的時(shí)候,事件如果傳遞到按鈕這個(gè)第一響應(yīng)者上,這就是事件傳遞鏈要做的事情。系統(tǒng)根據(jù)下面兩個(gè)方法來(lái)傳遞事件。
//該點(diǎn)是否在本視圖點(diǎn)擊范圍內(nèi) point已經(jīng)被轉(zhuǎn)換了成本視圖對(duì)應(yīng)frame- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { //內(nèi)部實(shí)現(xiàn)大概是這樣
return CGRectContainsPoint(self.bounds, point);
}//本視圖/子視圖是否能夠傳遞本事件 point已經(jīng)被轉(zhuǎn)換了成本視圖對(duì)應(yīng)frame- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { //內(nèi)部實(shí)現(xiàn)大概是這樣
//用戶交互為NO,不處理
if(self.userInteractionEnabled == NO) { return nil;
} if([self pointInside:point withEvent:event]) { NSArray * superViews = self.subviews; //倒序從最上面的一個(gè)視圖開(kāi)始查找
for (NSUInteger i = superViews.count; i > 0; i--) { UIView * subview = superViews[i - 1]; //轉(zhuǎn)換坐標(biāo)系 使坐標(biāo)基于子視圖
CGPoint newPoint = [self convertPoint:point toView:subview]; //得到子視圖 hitTest 方法返回的值
UIView * view = [subview hitTest:newPoint withEvent:event]; //如果子視圖返回一個(gè)view 就直接返回 不在繼續(xù)遍歷
if (view) { return view;
}
} //所有子視圖都沒(méi)有返回 則返回自身
return self;
} return nil;
}
當(dāng)點(diǎn)擊按鈕的時(shí)候,其實(shí)事件是這樣傳遞的:AppDelegate->UIApplication->UIWindow->xxx->UIViewController->UIView->UIButton。
事件響應(yīng)鏈
當(dāng)找到事件第一響應(yīng)者之后,該事件如何響應(yīng),就是事件響應(yīng)鏈要做的事情。
接著上面的例子,UIButton就是系統(tǒng)找出來(lái)的第一響應(yīng)者,那么會(huì)執(zhí)行如下方法:
//觸摸事件開(kāi)始- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {}//觸摸事件移動(dòng)- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {}//觸摸事件結(jié)束- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {}//觸摸事件取消- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {}
如果你自己不處理,你可以self.nextResponder讓下一個(gè)響應(yīng)者處理。
//觸摸事件開(kāi)始- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { //讓下一個(gè)響應(yīng)者處理
[self.nextResponder touchesBegan:touches withEvent:event];
}
...
響應(yīng)者鏈也就是傳遞鏈的倒序。
這里需要注意的就是,如果給UIButton添加了target和UITapGestureRecognizer那么點(diǎn)擊按鈕只會(huì)執(zhí)行UITapGestureRecognizer,也就是說(shuō)如果手勢(shì)和target同時(shí)滿足條件則只會(huì)執(zhí)行手勢(shì)。target也是touchesxxx中判定的,你可以重寫touchesxxx內(nèi)部實(shí)現(xiàn)為空,你會(huì)發(fā)現(xiàn)并不影響手勢(shì)但會(huì)影響target。
了解更多
iOS事件攔截和事件轉(zhuǎn)發(fā)
UIView之userInteractionEnabled屬性介紹
iOS觸摸事件那點(diǎn)兒事
簡(jiǎn)述RunLoop
RunLoop是iOS中的Event Loop實(shí)現(xiàn),簡(jiǎn)單來(lái)說(shuō)是一個(gè)do while循環(huán),需要GCD等協(xié)作執(zhí)行;循環(huán)體內(nèi)沒(méi)事件需要處理就休眠,被mach_port喚醒之后處理相應(yīng)事件后判斷條件繼續(xù)進(jìn)入循環(huán)。一個(gè)線程只能有一個(gè)根RunLoop,RunLoop保存在TSD中;一次RunLoop執(zhí)行只能指定一個(gè)RunLoopMode,mode有timer、source、common和observer等;幾乎所有的操作都是通過(guò)Call out方法進(jìn)行回調(diào)的,比如點(diǎn)擊是通過(guò)source1到source0再到action回調(diào);要切換mode必須退出當(dāng)前RunLoop并指定新mode重新執(zhí)行。
了解更多
iOS刨根問(wèn)底-深入理解RunLoop
Run Loop 記錄與源碼注釋
深入理解RunLoop
RunLoop 源碼閱讀
NSTimer原理
有容錯(cuò)值用gcd timer實(shí)現(xiàn),反之用mk_timer實(shí)現(xiàn),mk_timer更準(zhǔn)確;觸發(fā)點(diǎn)并不是一開(kāi)始就計(jì)算出的,而是每次觸發(fā)后動(dòng)態(tài)計(jì)算;當(dāng)RunLoop執(zhí)行一個(gè)阻塞操作時(shí),觸發(fā)點(diǎn)可能延遲,可能會(huì)跳過(guò)中間的觸發(fā)點(diǎn)。
了解更多
從RunLoop源碼探索NSTimer的實(shí)現(xiàn)原理
簡(jiǎn)述GCD
iOS的一個(gè)多核調(diào)度器,用于優(yōu)化應(yīng)用程序以支持多核處理器;內(nèi)部默認(rèn)創(chuàng)建一個(gè)串行主隊(duì)列和12種不同優(yōu)先級(jí)的并發(fā)隊(duì)列,可以自己創(chuàng)建默認(rèn)優(yōu)先級(jí)為Default的串行/并發(fā)隊(duì)列;得到隊(duì)列后可以向隊(duì)列同步/異步方式添加任務(wù),異步GCD會(huì)按需創(chuàng)建線程;向主隊(duì)列添加的任務(wù)將由主線程RunLoop處理;GCD還可以實(shí)現(xiàn)定時(shí)器、延遲、柵欄、信號(hào)量和組等。
了解更多
iOS多線程:『GCD』詳盡總結(jié)
iOS GCD之dispatch_semaphore(信號(hào)量 )
GCD源碼分析
自動(dòng)釋放池
釋放池是由n個(gè)page組成的雙向鏈表,線程和釋放池一一對(duì)應(yīng);釋放池push時(shí)會(huì)放入哨兵對(duì)象,根據(jù)next指針?lè)胖锰砑舆M(jìn)來(lái)的自動(dòng)釋放對(duì)象;釋放池pop時(shí)會(huì)將hotpage中next指針依次向前移動(dòng),對(duì)所指對(duì)象調(diào)用release直到遇到結(jié)束標(biāo)志,清理過(guò)程可跨越page;從main方法中知道iOS項(xiàng)目默認(rèn)是包裹在大的釋放池中;RunLoop開(kāi)始循環(huán)、休眠和退出時(shí)會(huì)對(duì)釋放池進(jìn)行poolpush/poolpop操作。
了解更多
理解 iOS 的內(nèi)存管理
iOS 自動(dòng)釋放池原理探究
黑幕背后的Autorelease
iOS中autorelease的那些事兒
iOS中的定時(shí)器
NSTimer、GCD定時(shí)器和CADisplayLink。
NSTimer根據(jù)容錯(cuò)值使用GCD定時(shí)器或mk_timer。
NSTimer和CADisplayLink依賴于RunLoop,GCD定時(shí)器不依賴。
了解更多
iOS定時(shí)器 NSTimer、CADisplayLink、GCD
UIView/CALayer關(guān)系
view是layer的代理對(duì)象;view負(fù)責(zé)管理layer,layer負(fù)責(zé)渲染;view初始化的時(shí)候默認(rèn)會(huì)創(chuàng)建一個(gè)layer;設(shè)置view的frame和bounds等內(nèi)部其實(shí)是修改layer對(duì)應(yīng)屬性。
了解更多
詳解 CALayer 和 UIView 的區(qū)別和聯(lián)系
簡(jiǎn)述你了解的鎖
互斥鎖:NSLock、pthread_mutex、@synchronized。
加鎖后,其他加鎖操作阻塞直到解鎖。
遞歸鎖:NSRecursiveLock。
一個(gè)線程可以多次加鎖,相應(yīng)的要對(duì)應(yīng)多次解鎖其他線程才可以加鎖。
條件鎖:NSCondition、NSConditionLock。
鎖滿足指定條件時(shí)才繼續(xù)執(zhí)行,否則阻塞。
信號(hào)量:dispatch_semaphore。
wait操作阻塞直到signal被調(diào)用。
讀寫鎖:pthread_rwlock。
讀模式占有鎖時(shí)其他線程只能讀;寫模式占有鎖時(shí)其他線程不能進(jìn)行任何操作。
了解更多
ISO七層、TCP/IP四層協(xié)議
ISO七層協(xié)議
應(yīng)用、表示、會(huì)話、傳輸、網(wǎng)絡(luò)、數(shù)據(jù)鏈路、物理。
TCP/IP四層協(xié)議
應(yīng)用、傳輸、網(wǎng)絡(luò)、數(shù)據(jù)鏈路。
傳輸層單位:段;
網(wǎng)絡(luò)層單位:報(bào);
鏈路層單位:幀。
了解更多
什么是ARC
ARC是引用計(jì)數(shù),是一個(gè)簡(jiǎn)單而有效的管理對(duì)象生命周期的方式;編譯器在代碼合適的地方自動(dòng)給我們加了一些關(guān)鍵字,比如:retain、release和autorelease等;這樣我們就不用手動(dòng)管理對(duì)象生命周期。
了解更多
iOS類和結(jié)構(gòu)體有什么區(qū)別
區(qū)別還是有很多的,答到核心的就可以了。
1:類指針賦值時(shí)只是復(fù)制了地址,結(jié)構(gòu)體是復(fù)制內(nèi)容;
2:類不能有同名同參數(shù)個(gè)數(shù)的方法,結(jié)構(gòu)體可以;
3:結(jié)構(gòu)體方法實(shí)現(xiàn)編譯時(shí)就確定了,類方法實(shí)現(xiàn)可動(dòng)態(tài)改變;
4:內(nèi)存分配不一樣,結(jié)構(gòu)體在棧,類在堆;
5:結(jié)構(gòu)體可以多重繼承,類只能單繼承。
網(wǎng)上很多文章說(shuō)結(jié)構(gòu)體不能有方法,結(jié)構(gòu)體不能繼承;
請(qǐng)看清楚題,說(shuō)的是iOS中的結(jié)構(gòu)體,不是C中的結(jié)構(gòu)體。
了解更多
iOS通知和協(xié)議的區(qū)別
一個(gè)協(xié)議一時(shí)間只能有一個(gè)代理對(duì)象,而一個(gè)通知一時(shí)間可以有多個(gè)監(jiān)聽(tīng)者。
通知的發(fā)送和監(jiān)聽(tīng)依靠通知中心,協(xié)議則可以自己創(chuàng)建,通過(guò)setDelegate指定代理對(duì)象。
了解更多
IOS中的協(xié)議Protocol與代理Delegate以及通知
iOS內(nèi)存使用注意事項(xiàng)和優(yōu)化
使用注意事項(xiàng)
訪問(wèn)野指針:數(shù)據(jù)越界、對(duì)象已經(jīng)釋放但對(duì)其發(fā)送消息等;
內(nèi)存泄漏:循環(huán)引用、imageNamed讀取圖片等;
觸碰內(nèi)存峰值:for循環(huán)聲明變量等;
申請(qǐng)了不使用的內(nèi)存:聲明變量但未使用、只在某個(gè)邏輯分支用到某些變量但一開(kāi)始就初始化等。
內(nèi)存優(yōu)化
訪問(wèn)野指針:訪問(wèn)前加判斷;
這部分問(wèn)題大多是多線程造成的,比如兩個(gè)線程同時(shí)執(zhí)行一個(gè)方法,方法內(nèi)部對(duì)數(shù)組有更新操作。
內(nèi)存泄漏:Instrument Leaks/Allocations檢測(cè)、使用imageWithContentsOfFile讀取圖片等;
imageNamed會(huì)緩存加載的圖片;imageWithContentsOfFile只是簡(jiǎn)單的加載圖片。
觸碰內(nèi)存峰值:手動(dòng)添加釋放池;
for循環(huán)內(nèi)大量創(chuàng)建局部變量,這些局部變量會(huì)等到RunLoop的下一個(gè)循環(huán)才釋放,
而手動(dòng)加入釋放池則會(huì)提前釋放。
申請(qǐng)了不使用的內(nèi)存:懶加載。
了解更多
ViewController完整生命周期
init
loadView
viewDidLoad
viewWillAppear
viewDidAppear
viewWillDisappear
viewDisDisappear
viewWillUnload(Deprecated)
viewDidUnload(Deprecated)
delloc
這里要注意loadView方法,平時(shí)我們都沒(méi)有去管這個(gè)事情;
這個(gè)方法執(zhí)行后self.view才有值,也就是說(shuō)這個(gè)方法完成了view的加載,內(nèi)部會(huì)根據(jù)控制器名字、是否自己實(shí)現(xiàn)、xib等條件來(lái)加載view。
如果自己實(shí)現(xiàn)loadView方法,并且方法體為空,則self.view為nil,
并且viewDidLoad方法會(huì)調(diào)用兩次;
這說(shuō)明viewDidLoad是被loadView調(diào)起的,在viewDidLoad中如果self.view為nil會(huì)再調(diào)用一次loadView。
延伸了解。
viewWillUnload和viewDidUnload被棄用了,內(nèi)部是在清理self.view。
storyboard加載的是控制器+View,而xib加載的是View,也就是說(shuō)storyboard加載時(shí)會(huì)調(diào)用
ViewController的awakeFromNib方法。
awakeFromNib:表示ViewController/View從xib加載。
了解更多
iOS開(kāi)發(fā)筆記(九):UIViewController的生命周期
frame和bounds區(qū)別
frame表示在superview坐標(biāo)系中的位置和大小,bounds表示自身坐標(biāo)系,默認(rèn)左上角為0,0;
bounds給subview參考,其結(jié)合自身frame確定顯示位置;
改變bounds不會(huì)改變自己在superview中的位置,但會(huì)改變subview的位置。
改變bounds時(shí)如果寬高和frame寬高不一致則會(huì)以center為中心縮放,此時(shí)將改變frame并重新顯示。
了解更多
@synthesize和@dynamic的作用
@synthesize
如果屬性沒(méi)有自動(dòng)生成getter/setter方法,則告訴編譯器去生成。
@dynamic
告訴編譯器不要生成此屬性的getter/setter方法,開(kāi)發(fā)者自己去實(shí)現(xiàn)。
了解更多
iOS @property、@synthesize和@dynamic
SDWebImage作用
先了解一下NSURLCache。
NSURLCache默認(rèn)會(huì)對(duì)部分GET請(qǐng)求進(jìn)行緩存;
請(qǐng)求一張圖片,第一次請(qǐng)求成功后NSURLCache會(huì)緩存圖片內(nèi)容,第二次請(qǐng)求的時(shí)候直接從緩存中取就可以了,
并沒(méi)有真正發(fā)起請(qǐng)求;NSURLCache系統(tǒng)也是默認(rèn)啟動(dòng)的。
看了上面的介紹你發(fā)現(xiàn)這不就是你最終要實(shí)現(xiàn)的功能嗎?那SDWebImage到底做了什么呢?
1:正在下載該url的圖片,直接返回;2:處理多線程問(wèn)題,比如cell復(fù)用造成的顯示錯(cuò)亂問(wèn)題,也就是下載之前先取消;3:增加一層內(nèi)存緩存,直接從url得到image,NSURLCache存的是data;4:相同url請(qǐng)求時(shí)只加了一個(gè)finish回調(diào);5:請(qǐng)求做了排隊(duì)處理,控制資源。
所以可以把SDWebImage看成是NSURLCache的封裝,等同于NSOperationQueue和GCD的關(guān)系。
了解更多
XML解析方式
SAX:基于事件驅(qū)動(dòng),逐行解析,采用協(xié)議回調(diào);文件比較大時(shí)建議用此方式。
DOM:文檔對(duì)象模型,解析時(shí)將整個(gè)文檔讀入并結(jié)構(gòu)化成樹(shù),通過(guò)樹(shù)狀結(jié)構(gòu)讀取相關(guān)數(shù)據(jù);文件比較小時(shí)建議用此方式。
了解更多
AFNetWorking作用
我看的是AFNetWorking 3.0版本,是基于NSURLSession封裝的,NSURLSession使用起來(lái)已經(jīng)足夠方便了,所以AFNetWorking做的內(nèi)容相對(duì)來(lái)說(shuō)少了很多。
1:設(shè)置請(qǐng)求/響應(yīng)序列化對(duì)象,這樣可以幫你檢查請(qǐng)求/響應(yīng)參數(shù)是否正確;
2:https驗(yàn)證功能,可以用于自簽名證書等特殊情況,如果不啟用則讓系統(tǒng)幫你驗(yàn)證,
那么就只能是蘋果官方認(rèn)可的CA證書才能通過(guò);
3:對(duì)于不同的請(qǐng)求方式和參數(shù),幫你設(shè)置請(qǐng)求,比如頭部的Content-type。
了解更多
Http協(xié)議特點(diǎn),GET/POST請(qǐng)求區(qū)別
Http協(xié)議特點(diǎn),基于Http2.0
快速:協(xié)議簡(jiǎn)單,通訊速度快;
靈活:通過(guò)Content-Type可以傳遞任何類型的數(shù)據(jù);
長(zhǎng)連接:一次連接處理多個(gè)請(qǐng)求,并支持管線(同時(shí)發(fā)出多個(gè)請(qǐng)求,不用等到前面請(qǐng)求響應(yīng))、多路復(fù)用(一個(gè)請(qǐng)求多次響應(yīng));
無(wú)狀態(tài):協(xié)議對(duì)于事務(wù)處理沒(méi)有記憶能力,如果本次請(qǐng)求需要上次的數(shù)據(jù)則需要重傳。
GET/POST請(qǐng)求區(qū)別
GET在URL后以?形式拼接參數(shù),POST將參數(shù)放在body中;
GET也可以在body里面放數(shù)據(jù),POST也可以在URL放數(shù)據(jù),Http只是規(guī)定,你也可以不遵守啊。
至于服務(wù)器獲不獲取就看具體實(shí)現(xiàn)了。
POST比GET安全,因?yàn)镚ET參數(shù)在URL中,用戶一眼就能看到;
POST當(dāng)然也可以用工具看到參數(shù)。
語(yǔ)意理解,GET用來(lái)獲取數(shù)據(jù),POST用來(lái)上傳數(shù)據(jù);
客戶端和服務(wù)器對(duì)URL數(shù)據(jù)一般有1kb的限制。
Http協(xié)議對(duì)URL并沒(méi)有限制。
了解更多
iOS-網(wǎng)絡(luò)編程(一)HTTP協(xié)議
http2.0的時(shí)代真的來(lái)了...
Socket連接和Http連接區(qū)別
Http是基于Tcp的,而Socket是一套編程接口讓我們更方便的使用Tcp/Ip協(xié)議;Http是應(yīng)用層協(xié)議,在Tcp/Udp上一層。
1:Http是基于"請(qǐng)求-響應(yīng)"的,服務(wù)器不能主動(dòng)向客戶端推送數(shù)據(jù),只能借助客戶端請(qǐng)求到后向客戶端推送數(shù)據(jù),而Sokcet雙方隨時(shí)可以互發(fā)數(shù)據(jù);
2:Http不是持久連接的,Socket用Tcp是持久連接;
3:Http基于Tcp,Socket可以基于Tcp/Udp;
4:Http連接是通過(guò)Socket實(shí)現(xiàn)的;
5:Http連接后發(fā)送的數(shù)據(jù)必須滿足Http協(xié)議規(guī)定的格式:請(qǐng)求頭、請(qǐng)求頭和請(qǐng)求體,而Socket連接后發(fā)送的數(shù)據(jù)沒(méi)有格式要求。
了解更多
Tcp三次握手、四次揮手
Tcp是傳輸層可靠傳輸協(xié)議,發(fā)送數(shù)據(jù)前要進(jìn)行握手,數(shù)據(jù)發(fā)送完時(shí)可以揮手?jǐn)嚅_(kāi)連接釋放資源;揮手比握手多一次是因?yàn)閿嚅_(kāi)需要雙方單獨(dú)斷開(kāi),而握手被連接端是被動(dòng)打開(kāi)的。
首先,我們必須要明白一些重要的Tcp頭部標(biāo)志。
序號(hào):每一個(gè)包都有一個(gè)序號(hào),此序號(hào)mod2^32;
確認(rèn)號(hào):用來(lái)確認(rèn)收到對(duì)方的包,此序號(hào)mod2^32;
SYN:為1時(shí)表示希望與對(duì)方建立連接;
FIN:為1時(shí)表示我已經(jīng)沒(méi)有數(shù)據(jù)發(fā)送了,希望斷開(kāi)連接;
ACK:為1時(shí)確認(rèn)號(hào)有效,Tcp規(guī)定除了第一次建立連接的包ACK都要置為1。
這是我抓的訪問(wèn)百度握手/揮手過(guò)程,Http協(xié)議也是基于Tcp的。
10.10.9.141:客戶端ip;180.97.33.107:百度ip。
第一次握手 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 64)
10.10.9.141.50806 > 180.97.33.107.http: Flags [S], cksum 0x95b1 (correct), seq 589117916, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 815096723 ecr 0,sackOK,eol], length 0
第一次握手 SYN=1 seq=589117916 第二次握手 IP (tos 0x0, ttl 53, id 0, offset 0, flags [DF], proto TCP (6), length 64)
180.97.33.107.http > 10.10.9.141.50806: Flags [S.], cksum 0x2cb0 (correct), seq 1775662715, ack 589117917, win 8192, options [mss 1408,nop,wscale 5,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,sackOK,eol], length 0
第二次握手 SYN=1 ACK=1 seq=1775662715 ack=589117917第三次握手 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
10.10.9.141.50806 > 180.97.33.107.http: Flags [.], cksum 0xa25d (correct), seq 589117917, ack 1775662716, win 8192, length 0
第三次握手 ACK=1 seq=589117917 ack=1775662716數(shù)據(jù)傳輸...
數(shù)據(jù)傳輸...
第一次揮手 IP (tos 0x0, ttl 50, id 43779, offset 0, flags [DF], proto TCP (6), length 40)
180.97.33.107.http > 10.10.9.141.50806: Flags [F.], cksum 0xb3c8 (correct), seq 1775665497, ack 589118060, win 808, length 0
第一次揮手 FIN=1 ACK=1 seq=1775665497 ack=589118060第二次揮手 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
10.10.9.141.50806 > 180.97.33.107.http: Flags [.], cksum 0x973b (correct), seq 589118060, ack 1775665498, win 8117, length 0
第二次揮手 ACK=1 seq=589118060 ack=1775665498第三次揮手 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
10.10.9.141.50806 > 180.97.33.107.http: Flags [F.], cksum 0x96ef (correct), seq 589118060, ack 1775665498, win 8192, length 0
第三次揮手 ACK=1 FIN=1 seq=589118060 ack=1775665498第四次揮手 IP (tos 0x0, ttl 50, id 0, offset 0, flags [DF], proto TCP (6), length 40)
180.97.33.107.http > 10.10.9.141.50806: Flags [.], cksum 0xb3c7 (correct), seq 1775665498, ack 589118061, win 808, length 0
第四次揮手 ACK=1 seq=1775665498 ack=589118061
了解更多
通俗大白話來(lái)理解TCP協(xié)議的三次握手和四次分手
tcpdump查看三次握手
performSelector傳三個(gè)參數(shù)(未解答)
了解更多
main方法前過(guò)程
1:系統(tǒng)內(nèi)核做好準(zhǔn)備工作,比如把應(yīng)用數(shù)據(jù)從ROM移到RAM;
2:libdyld接管后續(xù)工作,加載動(dòng)態(tài)庫(kù)到內(nèi)存等;
3:ImageLoader把動(dòng)態(tài)庫(kù)和可執(zhí)行文件加載到內(nèi)存;
4.1:Runtime解析文件符號(hào)表,注冊(cè)類、調(diào)用load方法;
4.2:libdispath等其他庫(kù)初始化;
5:libdyld調(diào)用main方法。
了解更多
iOS 程序 main 函數(shù)之前發(fā)生了什么
線程安全方法
線程安全:多線程環(huán)境下保證數(shù)據(jù)的完整性。
隊(duì)列
把操作放入隊(duì)列線性執(zhí)行,可用GCD和NSOperationQueue。
鎖/信號(hào)量
用鎖/信號(hào)量形成操作互斥。
讓操作原子化
讓操作原子執(zhí)行,系統(tǒng)提供了一些原子執(zhí)行的方法。
了解更多
NSOperationQueue和GCD區(qū)別聯(lián)系
區(qū)別
NSOperationQueue沒(méi)有串行/并發(fā)隊(duì)列,但可以設(shè)置最大并發(fā)數(shù);
NSOperationQueue支持方法和block,GCD只支持block;
NSOperationQueue可以暫停/取消操作;
NSOperationQueue支持更多的功能,比如KVO和自定義操作;
NSOperationQueue可以設(shè)置操作的優(yōu)先級(jí),GCD只能設(shè)置隊(duì)列的優(yōu)先級(jí)。
聯(lián)系
提供的功能是相似的;
NSOperationQueue是GCD的封裝。
了解更多
iOS常用設(shè)計(jì)模式
其實(shí)設(shè)計(jì)模式有很多,你只要答上6個(gè)就可以了。
裝飾模式:分類;
代理模式:協(xié)議;
工廠模式:UIButton創(chuàng)建;
原型模式:[object copy];
觀察者模式:KVO;
迭代器模式:數(shù)組的遍歷;
單例模式:Appdelegate;
命令模式:給對(duì)象發(fā)消息;
職責(zé)鏈模式:事件傳遞鏈;
中介者模式:模塊解耦;
解釋器模式:Siri語(yǔ)意識(shí)別;
了解更多
IOS 設(shè)計(jì)模式探索:常用的 23 種設(shè)計(jì)模式
簡(jiǎn)述Block
Block本質(zhì)就是函數(shù),根據(jù)有無(wú)返回值/參數(shù)有4種Block;
在ARC下根據(jù)是否訪問(wèn)棧/堆變量可分為全局/堆Block;
Block內(nèi)修改棧變量時(shí)需要__block修飾,__block的作用其實(shí)就是在堆上創(chuàng)建一個(gè)指向棧變量的指針達(dá)到修改棧變量值的目的。
了解更多
消息動(dòng)態(tài)處理/轉(zhuǎn)發(fā)流程
動(dòng)態(tài)處理
當(dāng)向?qū)ο蟀l(fā)送了一個(gè)不存在的消息時(shí),會(huì)先走resolvexxxMethod動(dòng)態(tài)處理流程,你可以在這之中用Runtime動(dòng)態(tài)添加該方法;你也可以不處理,則進(jìn)入轉(zhuǎn)發(fā)流程。
轉(zhuǎn)發(fā)
先走forwardingTargetForSelector,你可以在這里返回一個(gè)可以處理aSelector的對(duì)象,否則走forwardInvocation操作anInvocation;forwardInvocation需要實(shí)現(xiàn)methodSignatureForSelector得到一個(gè)方法簽名。
了解更多
weak變量怎么置為nil
系統(tǒng)維護(hù)了一個(gè)weak變量組成的hash表,key為weak指向的變量地址,value為weak變量的地址;當(dāng)對(duì)象引用計(jì)數(shù)為0時(shí),遍歷hash表,設(shè)置對(duì)應(yīng)的weak變量為nil。
了解更多
iOS開(kāi)發(fā) Runtime是如何實(shí)現(xiàn)weak屬性的?
對(duì)nil發(fā)消息會(huì)發(fā)生什么
我們可以從Runtime的源碼中看到,發(fā)消息最終會(huì)走objc_msgSend()并把nil最為第一個(gè)參數(shù),其內(nèi)部用匯編實(shí)現(xiàn),里面會(huì)判斷第一個(gè)參數(shù)是否為nil,如果為nil則返回0,所以iOS允許對(duì)nil發(fā)送消息;這個(gè)0針對(duì)不同的selector返回值有不同的表示,比如:0、nil和結(jié)構(gòu)體等。
了解更多
Objective-C 消息發(fā)送與轉(zhuǎn)發(fā)機(jī)制原理
安全區(qū)域的理解
SafeArea是View的屬性,是iOS11出來(lái)用來(lái)代替bottomLayoutGuide/topLayoutGuide的,bottomLayoutGuide/topLayoutGuide是ViewController的屬性;從這里可以看出,SafeArea更靈活,可以對(duì)每一個(gè)View進(jìn)行配置;他們都是讓控件不被父View遮擋系統(tǒng)自動(dòng)計(jì)算的距離,你當(dāng)然也可以關(guān)閉這個(gè)功能;iOS11前用automaticallyAdjustsScrollViewInsets,iOS11后用contentInsetAdjustmentBehavior。
了解更多
UITableView優(yōu)化方法
cell重用,異步執(zhí)行耗時(shí)操作這種就不用提了,這都是大家能想到的,我們可以說(shuō)一點(diǎn)其他的。
1:減少視圖層次;
2:正確使用api,比如設(shè)置rowHeight而不去取dataSource;
3:減少離屏渲染;
圓角圖片
陰影
...
4:設(shè)置視圖不透明減少渲染代價(jià),如果有透明度則會(huì)根據(jù)多個(gè)視圖才知道一個(gè)像素點(diǎn)顯示什么顏色;
5:RunLoop空閑計(jì)算cell高度并緩存;
6:利用RunLoop的mode在滾動(dòng)時(shí)不執(zhí)行耗時(shí)操作。
了解更多
ssl/tls證書作用
如果沒(méi)有ssl/tls證書,每個(gè)不同客戶端訪問(wèn)服務(wù)器都需要生成一對(duì)密鑰,這會(huì)造成服務(wù)器端存儲(chǔ)的密鑰太多等問(wèn)題;讓所用客戶端使用統(tǒng)一的服務(wù)器ssl/tls證書則可以解決這些問(wèn)題。
https=http+ssl/tls,拿我們客戶端請(qǐng)求api來(lái)說(shuō),我們適配https時(shí)要后臺(tái)給我們一個(gè)cer證書,這個(gè)證書里面包括了:頒發(fā)機(jī)構(gòu)、有效期、RSA公鑰和Hash指紋等信息;客戶端會(huì)把這個(gè)證書交給請(qǐng)求庫(kù),請(qǐng)求庫(kù)負(fù)責(zé)完成加/解密;為什么需要從頒發(fā)機(jī)構(gòu)申請(qǐng)證書呢?因?yàn)槲覀兊腶pi和web可能在一個(gè)域名下,一個(gè)域名只能一個(gè)證書,也就是說(shuō)如果只有api訪問(wèn)這個(gè)域名我們完全可以自己創(chuàng)建一個(gè)證書設(shè)置受信用;然而如果web也要訪問(wèn)該域名則瀏覽器不會(huì)認(rèn)為這個(gè)證書受信用會(huì)拒絕訪問(wèn)。
這個(gè)欄目將持續(xù)更新--請(qǐng)iOS的小伙伴關(guān)注!
作為開(kāi)發(fā)者,有一個(gè)學(xué)習(xí)的氛圍跟一個(gè)交流圈子特別重要,這是一個(gè)我的iOS交流群:761407670 進(jìn)群密碼000,不管你是小白還是大牛歡迎入駐 ,分享BAT,阿里面試題、面試經(jīng)驗(yàn),討論技術(shù), 大家一起交流學(xué)習(xí)成長(zhǎng)!