1. 第一個OC程序
框架(Framework)
和C的Hello不同:
1) 擴展名(后綴名)為.m
2) 使用Foundation框架
3) 使用#import導入頭文件:
#import <Foundation/Foundation.h>
#import 會自動處理頭文件重復導入問題。
4) 使用NSLog函數輸出日志信息
5) 使用clang編譯器,並且連接Foundation框架:
clang -framework Foundation xxxx.m (編譯時要注意指定Foundation框架)
在Unix/Linux/蘋果系統下可執行文件的后綴名可以是任何文件,可以是任意后綴名或沒有后綴。
如,a.out==》a.txt (都可以執行!)
總結一個文件擴展名(后綴名):
.c ===》C語言源程序文件
.m ===》OC
.cpp ===》C++
.cc ===》某些Unix系統的C++
.mm ===》Objective C++
.s ===》匯編
.i ===》經過預處理后的源程序
.o ===》編譯還沒連接的二進制文件
.o、.out (c、c++、Objective-C語言編譯后生成的文件)
.a ===》靜態庫文件
.so ===》Unix/Linux下的動態庫文件
.dylib ===》Mac OS/iOS 動態庫文件
2. 編譯器
C語言標准編譯器是: gcc OC早期的編譯器使用gcc (gcc不是蘋果公司的)
OC現在的編譯器:
clang (蘋果公司自己開發的,獨立的編譯器)
LLVM(小的一個語言虛擬機)集成在Xcode中【特點:隨時編譯,方便Xcode自動隨時檢查語法錯誤】
C語言編譯器:gcc
OC語言的編譯器:clang (由於OC語言兼容所有的C語言語法,所以也可以用clang編譯器編譯C程序)
3. Xcode寫OC程序

只需要在C語言字符串前面加上@符號, 系統就會自動將C語言字符串轉換為OC字符串。
4. 面向對象編程
4.0 定義
面向對象編程: 直接使用解決現實生活中問題的辦法來解決計算機問題。
4.1 對象
Anything is Object 萬物皆對象,現實中,對象是一種客觀上的存在。
程序中對象是一片內存空間,這片空間中存放表示對象的數據。
對象:類這種類型的變量
對象中有:
有什么 屬性
能干什么 方法
4.1.1 系統中的對象:
一個對象有可能由若干個小對象組成
對象職能單一,一個對象只做自己該做的事
對象們各司其職,各盡所能
對象與對象之間有一定聯系,之間用發消息的方式進行工作
這些對象構建成一個運行的系統。
4.1.2 %@打印一個對象(實例對象/類對象):
只要利用%@打印某個對象, 系統內部默認就會調用父類的description方法
打印對象的本質是:打印description方法中的字符串!

4.1.3 匿名對象
有名字的對象:只要用一個指針保存了某個對象的地址, 我們就可以稱這個指針為某個對象(稱p為TRPerson的對象)
| TRPerson *p = [TRPerson new]; p.name = @"張三"; p.age = 22; [p show]; |
沒有名字的對象
無論有沒有名字, 只要調用new方法都會返回對象的地址
每次new都會新開辟一塊存儲空間
| [TRPerson new].name = @"張三"; [TRPerson new].age = 22; [[TRPerson new] show]; |
4.2 類
類是類型的意思,現實中是一種主觀的認識
在計算機中,類是自定義類型,是創建對象的模型(模板)
類就是用於描述對象的共性特征,主要用於描述對象的屬性和行為
類中有:屬性的定義和方法的定義

4.2.1 類的本質:類其實也是一個對象(類對象),這個對象會在這個類第一次被使用的時候創建。
- 只要有了類對象, 將來就可以通過類對象來創建實例對象
- 實例對象中有一個isa指針, 指向創建自己的類對象
- 類對象中保存了當前對象所有的對象方法
- 當給一個實例對象發送消息的時候,會根據實例對象中的isa指針去對應的類對象中查找
類對象代表類,class類型,對象方法屬於類對象
如果消息的接收者是類名,則類名代表類對象
所有類的實例都由類對象生成,類對象會把實例的isa的值修改成自己的地址,每個實例的isa都指向該實例的類對象。
4.2.2 如何獲取類對象?
Class c = [類名/實例對象 class];

類對象的應用場景:
- 用於創建實例對象
TRPerson *p3 = [c1 new];
TRPerson *p4 = [[c3 alloc]init];
- 用於調用類方法
[c3 method];//等價於[TRPerson method];
4.2.3 類的啟動過程(系統內部自動調用的兩個方法:load方法 和 initialize方法)
- load方法:程序一啟動就會調用
- 只要程序啟動就會將所有類的代碼加載到內存中, 放到代碼區
- load方法會在當前類被加載到內存的時候調用, 有且僅會調用一次
- 如果存在繼承關系, 會先調用父類的load方法, 再調用子類的load方法
- initialize方法:
- 當類第一次被使用的時候就會調用(創建類對象的時候)
- initialize方法在整個程序的運行過程中只會被調用一次, 無論你使用多少次這個類都只會調用一次
- initialize用於對某一個類進行一次性的初始化
- initialize和load一樣, 如果存在繼承關系, 會先調用父類的initialize再調用子類的initialize

4.3 在OC中定義類和創建對象
4.3.1 定義一個類
分兩部分:接口部分,實現部分
1、接口部分
聲明類的目的: 告訴系統我們這個類中有哪些屬性和方法
| @interface 類名 : 父類名 //類開始 //定義屬性 //聲明方法(相當於聲明函數) @end //類結束 |
2. 實現部分
| @implementation 類名 //方法的定義(相當於定義函數) @end |
4.3.2 創建對象
創建對象使用alloc,創建好后用一個指針將對象的地址保存起來,以便后面使用。我們把保存對象地址的指針叫引用(Reference)
類名 *引用名 = [類名 alloc];
通過類創建對象
1) 開辟存儲空間,通過alloc(new)方法創建對象會在堆內存中開辟一塊存儲空間
2) 初始化所有屬性
3) 返回指針地址
創建對象的時候返回的地址其實就是類的第0個屬性的地址
但是需要注意的是: 類的第0個屬性並不是我們編寫的第一個屬性,而是一個叫做isa的屬性(isa是一個指針, 占8個字節)
isa屬性是系統內部自動幫我們添加的,當你創建一個對象的時候,系統自動生成isa屬性
isa是一個指針,占8個字節
isa的作用:會指向創建這個類的那個類

其實類也是一個對象,也就意味着MyClass也是一個對象(類對象)
平時我們所說的創建對象其實就是通過一個 類對象 來創建一個 新的實例對象
類對象是系統自動幫我們創建的,里面保存了當前對象的所有方法
而實例對象是程序自己手動通過alloc(new)來創建的,而實例對象中有一個isa指針就指向了創建它的那個類對象
4.3.2 對象的存儲細節
類創建對象,每個對象在內存中都占據一定的存儲空間,每個對象都有一份屬於自己的單獨的成員變量,所有的對象共用類的成員方法。
方法在整個內存中只有一份,類本身在內存中占據一份存儲空間。
| OC中對象創建 TRPerson *p = [TRPerson new];// 等價於 TRPerson *p = [[TRPerson alloc]init]; 怎么理解這句話: 理解1:定義了一個TRPerson類型的指針變量,指針變量指向新申請的內存空間 理解2:用TRPerson類實例化了(創建了)一個實例對象,對象的名稱是p 這里的new做了三件事:
|



4.4 定義屬性
1) 在接口部分定義屬性:
| @property int x; @property double y; @property NSString *name; //對象只能通過引用訪問,所以要加*(指針類型) //NSString是OC中的字符串類型,*name代表一個指針,OC語言中字符串類型是一個對象,只能用一個指針來保存一個對象的地址,而不能直接保存一個對象;所有的對象都一樣,不能直接用變量來保存對象,只能用一個指針來保存對象的地址!MyClass *obj = [MyClass alloc]; @property NSString *name;//姓名 @property int age;//年齡 @property BOOL gender;//性別 @property double salary;//工資 |
2) 訪問對象中的屬性:
引用.屬性 = 值;
NSLog(@"%d", 引用.屬性);
// %@打印字符串對象
NSLog(@“姓名: %@,性別: %@“, self.name,self.gender?@"男":@"女");
4.5 聲明和定義方法
1) 在接口部分聲明方法
- (返回值類型)方法名;
- (返回值類型)方法名:參數表;
2) 在實現部分定義方法
- (返回值類型)方法名 {
//寫具體的實現代碼
}
| //在OC中方法名會被分解成若干個部分分散在多個參數的前面。 //此方法的方法名是:"setName: age: gender: salary:" - (void)setName:(NSString *)name age:(int)age gender:(BOOL)gender salary:(double)salary; |
3) 調用
通過對象來調用方法
[引用 消息]; //向引用指向的對象發消息(消息的名字應該是方法名),如果引用指向的對象有和這個消息名字相同的方法,就會自動調用此方法。如果沒有這個方法,程序崩潰。
4.6 實際開發中類的寫法
實際開發中,類的接口部分和實現部分是分開的,接口部分放在頭文件中,實現部分放在.m文件中
類名加前綴,防止命名沖突(蘋果官方的前綴是兩個字母,為了不與官方的重復,開發者一般用3個字母的前綴)
5. 方法(Method)
5.1 概念
本質是函數,在OC中寫法和函數不同。
在方法中可以訪問屬性。
當一個對象收到一個消息時,調用對應的方法。
5.2 分類:
實例方法(instance method): -
類方法(class method): +
在.h中聲明的所有方法作用域都是public類型,不能更改。
5.3 實例方法(instance method)
實例(instance)指的是對象。一個類的對象可以被稱為這個類的一個實例。
必須通過對象來調用的方法叫實例方法。具體的來說是通過指向對象的引用來調用。
5.4 實例方法的參數
無參、一個參數、多個參數
5.5 方法的返回值
和函數一樣
輸出一個對象詳細信息的兩種方法:

5.6 函數和方法的區別
1) 函數屬於整個文件, 方法屬於某一個類,方法如果離開類就不行
2) 函數可以直接調用, 方法必須用對象或者類來調用
3) 不能把函數當做方法來調用, 也不能把方法當做函數來調用
6. 成員變量、實例變量(instance variable)
6.1 概念
實例就是對象
每個對象(實例)都有一份自己獨特的數據和別的對象不同,這些獨特的數據會保存在對象的一些特殊變量中,這些變量就是實例變量。
每一個實例都有一份獨特的實例變量。實例變量用來記錄和保存數據!
有人也叫成員變量
C++ member variable 成員變量
member function 成員函數
6.2 定義成員變量(在OC里也叫實例變量)
//在大括號中聲明的變量都為成員變量
{
UIButton *_button;
int age;
id data;
}
成員變量的常用作用域有3種:
- @public 全局都可以訪問
- @protected 只能在類內部和子類中訪問
- @private 只能在類內部訪問
6.3 實例變量和屬性的關系
屬性的本質:兩方法(setter和getter)+ 實例變量
當我們在類中定義一個屬性時,編譯器會生成以下內容:
1) 保存屬性值的實例變量,名字為"_屬性名"
2) 修改實例變量值的setter方法,名字為"set屬性名",並且屬性名的首字母大寫
3) 讀取實例變量值的getter方法,名字為"屬性名"

比如,定義的屬性名叫name,生成的實例變量名為"_name",生成的setter方法的名字為:"setName:",生成的getter方法的名字為:"name"
怎么訪問實例變量?
在實例方法內(類內部),可以直接訪問實例變量。(如:_age=22;)
在實例方法外(類外部),用以下兩種方式訪問:
1)用->直接進行訪問;
如:f->_name = @“張三”; f->_age = 20; (一般不用!)
如果使用,要用@public公開實例變量(實例變量默認是受保護的:@protect),才能用->訪問
2)用方法間接訪問(setter/getter),屬性是訪問實例變量的一種方式。
(setter方法可以給實例變量賦值,getter方法可以獲取實例變量的值。)
6.4 實際開發中的經驗:
一般情況下,很少會定義實例變量,而會大量的定義屬性。
在頭文件中,盡量不要定義實例變量,而是定義屬性。
OC中的實例變量相當於java中的成員變量,OC中經常用實例變量來存數據。
有時候我們會在.m文件中定義實例變量,保存一些私有的數據。也就是說在implementation中定義。
.h文件中的是公開的,.m文件是私有的:
在.h文件中定義的屬性(實例變量)是公開的,在.m文件中定義的屬性(實例變量)是私有的。
在.h文件中聲明和在.m文件中實現的方法是公開的,只在.m文件中實現,未在.h文件聲明的方法是私有的。
