個(gè)人主頁:http://hellogod.cn
長文,建議跳躍選擇性閱讀,大約10min可以讀完全文。
1.目錄
- 1.個(gè)人學(xué)習(xí)建議
- 2.知識(shí)點(diǎn)整理
- 3.下集預(yù)告
iOS這一行,都過了這么多年,還是水分很足,沒有幾個(gè)愿意安安心心查資料寫東西的。雖說博客都是互相抄,但是起碼其他行業(yè)抄的最開始的人是對(duì)的,但是這一行因?yàn)橹形馁Y料少(是的,到現(xiàn)在中文資料也不完善),所以出現(xiàn)很多粗制濫造的,這里經(jīng)過筆者校驗(yàn)之后分享一些相關(guān)知識(shí)。
個(gè)人建議:
入門視頻首選是斯坦福CS193P課程 iOS10, Xcode8 ,Swift 3 - Youtube,白胡子老爺爺在這一行可以稱得上是元老,之前還想出一個(gè)針對(duì)這個(gè)視頻教程的學(xué)習(xí)筆記,后來給鴿了;這里鏈接放了YouTube上的最新視頻,墻內(nèi)的朋友也可以自行百度其他資源,我這里也存了一份百度云(16年的版本iOS9),需要的可以在評(píng)論留下郵箱(某資源論壇既視感???)。
入門教材Programming in Objective-C 6th edition(英文版),這里附上教材PDF下載鏈接,沒有具體考證鏈接合法性,經(jīng)濟(jì)允許建議支持正版。
項(xiàng)目實(shí)戰(zhàn),大學(xué)生的話去實(shí)驗(yàn)室找一個(gè)項(xiàng)目做一做,大概幾個(gè)月也就熟了(最初級(jí)的那種),這里還要感謝當(dāng)初帶我的學(xué)長@子豪學(xué)長——是一個(gè)很讓人佩服的學(xué)長。社會(huì)人士自學(xué)的話可以在在github、碼云上面多找找完整的客戶端試試看。
下面是學(xué)習(xí)OC時(shí)對(duì)于一些知識(shí)點(diǎn)的總結(jié),資料來源互聯(lián)網(wǎng),權(quán)當(dāng)學(xué)習(xí)筆記,參考的資料盡量附上原文鏈接。
2.重要知識(shí)點(diǎn)總結(jié)
其實(shí)下面的每一個(gè)點(diǎn)都可以單獨(dú)行文,這里摘錄其中較為重要的部分,同時(shí)添加鏈接供讀者深度查看。之后可能單獨(dú)領(lǐng)出深究,這里先埋坑。
2.1 繼承關(guān)系
OC中的繼承屬于單繼承,這一點(diǎn)和Java類似。
- 在Objective-C中super是指向直接父類的指針
- 而self是指向本身的指針,self就相當(dāng)于java中的this指針。
在Objectiv-C中幾乎所有的類都是繼承自NSObject類,NSObject類中存在大量功能強(qiáng)大的方法。這里不再贅述,詳情可查看
2.2 MVC設(shè)計(jì)模式
iOS開發(fā)——MVC詳解&Swift+OC
2.3 block
這里搬運(yùn)一下
block定義
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
};
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
有人認(rèn)為OC中block 本質(zhì)應(yīng)該是一個(gè)函數(shù)指針加上一個(gè)對(duì)應(yīng)捕獲上下文變量的內(nèi)存塊(結(jié)構(gòu)體或者類)。
建議參考:
知乎:OC中, block(塊)的本質(zhì)是什么?
2.4 靜態(tài)變量、靜態(tài)常量、全局變量
static
static修飾的變量必須放在@implementation外面或方法中,它只在程序啟動(dòng)初始化一次。
static int num;
const
const修飾的變量是不可變的,如果需要定義一個(gè)時(shí)間間隔的靜態(tài)常量,就可以使用const修飾。
static const NSTimeInterval LMJTimeDuration = 0.5;
如果試圖修改TimeDuration編譯器則會(huì)報(bào)錯(cuò)。
如果我們定義一個(gè)字符串類型的靜態(tài)常量就要注意了,這兩種寫法是一樣的,而且是可以修改的。
static NSString const * LMJName = @"iOS開發(fā)者公會(huì)";
static const NSString * LMJName = @"iOS開發(fā)者公會(huì)";
這兩種寫法cons修飾的是* LMJName,*是指針指向符,也就是說此時(shí)指向內(nèi)存地址是不可變的,而內(nèi)存保存的內(nèi)容時(shí)可變的。
所以我們應(yīng)該這樣寫:
static NSString * const LMJName = @"iOS開發(fā)者公會(huì)";
當(dāng)我們定義一個(gè)對(duì)象類型常量的時(shí)候,要將const修飾符放到*指針指向符后面。
extern
extern修飾的變量,是一個(gè)全局變量。
extern NSString * LMJName = @"iOS開發(fā)者公會(huì);
extern修飾的變量也可以添加const進(jìn)行修飾:
extern NSString * const LMJName = @"iOS開發(fā)者公會(huì);
此時(shí)全局變量只能被初始化一次
extern定義的全局常量的用法和宏定義類似,但是還是有本質(zhì)上的不同的。 extern定義的全局常量更不容易在程序中被無意竄改。
2.5 NSObject ,Id, instancetype
- NSObject
NSObject確定對(duì)象類型是繼承于NSObject。很常用。
- id
可以指向任意類型的objcetive-c的對(duì)象,聲明的對(duì)象具有運(yùn)行時(shí)的特性。并不一定是NSObject對(duì)象。對(duì)于一些不能進(jìn)行類型檢查或者不想檢查的地方,可以使用id,經(jīng)常會(huì)聲明delegate為id類型,在運(yùn)行的時(shí)候載使用respondToSelector:檢查。
-
instancetype
stack overflow上面所說:“Use instancetype whenever it's appropriate, which is whenever aclass returns an instance of that same class.”
在instancetype有效的情況下,應(yīng)該盡量去使用instancetype。
id數(shù)據(jù)類型,是一種通用的對(duì)象類型。也就是說,它可以用來存儲(chǔ)屬于任何類的對(duì)象。當(dāng)以這種方式在一個(gè)變量中存儲(chǔ)不同類型的對(duì)象時(shí),在程序執(zhí)行的期間,這種數(shù)據(jù)類型的真正優(yōu)勢就出現(xiàn)了。
instancetype和id的區(qū)別如下(ARC和MRC的講解部分放在后面的2.7中):
區(qū)別1:
在ARC(Auto Reference Count)環(huán)境下:
instancetype用來在編譯期確定實(shí)例的類型,而使用id的話,編譯器不檢查類型, 運(yùn)行時(shí)檢查類型.
在MRC(Manual Reference Count)環(huán)境下:
instancetype和id一樣,不做具體類型檢查
區(qū)別2:
id可以作為方法的參數(shù),但instancetype不可以
instancetype只適用于初始化方法和便利構(gòu)造器的返回值類型
2.6 Copy, strong, retain
先說copy和strong的區(qū)別,這里摘錄一個(gè)例子。
在定義一個(gè)類的property時(shí)候,為property選擇strong還是copy特別注意和研究明白的,如果property是NSString或者NSArray及其子類的時(shí)候,最好選擇使用copy屬性修飾。
為什么呢?這是為了防止賦值給它的是可變的數(shù)據(jù),如果可變的數(shù)據(jù)發(fā)生了變化,那么該property也會(huì)發(fā)生變化。
代碼示例
還是結(jié)合代碼來說明這個(gè)情況
@interface Person : NSObject
@property (strong, nonatomic) NSArray *bookArray1;
@property (copy, nonatomic) NSArray *bookArray2;
@end
@implementation Person
//省略setter方法
@end
//Person調(diào)用
main(){
NSMutableArray *books = [@[@"book1"] mutableCopy];
Person *person = [[Person alloc] init];
person.bookArray1 = books;
person.bookArray2 = books;
[books addObject:@"book2"];
NSLog(@"bookArray1:%@",person.bookArray1);
NSLog(@"bookArray2:%@",person.bookArray2);
}
我們看到,使用strong修飾的person.bookArray1輸出是[book1,book2],而使用copy修飾的person.bookArray2輸出是[book1]。這下可以看出來區(qū)別了吧。
備注:使用strong,則person.bookArray1與可變數(shù)組books 指向同一塊內(nèi)存區(qū)域 ,books內(nèi)容改變,導(dǎo)致person.bookArray1的內(nèi)容改變,因?yàn)閮烧呤峭粋€(gè)東西;而使用copy,person.bookArray2在賦值之前,將books內(nèi)容復(fù)制,創(chuàng)建一個(gè) 新的內(nèi)存區(qū)域,所以兩者不是一回事,books的改變不會(huì)導(dǎo)致person.bookArray2的改變。
總結(jié)起來,其實(shí)@property的參數(shù)還有很多,主要分為四類:
- 1、內(nèi)存管理
retain : release舊值,retain新值
assign :直接復(fù)制(缺省值,適用于非OC對(duì)象類型)
copy : release舊值,copy新值
- 2、讀寫屬性,是否要生成set方法
readaonly :只讀,只生成getter的聲明和實(shí)現(xiàn)
readwrite :可讀可寫,生成setter和getter的生命和實(shí)現(xiàn)(缺省值)
- 3、多線程管理
nonatomic :性能高,不加鎖,線程不安全(建議使用,開發(fā)常寫)
atomic:性能低,加鎖,線程安全(缺省值)
- 4、setter和getter方法的名稱
@property (setter = setXxx: ,getter = xxx) int weight;
一般使用在BOOL類型的成員變量 getter = isXxx
2.7 Manually reference Counting和Automatic Reference Counting
** 1.MRC 手動(dòng)管理內(nèi)存(Manual Reference Counting)**
先看一個(gè)例子:
NSNumber對(duì)象myInt被設(shè)置為整數(shù)100,并且程序輸出顯示它的初始計(jì)數(shù)為1。然后,使用addObject:方法將該對(duì)象添加到數(shù)據(jù)myArr中。引用計(jì)數(shù)變成2.將對(duì)象添加到任何類型的集合都會(huì)使該對(duì)象的引用次數(shù)增加。這意味著,如果隨后釋放了添加的對(duì)象,那么數(shù)組中仍然保存這該對(duì)象的有效引用,對(duì)象不會(huì)釋放。
接下來,將myInt賦值給變量myInt2.要注意這個(gè)操作并沒有使myInt對(duì)象的引用次數(shù)增加,這會(huì)給以后造成潛在的麻煩。例如,如果對(duì)myInt的引用次數(shù)減少到0,并且它占用的空間被釋放,那么myInt2將擁有無效的引用對(duì)象(將myInt賦值給myInt2的操作并沒有復(fù)制實(shí)際的對(duì)象,只是指向myInt在內(nèi)存中位置的指針)。
然后通過代碼再來直觀的感受一下。
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 只要?jiǎng)?chuàng)建一個(gè)對(duì)象默認(rèn)引用計(jì)數(shù)器的值就是1
Person *p = [[Person alloc] init];
NSLog(@"retainCount = %lu", [p retainCount]); // 1
// 只要給對(duì)象發(fā)送一個(gè)retain消息, 對(duì)象的引用計(jì)數(shù)器就會(huì)+1
[p retain];
NSLog(@"retainCount = %lu", [p retainCount]); // 2
// 通過指針變量p,給p指向的對(duì)象發(fā)送一條release消息
// 只要對(duì)象接收到release消息, 引用計(jì)數(shù)器就會(huì)-1
// 只要一個(gè)對(duì)象的引用計(jì)數(shù)器為0, 系統(tǒng)就會(huì)釋放對(duì)象
[p release];
// 需要注意的是: release并不代表銷毀\回收對(duì)象, 僅僅是計(jì)數(shù)器-1
NSLog(@"retainCount = %lu", [p retainCount]); // 1
[p release]; // 0
NSLog(@"--------");
}
// [p setAge:20]; // 此時(shí)對(duì)象已經(jīng)被釋放
return 0;
}
MRC內(nèi)存原則
1.需要引用時(shí),+1;不需要引用了,-1;
2.誰創(chuàng)建,誰release;
3.誰retain,誰release;
4.只要調(diào)用了alloc,必須有release(autorelease)
5.成員變量的set方法中需要注意的:基本數(shù)據(jù)不用管,對(duì)象數(shù)據(jù)需要注意。
2.自動(dòng)釋放池(Automatic Reference Counting)
autorelease是一種支持引用計(jì)數(shù)的內(nèi)存管理方式,只要給對(duì)象發(fā)送一條autorelease消息,會(huì)將對(duì)象放到一個(gè)自動(dòng)釋放池中,當(dāng)自動(dòng)釋放池被銷毀時(shí),會(huì)對(duì)池子里面的所有對(duì)象做一次release操作
- 使用autorelease有什么好處呢
不用再關(guān)心對(duì)象釋放的時(shí)間
不用再關(guān)心什么時(shí)候調(diào)用release
- autorelease的原理實(shí)質(zhì)上是什么?
autorelease實(shí)際上只是把對(duì)release的調(diào)用延遲了,對(duì)于每一個(gè)autorelease,系統(tǒng)只是把該對(duì)象放入了當(dāng)前的autorelease pool中,當(dāng)該pool被釋放時(shí),該pool中的所有對(duì)象會(huì)被調(diào)用release。
2.8 auto、const和volatile
待補(bǔ)充...
2.9 alloc, init, dealloc, release,new ,retain
簡單地說,alloc分配內(nèi)存空間,init對(duì)該對(duì)象進(jìn)行初始化,這些方法若沒有重寫方法則默認(rèn)繼承自父類。
通常來講,new = alloc + init
Objective-C的對(duì)象在使用完成之后不會(huì)自動(dòng)銷毀,需要執(zhí)行dealloc來釋放空間(銷毀),否則內(nèi)存泄露。下面是一個(gè)簡單的例子。
ClassA *obj1 = [[ClassA alloc] init];
[obj1 hello]; //輸出hello
[obj1 dealloc];
Objective-C采用了引用計(jì)數(shù)(ref count或者retain count)。對(duì)象的內(nèi)部保存一個(gè)數(shù)字,表示被引用的次數(shù)。例如,某個(gè)對(duì)象被兩個(gè)指針?biāo)赶颍ㄒ茫┠敲此膔etain count為2。需要銷毀對(duì)象的時(shí)候,不直接調(diào)用dealloc,而是調(diào)用release。release會(huì)讓retain count減1,只有retain count等于0,系統(tǒng)才會(huì)調(diào)用dealloc真正銷毀這個(gè)對(duì)象。
Objective-C指針賦值時(shí),retain count不會(huì)自動(dòng)增加,需要手動(dòng)retain。
ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj2 retain]; //retain count = 2
[obj1 hello]; //輸出hello
[obj1 release]; //retain count = 2 – 1 = 1
[obj2 hello]; //輸出hello
[obj2 release]; //retain count = 0,對(duì)象被銷毀
Objective-C 內(nèi)存管理——你需要知道的一切
Objective-C內(nèi)存管理教程和原理剖析(一)
2.10 文件操作
待補(bǔ)充...
2.11 分類和協(xié)議
待補(bǔ)充...
2.12 NSString, NSNumber,NSArray,NSDictionary, NSSet 類的主要方法
待補(bǔ)充...
2.13 Cocoa
Cocoa是一種支持應(yīng)用程序提供豐富用戶體驗(yàn)的框架,它實(shí)際上由兩個(gè)框架組成:
- Foundation框架
- Application Kit (或AppKit)框架 : 提供與窗口、按鈕、列表等相關(guān)的類。
- core Data
補(bǔ)充:
內(nèi)核以設(shè)備驅(qū)動(dòng)程序的形式提供與硬件的底層通信。它負(fù)責(zé)管理系統(tǒng)資源,包括調(diào)度要執(zhí)行的程序、管理內(nèi)存和電源,以及執(zhí)行基本的I/O操作。
核心服務(wù)提供的支持比它上面層次更加底層或更加“核心”。例如,這里提供對(duì)集合、網(wǎng)絡(luò)、 調(diào)試、文件管理、文件夾、內(nèi)存管理、線程、時(shí)間和電源的管理。
應(yīng)用程序服務(wù)層包含對(duì)打印和圖形呈現(xiàn)的支持,包括Quartz、OpenGL和Quicktime。
Cocoa層直接位于應(yīng)用程序?qū)又隆U鐖D所示,Cocoa包括Foundation禾口AppKit框架0 Foundation框架提供的類用于處理集合、字符串、內(nèi)存管理、文件系統(tǒng)‘存檔等。AppKit框架提供的類用于管理視圖、窗口、文檔和讓Mac OS X聞名于世的多信息用戶界面。
Cocoa框架用于Mac OS X桌面與筆記本電腦的應(yīng)用程序開發(fā),而Cocoa Touch框架用于 iPhone與ipod Touch的應(yīng)用程序開發(fā)。
Cocoa和Cocoa Touch都有Foundation框架。然而在Cocoa Touch下,UIKit代替了 AppKit框架,以便為很多相同類型的對(duì)象提供支持,比如窗口、視圖、按鈕、文本域等。另外,Cocoa Touch還提供使用加速器(它與GPS和WiFi信號(hào)一樣都能跟綜你的位置)的類和觸摸式界面, 并且去掉了不需要的類,比如支持打印的類。
4.
前文也提到,本文提到的每一個(gè)點(diǎn)都可以單獨(dú)行文,這里只是做一個(gè)淺顯的介紹,后期會(huì)結(jié)合示例代碼做一些更加深入探討。
歡迎指正批評(píng)與交流,本博客將長期更新維護(hù),如果讀完覺得有一定幫助可以點(diǎn)一個(gè)喜歡支持一下~
本文首發(fā)于簡書: http://www.lxweimin.com/p/13580d6d6d2a
未完待續(xù)...