原文出處:hherima
本文旨在總結iOS知識網絡,知識點,該知識網絡羅列出常見UIKit、Foundation的對象特點和一些使用經驗,可以看成是一本書;文本編輯采用樹的形式,對知識點進行羅列,并標注一些使用經驗(★)希望對初學者有用或給一些解決疑難雜癥者提供思路;某些知識點會深入探討;通過總結希望站在一個較高平臺的角度全觀Objective-C。
知識樹中有些是原創文章,有些則是轉載網絡上iOS大神的文章。由于篇幅的限制筆者會簡潔地介紹各個知識點,讀者可通過鏈接了解詳情。當然一個人的知識面是相當有限的,在給各位讀者提供知識參考的同時,歡迎大家對本文提意見。
/->UIViewController
|ViewController在iOS只是一個非常重要的概念,其在一個App中所扮演的角色:
|(1) View Management:管理View ? ??(2) Data Marshalling:管理數據
|(3) User Interactions:響應用戶交互?(4) Resource Management:管理資源
|(5) Adaptivity:適配不同的屏幕尺寸空間的變化
|+ (void)initialize +(void)load?的調用時機,區別【點擊】
|ViewDidLoad調用時機:當view被首次使用的時候,某些情況可提升性能
|橫豎屏的坑【點擊】。APP整體是豎屏,單個controller可以是橫屏的
|★兩種交互方式:push和present
|左右滑動?- (void)pushViewController:(UIViewController *) animated:(BOOL)
|模態,從下往上彈出?- (void)presentViewController:(UIViewController *) animated: (BOOL) completion:
|★還有一種:直接把Controller的view添加到另一個Controller上。
|->UIView
|frame 和bound 的區別【點擊】
|frame 是相對父試圖坐標的值;?bound是本身坐標系統的值
|layoutSubviews【點擊】需要將[super layoutSubviews];放到最后,不然iOS7有可能會有這個崩潰
|★“Auto Layout still required after executing -layoutSubviews” iOS7上崩潰sdk缺陷【點擊】
|每一個視圖有唯一的父視圖【點擊】。addsubview操作把它從上一個父試圖中移除
|善于使用hidden?使用animateWithDuration簡單地控制頁面切換效果
|使用animateWithDuration簡單地控制頁面切換效果【點擊】
|★簡單動畫?animateWithDuration【點擊】
|->CALayer
|CALayer是個簡單的類,它是用來在屏幕上顯示內容展示的矩形區域.【容芳志出品點擊】
|直接從NSObject繼承,少了UIResponder類,固CALayer悲催的不能響應任何用戶事件【點擊】
|->UIWindow
|每一個IOS程序都有一個UIWindow
|UIWindow有三個層級,分別是Normal,StatusBar,Alert【點擊】
|keyWindow是指定的用來接收鍵盤以及非觸摸類的消息,
|而且程序中每一個時刻只能有一個window是keyWindow。
|->UIImage
|加載圖片幾種方式【點擊】
|[UIImage imageNamed:@“xxx”] 系統緩存到cache中
|[UIImage imageWithContentsOfFile:path] 不緩存
|[UIImage imageWithData:data] ?不緩存
|★拉伸圖片,四角保持不變resizableImageWithCapInsets:
|★加載gif圖片【點擊】
|->UILabel【點擊】
|沒有上下居中對齊,可以使用TTTAttributedLabel
|★重寫drawTextInRect:方法,可以自定義繪制區域,比如可設置Inset
|[super drawTextInRect:UIEdgeInsetsInsetRect(rect, self.textInsets)];
/
/->UIKit
|
||->UIButton
||設置顏色,文字一定要指定button狀態
||善于使用contentEdgeInsets,可以設置文本邊距【點擊】
||設置圓角可layer.cornerRadius
||->UITextfield
||隱藏鍵盤,[textfield resignFirstResponder]
||★任意頁面隱藏鍵盤【點擊】
||->UIScrollerView
||上拉下拉原理【點擊】
||->UITableView
||復用,注意重寫?- (void)prepareForReuse
||dequeueReusableCellWithIdentifier 從重用池中獲取,可能是nil
||dequeueReusableCellWithReuseIdentifier?同上,但是不會是nil
||插入,刪除,移動section或item的順序,需遵循下面兩個步驟【點擊】
||1. 更新dataSource的數據
||2. 調用相應的collection view方法刪除或者插入section或item
||★非常嚴格的條件:,在更新collection view之前,先更新datasource,
||因為collection view總是假設你已經準備好打他source了 否則collection view收到錯誤的item,并造成crash
||右側音序條【點擊】
||UITableView上拉、下拉原理【點擊】
||AsyncDisplayKit 流暢的解決方法【點擊】
||★tableView正在滾動的時候,如果reloadData,偶爾發生App crash的情況【點擊】
||★UITableview Deceleration 加速滑動(慣性滑動)、彈性回歸原理【點擊】
||->UIDevice
||設備名 [UIDevice currentDevice].name,
||系統版本號 [[UIDevice currentDevice].systemVersion doubleValue];【點擊】
||屏幕旋轉方向 [[UIDevice currentDevice] orientation]
||區分iPad還是iPhone [UIDevice currentDevice].userInterfaceIdiom);
||->UIScreen
||如何正確的繪制1像素的線【點擊】
||保證邊距不變,內容等比例拉伸【點擊】
||->UIEdgeInsets
||實際顯示邊距,跟設置邊距的距離【點擊】
|->自動布局
|Masonry
|storyboard
|
|/->NSObject既是對象也是協議,可以將對象自動置nil 比如 int = 0 bool = NO
||幾乎所有類的基類或者協議【點擊】
||isKindOfClass:和isMemberOfClass:,通過這兩種方法可以確定一個類的從屬關系
||后者測試一個接收器是否是一個指定類的實例;而后者可以測試類的從屬關系。
||respondsToSelector: 方法測試一個接收器是否通過selector實現(implements)了一個標志符話的方法
||description方法,允許一個對象返回一個字符串來描述它的內容;這個常用于調試debug
||encodeWithCoder: 和 initWithCoder:方法,NSCoding協議中僅有的組成成員
||第一個允許對象編譯它的實例變量,第二個允許一個對象初始化它自身的解碼實例變量。
||conformsToProtocol:方法,測試接收器(對象或者類)符合一個給定的協議(protocol)
||★類對象中的 isa 指向類結構被稱作 metaclass【點擊】跟[object class]有點區別,比如KVO的時候
||★__weak如何實現對象值自動設置為nil的【點擊】
||->NSString & NSMutableString
||NSString作為屬性時候,用copy還是strong修飾?
||strong是單純的增加對象的引用計數,而copy操作是執行了一次深拷貝【點擊】
||->NSArray &?NSMutableArray
||NSArray 各種遍歷方式,倒序遍歷【點擊】
||NSArray簡便初始化方法@[@"1",@"2"];
||淺拷貝。數組本身使用地址,但是數組item仍是舊對象【Apple 官方解釋點擊】
||無論copy、arrayWithArray、copyWithZone 數組內對象并沒有變。
||只是copy出來的array是新地址,arrayWithArray出來的數組也是新地址。
||深拷貝。數組本身使用地址,但是數組item是新地址
||[[NSArray alloc] initWithArray:someArray copyItems: YES];
||深拷貝時候,數組中的item必須實現NSCopying協議并實現copyWithZone:
||★防止NSArray was mutated while being enumerated
||array包含array的情況深拷貝。NSArray* trueDeepCopyArray = [NSKeyedUnarchiver
||unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];
||★containsObject 注意:在對比數組中元素的時候,調用元素的isEqual的返回值。
||->NSDictionary &?NSMutableDictionary
||取值時候,最好判斷object的類型。? ? if ([object isKindOfClass:[NSString class]]){ //todo};
||->NSNumber 和 NSInteger NSRange
||前者專門用來裝基礎類型的對象,把整型、單精度、雙精度、字符型等基礎類型存儲為對象
||->NSNullFMDB數據庫,使用的時候崩潰
||JsonKit轉換以后會生出相應的[NSNull null]對象【點擊】
||->NSData字節緩沖區
||+ (nullable instancetype)dataWithContentsOfURL:(NSURL *)url
||dataWithContentsOfURL 雖然是同步的,但可以結合gcd 異步加載網絡圖片【點擊】
||->NSUserDefaults【點擊】
||可用于APP setting默認值不好用,SDK bug
||設置WebVIew的UA【點擊】
||->NSDate & NSDateFormatter &NSCalendar
||可判斷過去幾個小時,還是幾天?- (NSDateComponents *)?components:fromDate:toDate:options:
||可獲取時間戳
||有時候有8小時的時差,解決辦法【點擊】
||在開發iOS程序時對日期處理的總結【點擊】
||->NSCoding & NSCoder僅有的兩個方法,數據的序列號和反序列化【點擊】
||- (void)encodeWithCoder:(NSCoder *)aCoder;
||- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder;
||->NSCopying &?NSZone
||+ (instancetype)allocWithZone:深拷貝,類似于memcpy這樣的C方法【點擊】
||->NSAutoreleasePool
||降低內存峰值【點擊】
||->NSFileManager刪除文件的時候先判斷是否存在是個好習慣
||->NSTimer
||NSTimer 簡單使用【點擊】
||★NSTimer定時器時間并不精確,類似于公交車進站,堵車就不準時【點擊】
||->NSLog暴力打印,常用于測試【點擊】
||->NSClassFromString從字符串獲取類。NSStringFromClass,從類名獲取字符串
||★不要小瞧這兩個API,配合使用,他可以做到代碼邏輯解藕的效果。
|/
|->Foundation
|
||->NSIndexPath鏈式結構;tableview用的比較多【點擊】
||初始化?[NSIndexPath indexPathForRow:0 inSection:1];
||->NSError網絡變成經常用到
||->NSException
||->NSStringEncoding NSString的編碼格式,了解即可【點擊】
||->NSProgressIndicator
||->NSBundle?是個目錄,包含了程序使用的資源,如圖像,聲音,編譯好的代碼,nib文件【點擊】
||->NSNetServiceBrowser
||->NSValue可以包裝任意一個對象,可以用NSValue將struct存到NSArray和NSDictionary中?!?a target="_blank" rel="nofollow">點擊】
||->NSURLConnectioniOS9已不再使用
||->NSURLSession&NSURLSessionTask【點擊】NSURLSession提供的功能:
||通過URL將數據下載到內存【點擊】
||通過URL將數據下載到文件系統
||將數據上傳到指定URL
||在后臺完成上述功能【點擊】
||->NSURLRequest 包裝了網絡請求的信息【點擊】
||->NSInputStream & NSOutputStream socket編程【點擊】
||->NSPredicate
||謂語查詢,原理和用法都類似于SQL中的where【點擊】
||->NSLayoutConstraint
||->NSLock & NSRecursiveLock & NSCondition多線程鎖
||最基本的同步鎖【點擊】
||@synchronized{//todo} 同樣也是同步鎖【點擊】
||事實上信號量也能實現鎖的目的,信號量和鎖的區別【點擊】第二篇【點擊】
||->NSMethodSignature
/|配合NSInvocation實現消息轉發【點擊】
iOS|->NSInvocation直接調用 某個對象的消息【點擊】
|iOS中可以直接調用 某個對象的消息 方式有2種performSelector:withObject: 和NSInvocation
||當然,還以用C語言的函數指針,參見下面的“方法調配技術”
||->NSSet無序的對象集合,用處少
||->NSUrl基本使用,包含File URL和File path【點擊】
||->AVPlayer基本使用【點擊】
||獲取視頻時間長度【點擊】
|->NSNotificationCenter同步的機制【點擊】注意防止重復,相似的機制還有delegate,observer,block
|
|/->創建push原理介紹、證書制作、測試push 專輯【點擊】
||“iOS push全方位解析(一)【譯文】”——iOS PUSH概述【點擊】
||“iOS push全方位解析(二)【譯文】”——生成OpenSSL證書,Provisioning Profile【點擊】
||“iOS push全方位解析(三)【譯文】”——一個極簡的demo,并測試一下push【點擊】
|/
|->Push
|
||★iOS6、7、8、9 Push的演化【點擊】,但目前還是不盡人意(APP 無法獲取通知欄消息數目)
||★php寫的可以在本機發送iOS push程序【點擊】
||iOS7 Background Remote Notification(后臺遠程通知——靜默push)【點擊】
|->有一些三方push SDK:極光push
|
|->block必須掌握
|block專輯【點擊】;Block帶有局部變量的匿名函數;iOS開發尤其實用
|【block編程第一篇】 block編程熱點介紹(官方文檔翻譯的)【點擊】
|【block編程第二篇】 block捕獲變量和對象【點擊】
|【block編程第三篇】block內存管理——如何驗證block在棧上,還是堆上【點擊】
|【block編程第五篇】block中使用 weak–strong dance 技術避免循環引用【點擊】
|->多線程
|iOS有三種多線程編程的技術,分別是:【點擊】
|1、NSThread?下面會講到
|2、Cocoa NSOperation?下面會講到
|3、GCD 下面會講到
|這三種編程方式從上到下,抽象度層次是從低到高的,抽象度越高的使用越簡單。
|dispatch_once 執行一次,用于創建單例【點擊】可滿足線程安全
|iOS 不像C++ 那樣,可以直接將構造函數設成private。所以創建絕對單例模型需重寫allocWithZone,【點擊】
|
|/->引用計數(retainCount)
||retain 引用計數+1 對象alloc時,引用計數為1, release引用計數-1.引用計數=0時候,真正釋放
||autoRelease,自動釋放對象【點擊】
||->便捷構造方法?iOS
||對象在自動釋放池中,不需要開發者手動釋放,比如下面的方法
||NSString的stringWithString
||NSArray的arrayWithObjects:和arrayWithArray:
||UIImage的imageNamed:
||->內存管理高級指南【官方譯點擊】
||->內存管理實踐【點擊】
|/
|->內存管理【專欄點擊】
|
||->MRC手動引用計數。release和retain成對兒
|->ARC自動引用計數
|★強烈建議使用ARC
|★禁止在函數內返回局部變量指針,不然就是野指針!
|★容易引起循環引用的地方【點擊】
|★- (id)performSelector:(SEL)aSelector withObject:(id)object;引起警告
|warning:performSelector may cause a leak because its selector【點擊】
|
|iOS可通過URL Scheme,調用別的APP(iOS內的應用調用協議),APP 實現?- (BOOL)application: openURL: options:
|
|/->Runtime運行時特點【《運行時之一:類與對象》南峰子出品點擊】
||Objective-C程序員可以在程序運行時創建,檢 查,修改類,對象和它們的方法【點擊】
||Objective-C runtime庫也負責找出方法的最終執行代碼
||★class ?Objective-C類是由Class類型來表示的,它實際上是一個指向objc_class結構體的指針。
||struct objc_class {
||Class isa ?OBJC_ISA_AVAILABILITY;
||#if !__OBJC2__
||Class super_class ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE; ?// 父類
||const char *name ? ? ? ? ? ? ? ? ? ? ? ?OBJC2_UNAVAILABLE; ?// 類名
||long version ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE; ?// 類的版本信息,默認為0
||long info ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OBJC2_UNAVAILABLE; ?// 類信息,供運行期使用的一些位標識
||long instance_size ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE; ?// 該類的實例變量大小
||struct objc_ivar_list *ivars ? ? ? ? ? ?OBJC2_UNAVAILABLE; ?// 該類的成員變量鏈表
||struct objc_method_list **methodLists ? OBJC2_UNAVAILABLE; ?// 方法定義的鏈表
||struct objc_cache *cacheOBJC2_UNAVAILABLE; ?// 方法緩存
||struct objc_protocol_list *protocols ? ?OBJC2_UNAVAILABLE; ?// 協議鏈表
||#endif
||} OBJC2_UNAVAILABLE;
||1.isa:所有的類自身也是一個對象,這個對象的Class里面也有一個isa指針,它指向metaClass
||2.super_class:指向該類的父類,如果該類已經是最頂層的根類,則super_class為NULL。
||3.cache:用于緩存最近使用的方法。提高方法查找效率
||★objc_object與idobjc_object是表示一個類的實例的結構體
||struct objc_object {
||Class isa ?OBJC_ISA_AVAILABILITY;
||};
||typedef struct objc_object *id;
||當創建一個類的實例對象時,分配的內存包含objc_object數據結構,然后是類的實例變量的數據。
||NSObject類的alloc和allocWithZone:方法使用函數class_createInstance來創建objc_object數據結構。
||另外還有我們常見的id,它是一個objc_object結構類型的指針
||★meta class元類,是一個類對象的類;它存儲著一個類的所有類方法。
||當我們向一個對象發送消息時,runtime會在這個對象所屬的這個類的方法列表中查找方法;
||而向一個類發送消息時,會在這個類的meta-class的方法列表中查找。
||★繼承體系【點擊】
||動態創建類【點擊】
||objc_setAssociatedObject【點擊】給對象增加屬性,一般配合類別使用
||object_getClass ?得到一個實例的類【點擊】
||objc_copyImageNames ?獲取指定類所在動態庫【南峰子出品點擊】
||objc_copyClassList??創建并返回一個指向所有已注冊類的指針列表【點擊】
||class_xxx系列函數【點擊】
||class_copyPropertyList??獲取類的屬性
||class_addMethod?為類添加方法
||class_isMetaClass?判斷是否為元類
||class_getName 獲取類名
||class_copyIvarList?拷貝類的實例變量列表
||class_getInstanceMethod?獲取實例方法
||->Runnloop【ibireme出品點擊】
||RunLoop 實際上就是一個對象,這個對象管理了其需要處理的事件和消息
||并提供了一個入口函數來執行上面 Event Loop 的邏輯
||Run Loop并非iOS平臺專屬的概念,在任何平臺的多線程編程中,為控制線程生命周期【點擊】
||接收處理異步消息,都需要類似Run Loop的循環機制來實現:從簡單的一個無限順序
||do{sleep(1);//執行消息}while(true),到高級平臺,如Android的Looper,都是類似的機制。
||★PerformSelecter?當調用 NSObject 的 performSelecter:afterDelay: 后,實際上其內部會創建一個 Timer
||并添加到當前線程的 RunLoop 中;所以如果當前線程沒有 RunLoop,則這個方法會失效【點擊】
|/
|->iOS 動態機制
|
||->消息傳遞objc_msgSend【點擊】【南峰子出品點擊】
||obj-c脫胎于smalltalk的消息處理。所有方法調用都是發消息。消息是啥?一串字符【點擊】
||如果向某對象傳遞消息,那就會使用動態綁定機制來決定需要調用的方法
||objc_msgSend有兩個隱藏參數,消息接收對象 方法的selector ,即(self,_cmd)
||->消息轉發message forwarding【點擊】
||就是對象在接收到無法解讀的消息之后會發生什么情況
||(1)?+(BOOL) resolveInstanceMethod:(SEL)selector?類是否新增一個實例方法
||(2)?resolveClassMethod 是否新增了類方法
||(3)?-(id) forwardingTargetForSelector:(SEL)selector 能不能把這條消息轉給其他接收者來注冊
||(4)-(void) forwardInvocation:(NSInvocation*)invocation??消息派發系統
||(5)最后若都不能處理消息,則doesNotRecognizeSelector: 會拋出異常
||★當我們不能確定一個對象是否能接收某個消息時,會先調用respondsToSelector:來判斷一下
||->SEL【點擊】
||SEL又叫選擇器,是表示一個方法的selector的指針,每一個方法都對應著一個SEL。
||OC在編譯的時候,會根據方法的名字(包括參數序列),生成一個用 來區分這個方法的唯一的一個ID
||這個ID就是SEL類型的。需要注意的是,只要方法的名字(包括參數序列)相同,那么它們的ID都是相同的。
||就是 說,不管是超類還是子類,不管是有沒有超類和子類的關系,只要名字相同那么ID就是一樣的
||★方法的定義體里面,我們可以通過訪問_cmd得到這個方法自己的SEL。
||->方法調配技術method swizzling?用于調試【南峰子出品點擊】
||IMP?它是objetive-C 方法(method)實現代碼塊的地址,實際上是函數指針,指向方法實現的首地址
||IMP imp = [requestItem.delegateTarget methodForSelector:selector];
||void (*func)(id, SEL, ResponseItem *) = (void *)imp;
||func(requestItem.delegateTarget, selector, responseItem);
||可以從selector獲取IMP,比如:- (IMP)methodForSelector:(SEL)aSelector;
||Swizzling應該總是在+load中執行
|在 iOS 中,幾乎所有類都是 responder,比如 UIWindow、UIView、UIControl、UIControllers 等
|當手指去觸摸屏幕上 UIView 的實例對象 aView。產生一個觸摸事件 UIEventTypeTouches
|而接收觸摸事件的對象 aView,就是一個 responder object。
|initial view –> super view –> …..–> view controller –> window –> Application –> AppDelegate
|
|/->沙盒(Sandbox)iOS沙盒機制【容芳志出品點擊】
||每個應用程序都有自己的存儲空間
||應用程序不能翻過自己的圍墻去訪問別的存儲空間的內容
||應用程序請求的數據都要通過權限檢測,假如不符合條件的話,不會被放行。
||->GroupiOS8+數據共享,例如擴展(Extension)共享數據【點擊】
||->SpotlightiOS9+ 系統搜索。【官方demo點擊】
||->GCD(Grand Central Dispatch)iOS開發有一個強有力的多線程工具【點擊】
||多線程入門【raywenderlich出品點擊】
||系統提供一個叫做 主隊列(main queue)
||系統還提供一個叫做全局調度隊列(Global Dispatch Queues)有四個優先級
||開發者自己創建隊列(串行,或者并行)
||★至少有五個隊列任你處置:主隊列、四個全局調度隊列,再加上任何你自己創建的隊列。
||GCD 深入理解:第一部分【點擊】
||GCD 深入理解:第二部分【點擊】
||開發常見方法介紹
||dispatch_after?延后工作
||Dispatch Groups?會在整個組的任務都完成時通知你
||dispatch_semaphore_t ?信號量,讓你控制多個消費者對有限數量資源的訪問。【點擊】
||dispatch_semaphore_wait? 使得信號量-1,當=0時候阻塞
||dispatch_semaphore_signal? 釋放信號量,即信號量+1
||
||->CoreData數據持久化,相比sqlite有下面優勢【點擊】
||數據庫字段或者表有更改會導致crash,CoreData的版本管理和數據遷移變得非常有用,
||手動寫sql語句操作還是麻煩一些。
||不光能操縱SQLite,CoreData和iCloud的結合也很好,如果有這方面需求的話優先考慮
||并不是直接操縱數據庫,比如:使用CoreData時不能設置數據庫的主鍵,目前仍需要手動操作。
||效率上其實跑程序時感覺不出來,畢竟手機上的數據不能跟網站的數據和訪問量相提并論。
|/
|->特殊封裝&平臺特性
|
||->類別(Category)擴展(Extension)微小區別【點擊】
||->KVC鍵值編碼
||在IOS的中,沒有絕對的私有,包括方法和變量,可以通過字符獲取屬性【點擊】
||->KVO鍵值觀察,依賴isa-swizzling技術【王中周出品點擊】
||依賴Runtime 和KVC 一個新的類會動態被創建。詳細原理【點擊】另外一篇【點擊】
||同時派生類還重寫了 class 方法以“欺騙”外部調用者它就是起初的那個類。
||然后系統將這個對象的 isa 指針指向這個新誕生的派生類,因此這個對象就成為該派生類的對象了,
||因而在該對象上對 setter 的調用就會調用重寫的 setter,從而激活鍵值通知機制
||★Person在建立KVO監聽前和之后的打印輸出?self->isa:Person ? ?[self class]:Person
||self->isa:NSKVONotifying_Person ? [self class]:Person
||★比如:Tableview上拉下拉動畫檢測offset;播放視頻,獲取視頻時長時候等
||為什么KVO不成對兒調用,會崩潰?
||->多任務
||后臺運行一段時間(不是地圖,voip類app)【點擊】
||->3D Touch,通過在plist中添加菜單,然后app實現下面的方法。進入APP
||- (void)application: performActionForShortcutItem: completionHandler:
||->spotlight通過系統搜索,進入APP【點擊】
|->Touch ID如何使用iOS 8 指紋識別,代碼、實例【點擊】
|->HTTPs
|建立安全鏈接【點擊】
|https進階【點擊】
|
->iOS工具
CrashHlytics Crash統計工具
AFNetworking 和 ASIHttp
SDImage
TMCache
AsyncDisplayKit?是 Facebook 推出的用于保持界面流暢性的框架
——————————————————————————————
參考文獻:《Objective-C高級編程:iOS與OS X多線程和內存管理》日本人寫的;
《Effective Objective C 2.0:編寫高質量iOS與OS X代碼的52個有效方法》;
《Objective-C基礎教程(第2版)》
網絡博客參考(無循序):念茜、南峰子、ibireme、容芳志、唐巧、王巍、董柏然、阮一峰、一片楓葉,王中周,頤和園等博主
參考的公眾帳號:《iOSDevTips》
完整的UIKit和Foundation 結構 <點擊>