Objective-C 基礎核心文法 - 總結,objective-c文法
一、點文法本質
- “點文法”本質是“方法調用”
- 當使用“點文法”時,編譯器會自動延伸稱相應的方法
1 //方法調用2 Student *stu = [[Student alloc] init]; 3 [stu setAge:10]; 4 int age = [stu age];5 //-----------------------------我是華麗分割線-----------------------------6 //點文法 7 stu.age = 10; 8 int age = stu.age;
二、成員變數的範圍
- @public : 在任何地方都能直接存取對象的成員變數
- @private : 只能在當前類的對象方法中直接存取 ( @implementation 中預設是 @private )
- @protected : 可以在當前類及其字累的對象方法中直接存取 (預設就是 @protected )
- @package : 只要處在同一個架構中,就能直接存取對象的成員變數
- @interface 和 @implementation 中不能聲明同名的成員變數
- 沒有 @interface ,只有 @implementation ,也可以開發同一個類
三、@property 和 @synthesize 、setter 和 getter 及使用細節
- @property 用在 @interface 中,用來自動產生 setter 和 getter 的聲明
- @synthesize 永在 @implementation 中,用來產生 setter 和 getter 的實現
- @synthesize 細節:1> @synthesize age = _age;(setter 和 getter 實現中會訪問成員變數 _age,如果成員變數 _age 不存在,就會自動產生一個 @private 的成員變數 _age )
- 2> @synthesize age;(setter 和 getter 實現中會訪問成員變數 age,如果成員變數 age 不存在,就會自動產生一個 @private 的成員變數 age)
- 3> 若手動實現了 setter 方法,編譯器就只會自動產生 getter 方法
- 自從 Xcode4.4 後,@property 就獨攬了 @synthesize 的功能。也就是說,@property 可以同時產生 setter 和 getter 的聲明和實現。
- 預設情況下,setter 和 getter 方法中的實現,會訪問底線 _ 開頭的成員變數
1 //--[interface.h]---Xcode4.2之前的文法---------------我是華麗分割線-------- 2 @property int age; //@property 3 //--[interface.h]--------️等價於️-------- 4 - (void)setAge; 5 - (int)age; 6 7 //--[implementation.m]-------------------------------我是華麗分割線-------- 8 @synthesize int age = _age; //@synthesize 9 //--[implementation.m]---️等價於️--------10 - (void)setAge {11 _age = age;12 }13 - (int)age {14 return _age;15 }16 //--[implementation.m]-------------------------------我是華麗分割線--------17 @synthesize int age; //@synthesize18 //--[implementation.m]---️等價於️--------19 - (void)setAge {20 _age = age;21 }22 - (int)age {23 return age;24 }25 26 //--[interface.h]---Xcode4.4之後有了以下新文法-------我是華麗分割線-------27 @property int age; //@property28 //--[interface.h]---------️等價於️-------29 @interface Student:NSObject{30 int _age;31 }32 - (void)setAge;33 - (int)age; 34 //--[implementation.m]---------------------35 - (void)setAge {36 _age = age;37 }38 - (int)age {39 return _age;40 }
四、id
- 是萬能指標,能指向任何對象,相當於 NSObject * , id 後面不要加上*
- 調用一個不存在的方法,編譯器會馬上報錯
- id 是一個結構體,OC 對象本身是一個結構體
1 typedef struct objc_object {2 Class isa; //每個對象都有一個isa,且isa始終指向當前類本身3 } *id; // id 定義為一個結構指標
五、構造方法(基本概念、重寫 init 方法、init 方法的執行過程、自訂)
- 完整地建立一個可用的對象:1> 分配儲存空間 +alloc,2> 初始化 - init (+ new 方法連續完成 1>、2> 步驟)
- 基本概念:用來初始化對象的方法,是一個對象方法,- 號開頭,init 方法就是構造方法
- 重寫 init 方法:一定要調用回 super 的 init 方法。重寫目的:為了讓對象建立出來,就使成員變數具有固定的值
- 1 //----Student.m-------------
- 2 - (id)init {
- 3 if (self = [super init]) //調用回super的init方法,返回對象self,即isa為Student對象
- 4 { //初始化成功
- 5 _age = 10;
- 6 }
- 7 return self;
- 8 }
1 //------NSObject------------2 - (id)init {3 isa = [self class];4 return slef;5 }
- init 方法的執行過程:先初始化父類,再初始化子類。
- 自訂:規範:1>一定是對象方法,一定以 - 開頭,2>傳回值一般為 id 類型,3>方法名一般以 init 開頭
- 初始化的好習慣:初始化成員變數在其所在類實現中進行(優點:去耦合。即當父類改變成員變數名稱,就不用改子類的代碼)
六、更改 Xcode 模版(main.m 、注釋)
- main.m:如 Mac Application的終端項目:進入/Users/jackieyi/Library/Developer/Xcode/Templates/Project Templates/Application/Command Line Tool.xctemplate/Templateinfo.plist,按需要修改這個plist檔案即可。
- 注釋:如 Mac Application的終端項目:進入/Users/JackieYip/Library/Deverloper/Xcode/Templates/File Templates/Cocoa/Objective-C class.xctemplate/NSObject/___FILEBASENAME___.m,或按需要選對應檔案進行修改即可。
七、分類(基本使用、使用注意、給 NSString 增加類方法及擴充對象方法)
- 作用:在不改變原來類內容的基礎上,可以為類增加一些方法
- 注意:1> 只能增加方法,無法增加成員變數,但在分類的方法中可以訪問原類的成員變數
- 2> 分類可以重新實現原來類中的方法,但是會覆蓋原來的方法,會導致原來的方法無法再使用
- 3> 方法調用的優先順序:高|分類(最後參與編譯的分類優先)->原類->父類|低
- 編譯順序的查看:項目-TARGETS - Builde Phases - Complie Sources,由上往下順序編譯(全為 .m 檔案,.h 檔案不參與編譯)
八、類的深入研究(本質、類對象的使用、類的載入和初始化)
- 本質:我們知道:每個對象都有類型。而類本身也是一個對象,簡稱“類對象”,“類對象”的類型為 Class 類型(Class包含*)。
- 由“類對象”建立的對象稱為“執行個體對象”。
- “類對象”預設只有一份被載入到記憶體中,“執行個體對象”可以有多份被載入到記憶體中(不同的“執行個體對象”,其isa始終指向其同一“類對象”)。
1 Student *stu = [[Student alloc] init];2 Class stu1 = [stu class]; //利用Class建立Student類對象,[stu class]是擷取記憶體中的類對象3 Class stu2 = [Student class]; //stu1的地址等於stu2的地址,都是stu的地址
- 使用:“類對象”可以調用“類方法”
- 載入:屬於運行時機制。當程式啟動的時候,就會載入一次項目中所有的類和分類(無論有無使用類)。類載入完畢之後就會調用 + load 方法,只調用一次(先載入 父類 ,再載入 子類,最後載入 分類 )
1 + (void)load {2 //程式一啟動,所有的類都調用這個載入方法3 }
- 初始化:屬於運行時機制。當第一次使用類的時候,就會調用一次 + initialize 方法(先初始化 父類 ,再初始化 子類 ,如果有 分類 ,只會初始化 分類 )
1 + (void)initialize {2 //第一次使用類的時候([[類 alloc]init]),就會調用一次這個方法。我們可以在這裡監聽類何時被使用3 }
九、description 方法
- 預設情況下,利用 NSLog 和 %@ 輸出 類對象 的時候,結果是:<類名:記憶體位址>
- 每次調用 NSLog (@"%@",“執行個體對象”) 的時候,會預設調用“執行個體對象”的 - description 方法, - description 方法的傳回值為 (NSString *),預設返回的是"類名+記憶體位址"
- 可以重寫 - description 方法輸出所有 成員變數
1 - (NSSting *)description {2 // NSLog(@"%@",self); //這行代碼會引發死迴圈3 return [NSString stringWithFormat:@"age=%d, name=%@", _age, _name];4 }
- 每次調用 NSLog (@"%@",“類對象”) 的時候,會預設調用“類對象”的 + description 方法,+ description 方法的傳回值為 (NSString *),預設返回的是"類名"
- + description 也可以被重寫
十、NSLog 輸出補充
1 int main() {2 NSLog(@"%d",__LINE__); //輸出當前行號(即 2 )3 //NSLog(@"%s",__FILE__); //NSLog輸出 C 語言字串的時候,不能有中文4 printf(@"%s\n",__FILE__); //輸出源檔案的名稱(含路徑)5 NSLog(@"%s\n",__func__); //輸出當前函數名(即 main )6 }
十一、SEL (基本用法及其他使用)
- 屬於運行時機制。一個 SEL 代表一個方法,對應方法地址
- 對象調用 方法 時:1> 先把 方法 封裝成 SEL 類型的資料,2> 根據 SEL 資料找到對應的 方法地址,3> 根據 方法地址 調用對應的方法
1 int main() {2 Student *stu = [[Student alloc] init];3 [stu test]; 4 [stu performSelector:@selector(test)]; //間接調用test方法,@selector(test)就是一個SEL類型5 [stu performSelector:@selector(test1:) withObject:@"123"]; //間接調用test:方法,@selector(test:)就是一個SEL類型6 }
1 NSString *name = @"test";2 SEL s = NSSelectorFromSrting(name) //將test方法封裝成SEL資料3 [stu performSelector:s];
- 每個方法裡面都有一個 SEL 類型資料的_cmd,_cmd代表當前方法。給對象傳遞訊息,其實就是給對象傳遞 SEL 資料。SEL 不能直接列印,只能轉成字串進行列印。
1 - (void)test {2 NSString *str = NSStingWithSelector(_cmd);3 NSLog(@"調用了test方法---%@",str); //顯示:調用了test方法---test4 }