iOS開發(fā)中的一些tips吧

最近比較忙,事也多,這些tips有些亂,沒有進(jìn)行整理,先貼出來,之后會好好整理,大家多包涵。
文件目錄管理:

Utils:這里放一些與應(yīng)用無關(guān)的幫助類文件和全局工具類文件

Components:(項目名)這是重頭戲,所有的模塊都會被放到這里主工程文件

Vendors:這里放一些第三方的類庫,如MagicalRecord / CCUIViewWrapper等等

Models:與數(shù)據(jù)打交道的Model都會放到這里(數(shù)據(jù),業(yè)務(wù),viewmodel)

Config:應(yīng)用的默認(rèn)設(shè)置文件,plist文件等

模塊粒度劃分:

按需要拆分如果其他地方很少會單獨(dú)使用到這些實(shí)體,就可以整體作為一個模塊。當(dāng)然如果將來其他模塊會用到其中的某一部分,就需要重新拆分了

xcode:

昨天手賤升級到iOS10,然后Xcode就得升級到8......于是各種失效......我也是無語了

百度到Xcode8注釋快捷鍵的失效解決方法,這里碼一下:

命令運(yùn)行: sudo /usr/libexec/xpccachectl

然后必須重啟電腦后生效

objection:

objection 是一個輕量級的依賴注入框架;原理是先定義一個協(xié)議(protocol),然后通過objection來注冊這個協(xié)議對應(yīng)的class(在+(void)load里),需要的時候,可以獲取該協(xié)議對應(yīng)的object([injector getObject:@protocol(….Protocol)];)。對于使用方無需關(guān)心到底使用的是哪個Class,反正該有的方法、屬性都有了(在協(xié)議中指定)。這樣就去除了對某個特定Class的依賴。也就是通常所說的「面向接口編程」;

CopyOnWrite:

讀寫分離技術(shù),讀的時候讀原來的對象,寫的時候會復(fù)制一個原對象的副本,往新對象修改,改完之后把指針指向新對象。優(yōu)點(diǎn):1.減少擴(kuò)容開銷。根據(jù)實(shí)際需要,初始化CopyOnWriteMap的大小,避免寫時CopyOnWriteMap擴(kuò)容的開銷;2.使用批量添加。因?yàn)槊看翁砑樱萜髅看味紩M(jìn)行復(fù)制,所以減少添加次數(shù),可以減少容器的復(fù)制次數(shù)。如使用上面代碼里的addBlackList方法; 缺點(diǎn):1.即內(nèi)存占用問題;2.數(shù)據(jù)一致性問題;

alloc init:

init 還有一個需要注意的問題。某些情況下,init 會造成 alloc 的原本空間不夠用,而第二次分配內(nèi)存空間。所以下面的寫法是錯的

根據(jù)設(shè)計模式的 Single Responsibility 的設(shè)計原則,蘋果覺得 alloc 和 init 是做的 2 件不同的事情,把這兩件事情分開放在 2 個函數(shù)中,對于程序員更加清楚明了。更詳細(xì)查閱文檔后,我覺得這是由于歷史原因,讓蘋果覺得 alloc 方法過于復(fù)雜,在歷史上,alloc 不僅僅是分配內(nèi)存,還可以詳細(xì)的指定該內(nèi)存所在的內(nèi)存分區(qū)

@defs 關(guān)鍵字用于返回一個 Objective-C 類的 struct 結(jié)構(gòu),這個 struct 與原 Objective-C 類具有相同的內(nèi)存布局。就象你所知的那樣,Objective-C 類可以理解成由基本的 C struct 加上額外的方法構(gòu)成 struct { @defs( NSObject) }

@compatibility_alias AliasClassName ExistingClassName 用于給一個類設(shè)置一個別名

view渲染和內(nèi)存使用:

    CALayer 是一個 bitmap 圖象的容器類,當(dāng) UIView 調(diào)用自身的 drawRect 時,CALayer 才會創(chuàng)建這個 bitmap 圖象類。具體占內(nèi)存的其實(shí)是一個 bitmap 圖象類,CALayer 只占 48bytes, UIView 只占 96bytes。而一個 iPad 的全屏 UIView 的 bitmap 類會占到 12M 的大??!

在 iOS6 時,當(dāng)系統(tǒng)發(fā)出 MemoryWarning 時,系統(tǒng)會自動回收 bitmap 類。但是不回收 UIView 和 CALayer 類。這樣即回收了大部分內(nèi)存,又能在需要 bitmap 類時,通過調(diào)用 UIView 的 drawRect: 方法重建

    當(dāng)一段內(nèi)存被分配時,它會被標(biāo)記成 “In use“, 以防止被重復(fù)使用。當(dāng)內(nèi)存被釋放時,這段內(nèi)存會被標(biāo)記成 “Not in use”,這樣,在有新的內(nèi)存申請時,這塊內(nèi)存就可能被分配給其它變量。CALayer 包括的具體的 bitmap 內(nèi)容的私有成員變量類型為 [CABackingStore](http://blog.spacemanlabs.com/2011/08/calayer-internals-contents/), 當(dāng)收到 MemroyWarning 時,CABackingStore 類型的內(nèi)存區(qū)會被標(biāo)記成 volatile 類型(這里的 volatile 和 C 以及 Java 語言的 volatile 不是一個意思),volatile 表示,這塊內(nèi)存可能被再次被原變量重用。這樣,有了上面的優(yōu)化后,當(dāng)收到 Memoy Warning 時,雖然所有的 CALayer 所包含的 bitmap 內(nèi)存都被標(biāo)記成 volatile 了,但是只要這塊內(nèi)存沒有再次被復(fù)用,那么當(dāng)需要重建 bitmap 內(nèi)存時,它就可以直接被復(fù)用,而避免了再次調(diào)用 UIView 的 drawRect: 方法

支付寶的插件機(jī)制(應(yīng)用內(nèi)嵌別的應(yīng)用):

支付寶的插件機(jī)制整體上就是通過 html 和 javascript 方式實(shí)現(xiàn)的,主要的好處是:

跨平臺 (可以同時用在 iOS 和 Android 客戶端)

省流量(不需要的插件不用下載,插件本地緩存長期存在不會過期,自己管理插件更新邏輯)

更新方便(不用每次提交 AppStore 審核)

壞處如果非要說有的話,就是用 javascript 寫 iOS 界面,無法提供非常炫的 UI 交互以及利用到 iOS 的所有平臺特性。不過象支付寶這種工具類應(yīng)用,也不需要很復(fù)雜的 UI 交互效果。

另外教大家一個小技巧,如果你不確定某個頁面是不是 UIWebView 做的,直接在那個頁面長按,如果彈出 “ 拷貝,定義,學(xué)習(xí) “ 這種菜單,那就是確定無疑是 UIWebView 的界面了。如下圖所示

結(jié)構(gòu)體:

如下 2 個結(jié)構(gòu)體 SampleA 和 SampleB 在內(nèi)存上是完全一樣的,原因是結(jié)構(gòu)體本身并不帶有任何額外的附加信息

struct SampleA {

        int a;

        int b;

        int c;

};

struct SampleB {

        int a;

struct Part1 {

        int b;

};

struct Part2 {

        int c;

};

};

特殊字體:

使用動態(tài)下載中文字體的 API 可以動態(tài)地向 iOS 系統(tǒng)中添加字體文件,這些字體文件都是下載到系統(tǒng)的目錄中(目錄是/private/var/mobile/Library/Assets/com_apple_MobileAsset_Font/),所以并不會造成應(yīng)用體積的增加。并且,由于字體文件是 iOS 系統(tǒng)提供的,也免去了字體使用版權(quán)的問題。雖然第一次下載相關(guān)的中文字體需要一些網(wǎng)絡(luò)開銷和下載時間,但是這些字體文件下載后可以在所有應(yīng)用間共享,所以可以遇見到,隨著該 API 使用的普及,大部分應(yīng)用都不需要提示用戶下載字體,因?yàn)楹芸赡苓@些字體在之前就被其它應(yīng)用下載下來了

Objective-C對象模型:

方法的定義列表是一個名為 methodLists的指針的指針(如下圖所示)。通過修改該指針指向的指針的值,就可以實(shí)現(xiàn)動態(tài)地為某一個類增加成員方法。這也是Category實(shí)現(xiàn)的原理。同時也說明了為什么Category只可為對象增加成員方法,卻不能增加成員變量;

系統(tǒng)提供的 KVO 的實(shí)現(xiàn),就利用了動態(tài)地修改 isa 指針的值的技術(shù),所以不應(yīng)依賴isa確定所屬類,可能不準(zhǔn)確,而應(yīng)依賴類方法去確定

Objective-C 提供了以下 API 來動態(tài)替換類方法或?qū)嵗椒ǖ膶?shí)現(xiàn):

class_replaceMethod 替換類方法的定義

method_exchangeImplementations 交換 2 個方法的實(shí)現(xiàn)(內(nèi)部實(shí)現(xiàn)相當(dāng)于調(diào)用了 2 次method_setImplementation方法)

method_setImplementation 設(shè)置 1 個方法的實(shí)現(xiàn)

這 3 個方法有一些細(xì)微的差別,給大家介紹如下:

class_replaceMethod在蘋果的文檔(如下圖所示)中能看到,它有兩種不同的行為。當(dāng)類中沒有想替換的原方法時,該方法會調(diào)用class_addMethod來為該類增加一個新方法,也因?yàn)槿绱耍琧lass_replaceMethod在調(diào)用時需要傳入types參數(shù),而method_exchangeImplementations和method_setImplementation卻不需要

initWithFrame:

用[UIView new]或者[[UIView alloc] init]都會調(diào)用initWithFrame這個函數(shù)(有些UIView的子類有特殊情況,比如UITableViewCell,懷疑apple對其做過特殊處理

響應(yīng)者鏈:

響應(yīng)者樹的構(gòu)造過程是在ViewDidLoad周期中來完成的,能夠在viewDidAppear:方法中調(diào)用起效

view在什么情況下能夠變成第一響應(yīng)者?條件是什么?

只要繼承自UIResponder的子類都可使以成為第一響應(yīng)者的,但是除了UITextField,必須在實(shí)現(xiàn)文件中覆蓋canBecomeFirstResponder方法,如果按鈕的target是設(shè)置為nil的,所以系統(tǒng)將去尋找當(dāng)前第一響應(yīng)者,如果第一響應(yīng)者有pressPrint這個方法,那么他會調(diào)用它的pressPrint方法。而現(xiàn)在viewD中是實(shí)現(xiàn)了此方法

UITouch事件和響應(yīng)者鏈走的不是同一套機(jī)制,如果UITouch事件響應(yīng)了手勢就不再響應(yīng)UIEvent事件;或者 UIButton 上加UIView, 因?yàn)椴皇亲咄惶讬C(jī)制,所以會不響應(yīng)UIEvent事件;(如果藥響應(yīng),可以重寫最上層view的 hittest 返回需要點(diǎn)擊的button為 hitest 響應(yīng)的對象(穿透原理))

優(yōu)化:

處理圖片時,你也可以讓GPU為你工作來代替使用Core Graphics。使用Core Image,你不必用CPU做任何的工作就可以在圖片上建立復(fù)雜的效果。你可以直接在OpenGL上下文上直接渲染,所有的工作都在GPU上完成

重寫drawRect:,默認(rèn)的模式是將內(nèi)容縮放以填充視圖的范圍,并且當(dāng)視圖的frame改變時并不會重新繪制

如果你使用的層引發(fā)了離屏渲染,那么你最好避免這種方式。增加遮罩,設(shè)置圓角,設(shè)置陰影都造成離屏渲染。(動畫也會,但是動畫中可以提升性能)

當(dāng)一個層上面的所有像素和屏幕上面的像素完美對應(yīng),我們就說這個層是像素對齊的。主要有2個原因?qū)е驴赡懿粚R。第一個是放大縮??;當(dāng)放大或是縮小是,紋理的像素和屏幕像素不對齊。另一個原因是當(dāng)紋理的起點(diǎn)不在一個像素邊界上。

這2種情況,GPU不得不做額外的計算。這個需要從源紋理中混合很多像素來創(chuàng)建一個像素用來合成。當(dāng)所有像素對齊時,GPU就可以少做很多工作

NSNumber:

所以給一個weak對象賦值,它并不會馬上釋放,而是會放到autorelease pool中,與autorelease pool一起釋放

Tagged Pointer專門用來存儲小的對象,例如NSNumber和NSDate

Tagged Pointer指針的值不再是地址了,而是真正的值(其實(shí)是將值存在指針內(nèi),即指針也就是值)。所以,實(shí)際上它不再是一個對象了,它只是一個披著對象皮的普通變量而已!所以,它的內(nèi)存并不存儲在堆中,也不需要malloc,free。

在內(nèi)存讀取上有著3倍的效率(以前是尋址->發(fā)消息->獲取值,現(xiàn)在直接獲取值),創(chuàng)建時比以前快106倍

load:

所以庫的初始化順序可以如下:

  1. 初始化我們引用的庫
  2. 執(zhí)行我們自己庫的Objective-C的load函數(shù)
  3. 執(zhí)行C++和C的static初始化變量
  4. 初始化引用我們庫的其他庫

在我們的編寫的庫中,會有很多類重寫load函數(shù),他們之間的執(zhí)行順序是不確定的。

當(dāng)父類和子類都實(shí)現(xiàn)load函數(shù)時,父類的load函數(shù)會被先執(zhí)行。load函數(shù)是系統(tǒng)自動加載的,因此不需要調(diào)用父類的load函數(shù),否則父類的load函數(shù)會多次執(zhí)行。

在Category中寫load函數(shù)是不會替換原始類中的load函數(shù)的,原始類和Category中的load函數(shù)都會被執(zhí)行,原始類的load會先被執(zhí)行,再執(zhí)行Category中的load函數(shù)。當(dāng)有多個Category都實(shí)現(xiàn)了load函數(shù),這幾個load函數(shù)執(zhí)行順序不確定

如果類包含繼承關(guān)系,父類的initialize函數(shù)會比子類先執(zhí)行。由于是系統(tǒng)自動調(diào)用,也不需要顯式的調(diào)用父類的initialize,否則父類的initialize會被多次執(zhí)行。

假如這個類放到代碼中,而這段代碼并沒有被執(zhí)行,這個函數(shù)是不會被執(zhí)行的

但是假如我們是修改系統(tǒng)的類,一般會通過添加Category來添加功能,但是Category中如果修改initialize會導(dǎo)致原生的intialize不會執(zhí)行,所以放在load中會比較妥當(dāng)

bridge:

如之前提到的,MRC 下的 Toll-Free Bridging 因?yàn)椴簧婕皟?nèi)存管理的轉(zhuǎn)移,相互之間可以直接交換使用:

NSString *nsStr = (NSString *)cfStr;CFStringRef cfStr = (CFStringRef)nsStr;// 調(diào)用函數(shù)或者方法NSUInteger length = [(NSString *)cfStr length];NSUInteger length = CFStringGetLength((CFStringRef)nsStr);// releaseCFRelease((CFStringRef)nsStr);[(NSString *)cfStr release];

而在 ARC 下,事情就會變得復(fù)雜一些,因?yàn)?ARC 能夠管理 Objective-C 對象的內(nèi)存,卻不能管理 CF 對象,CF 對象依然需要我們手動管理內(nèi)存。在 CF 和 ObjC 之間 bridge 對象的時候,問題就出現(xiàn)了,編譯器不知道該如何處理這個同時有 ObjC 指針和 CFTypeRef 指向的對象。

如何實(shí)現(xiàn)父類的私有方法子類可以訪問:

這時候,我們需要使用__bridge (不做任何處理,指向同一對象,由轉(zhuǎn)化前的對象管理內(nèi)存,后來的對象相當(dāng)于一個弱指針), __bridge_retained(做一次retain,共同管理內(nèi)存), __bridge_transfer (轉(zhuǎn)化,由轉(zhuǎn)化后的對象管理內(nèi)存)

有Father類和Son類,繼承關(guān)系,可以考慮建一個如FatherPrivate.h的私有header:

<colgroup><col style="width: 603px;"></colgroup>
|

// FatherPrivate.h

@interface Father ()

@property (nonatomic, copy) NSString *privateThingSonNeed;

  • (void)privateMethodNeedsSonOverride;

@end

|

同時在Father.m和Son.m中同時import這個私有header,這樣,F(xiàn)ather和Son內(nèi)部對于定義的屬性和方法都是透明的,而對外部是隱藏的(因?yàn)閮蓚€類的header中都沒有import這個私有header

2D繪圖:

這里我們發(fā)現(xiàn),UIKit的代碼并沒有傳遞context。這是因?yàn)閁IKit或AppKit的context是隱形的。UIKit和UIKit維護(hù)著一個context棧。這些UIKit的方法始終在最上面的context繪制。你可以使用UIGraphicsPushContext()和 UIGraphicsPopContext()來push和pop對應(yīng)的context。

BDD和基于bdd的測試框架kiwi:

一個典型的BDD的測試用例包活完整的三段式上下文,測試大多可以翻譯為Given..When..Then的格式,即在一個上下文下,當(dāng)給予一個的條件時,應(yīng)該有的行為或特性;

可變參數(shù)的函數(shù):

-(id)initWithTitle:(NSString)title message:(NSString)message clickedBlock:(void (^)(CYAlertView *alertView, BOOL cancelled, NSInteger buttonIndex))clickedBlock cancelButtonTitle:(NSString )cancelButtonTitle otherButtonTitles:(NSString)otherButtonTitles,…NS_REQUIRES_NIL_TERMINATION; (可變參數(shù)列表)

collectionView自定義動畫:

給系統(tǒng)方法返回初始布局和終止布局,系統(tǒng)會自動過度,如果需要區(qū)分狀態(tài),只要使用系統(tǒng)的枚舉來記錄判斷當(dāng)前出去插入,刪除,或者轉(zhuǎn)場等等狀態(tài)予以區(qū)分即可

繪圖:

使用UiKit,你只能在當(dāng)前上下文中繪圖,所以如果你當(dāng)前處于UIGraphicsBeginImageContextWithOptions函數(shù)或drawRect:方法中,你就可以直接使用UIKit提供的方法進(jìn)行繪圖。如果你持有一個context:參數(shù),那么使用UIKit提供的方法之前,必須將該上下文參數(shù)轉(zhuǎn)化為當(dāng)前上下文。幸運(yùn)的是,調(diào)用UIGraphicsPushContext 函數(shù)可以方便的將context:參數(shù)轉(zhuǎn)化為當(dāng)前上下文,記住最后別忘了調(diào)用UIGraphicsPopContext函數(shù)恢復(fù)上下文環(huán)境

運(yùn)行時:

我們經(jīng)常在方法中使用self關(guān)鍵字來引用實(shí)例本身,但從沒有想過為什么self就能取到調(diào)用當(dāng)前方法的對象吧。其實(shí)self的內(nèi)容是在方法運(yùn)行時被偷偷的動態(tài)傳入的。

當(dāng)objc_msgSend找到方法對應(yīng)的實(shí)現(xiàn)時,它將直接調(diào)用該方法實(shí)現(xiàn),并將消息中所有的參數(shù)都傳遞給方法實(shí)現(xiàn),同時,它還將傳遞兩個隱藏的參數(shù):

1.接收消息的對象(也就是self指向的內(nèi)容)

2.方法選擇器(_cmd指向的內(nèi)容)

[super class]等價于[self class]

盡管轉(zhuǎn)發(fā)很像繼承,但是NSObject類不會將兩者混淆。像respondsToSelector: 和 isKindOfClass:這類方法只會考慮繼承體系,不會考慮轉(zhuǎn)發(fā)鏈。比如上圖中一個Warrior對象如果被問到是否能響應(yīng)negotiate消息:結(jié)果是NO,因?yàn)樗m然能夠接受negotiate消息而不報錯,是因?yàn)樗哭D(zhuǎn)發(fā)消息給Diplomat類來響應(yīng)消息而不是實(shí)現(xiàn)了Diplomat方法;

1)、category會在編譯時將方法和屬性鏈接到類的方法和屬性列表中,category的方法沒有“完全替換掉”原來類已經(jīng)有的方法,也就是說如果category和原來類都有methodA,那么category附加完成之后,類的方法列表里會有兩個methodA

2)、category的方法被放到了新方法列表的前面,而原來類的方法被放到了新方法列表的后面,這也就是我們平常所說的category的方法會“覆蓋”掉原來類的同名方法,這是因?yàn)檫\(yùn)行時在查找方法的時候是順著方法列表的順序查找的,它只要一找到對應(yīng)名字的方法,就會罷休_,殊不知后面可能還有一樣名字的方法。

3)、附加category到類的工作會先于+load方法的執(zhí)行,所以可以在類的+load方法中調(diào)用category方法。

4)、AssociationsManager里面是由一個靜態(tài)AssociationsHashMap 來存儲所有的關(guān)聯(lián)對象的。這相當(dāng)于把所有對象的關(guān)聯(lián)對象都存在一個全局map里面。而map的的key是這個對象的指針地址(任意兩個不同對象的指針地址一定是不同的),而這個map的value又是另外一個AssociationsHashMap,里面保存了關(guān)聯(lián)對象的kv對。而在對象的銷毀邏輯里面runtime的銷毀對象函數(shù)objc_destructInstance里面會判斷這個對象有沒有關(guān)聯(lián)對象,如果有,會調(diào)用_object_remove_assocations做關(guān)聯(lián)對象的清理工作

靜態(tài)庫, 動態(tài)鏈接庫,動態(tài)加載庫:

沙盒目錄及使用:

[NSUserDefaults standardUserDefaults] Library下的Preference,使用系統(tǒng)的plist文件;如果想要新建一個plist文件可以:

[[NSUserDefaults alloc]initWithSuiteName:@"gxw”]; 創(chuàng)建一個叫 gxw.plist的文件,如果已有就直接獲取,沒有就重新創(chuàng)建一個;

UIWindow:

UIWindow有 UIWindowLevel 屬性,是一個 cgfloat 類型 包含三個枚舉 normal = 0.0,statusbar = 1000.0,alert = 2000.0 當(dāng)前keywindow隊列中l(wèi)evel值越大的window顯示在最上面; 系統(tǒng)默認(rèn)的是 normal = 0.0; statusbar狀態(tài)欄的window 是 1000.0; 系統(tǒng) alert 的是1996.0 左右; 設(shè)置 key 用來接收鍵盤輸入等非觸摸事件;如果想實(shí)現(xiàn)一些遮蓋狀態(tài)欄的彈窗可以利用 UIWindowLevel 實(shí)現(xiàn);

編譯警告:

在Build Phases中的 Compile Sources中每個文件加入 -w 可以忽略掉該文件的編譯警告, 加入 -Wno-unused-variable 可以忽略未使用的變量名警官

對象的轉(zhuǎn)換:

為什么要在主線程刷新UI:(自線程的UI操作需要在自線程生命周期結(jié)束后執(zhí)行,實(shí)際上也是返回給主線程執(zhí)行)

1.(google的一套UI刷新規(guī)則)多線程操作UI控件,由于移動設(shè)備UI控件多,復(fù)雜,還有動畫,交互等等復(fù)雜的邏輯容易出錯,且移動設(shè)備設(shè)計之初內(nèi)存小,CPU數(shù)量和性能原因,所以把UI刷新統(tǒng)一放在UI線程執(zhí)行,簡化了邏輯也符合移動端較強(qiáng)UI展示的需要,也方便管理提高UI的使用效率;

2.如果能解決多線程的弊端確實(shí)可以提升效率,但是與其對規(guī)則推倒重來使用復(fù)雜的規(guī)則不如專注于設(shè)備硬件性能提升上;

3.自線程執(zhí)行耗時操作,主線程執(zhí)行重量級操作;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,099評論 0 9
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,656評論 30 472
  • __block和__weak修飾符的區(qū)別其實(shí)是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,608評論 0 6
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,906評論 33 466
  • 【背景】 大家在日常生活當(dāng)中有沒有發(fā)現(xiàn)一個很普遍的現(xiàn)象:平時什么事情也做不好,但總是瞧不上別人,動不動就覺得自己比...
    夜貓子譚娟閱讀 482評論 0 0

友情鏈接更多精彩內(nèi)容