第一講 OC簡介及基本語法
Objective-C簡稱OC是在C語言的基礎上,增加了一層最小的面向對象語法,完全兼容C語言,也就是可以在OC代碼中混入C語言代碼,甚至是C++代碼。可以使用OC開發Mac OS X平台和IOS平台的應用程序。簡單的介紹了一下OC,下面我們來看看OC的基本語法,學習OC之前我們先學習了C語言,因為OC是在C語言的基礎上的一門開發語言,因此OC的很多基本語法跟使用方法跟C語言有類似的地方但是也有其獨特的地方。
1. 關鍵字
OC中的關鍵字基本上所有的都是以@開頭,但也有少數不是以@開頭的,下面是一些較常用的關鍵字:
@interface、@implementation、@end @public、@protected、@private、@selector @try、@catch、@throw、@finally @protocol、@optional、@required、@class @property、@synthesize、@dynamic self、super、id、_cmd、__block、__strong、__weak、
2. 字符串以@開頭
比如@"Hello"是OC中的字符串,而"Hello"則是C語言中的字符串
3. OC程序的開發過程
OC程序的開發跟C語言類似,從 .m源文件編譯成 .o目標文件再鏈接成 a.out可執行文件
4. 程序框架
OC程序的入口也是main函數
在編寫第一個OC程序時用到了OC的輸出函數NSLog,但調用NSLog需要包含Foundation框架,OC中一般使用#import <Foundation/Foundation.h>來包含Foundation框架,每個框架都有自己的主頭文件:即最主要的頭文件。主頭文件名字一般跟框架名稱一樣,包含了框架中的所有其他頭文件,Foundation框架的主頭文件名稱就是Foundation.h,只需要包含Foundation框架的主頭文件,就可以使用整個框架的東西。
其中#import的作用:跟C語言中#include一樣,用來拷貝某個文件的內容,#import可以自動防止文件內容被拷貝多次,也就意味着頭文件中不用加入相應的預處理指令。
#import <Foundation/Foundation.h>
//OC程序的入口:main函數
int main()
{
//printf("第一個OC程序\n");//OC完全兼容C語言程序
NSLog(@"第一個OC程序"); //NSLog輸出內容會自動換行
return 0;
}
5. NSLog與printf的區別
NSLog接收OC字符串作為參數,printf接收C語言字符串作為參數
NSLog輸出后會自動換行,printf輸出后不會自動換行
使用NSLog需要#import <Foundation/Foundation.h>
使用printf需要#include <stdio.h>
6. Foundation框架的作用
開發OC、iOS、Mac程序必備的框架
此框架中包含了很多常用的API(應用編程接口)
框架中包含了很多頭文件,若想使用整個框架的內容,包含它的主頭文件即可:#import <Foundation/Foundation.h>
7. BOOL的使用
BOOL類型的本質 typedef signed char BOOL;
BOOL類型的變量有2種取值:YES、NO
#define YES (BOOL)1
#define NO (BOOL)0
BOOL的輸出(當做整數來用)
NSLog(@"%d %d", YES, NO);
第二講 類和對象
OC是一門面向對象的開發語言,而C語言是面向過程的,因此在開發思想上要把面向過程和面向對象好好區分開來,體會其中的不同之處。面向過程關注的是解決問題需要哪些步驟,而面向對象關注的是解決問題需要哪些對象。
1. 類的設計
在C語言中完整的寫一個函數需要函數的聲明和定義(也就是實現),而OC中類似,完整的寫一個類需要類的聲明和實現
類的設計主要包括:類名,屬性和行為
設計類名注意點:
類名的第一個字母必須是大寫
不能有下划線
多個英文單詞,用駝峰標識
2. 方法(行為)的設計
OC中方法就是行為,主要包括方法名,參數,返回值(聲明和實現)方法不能放在大括號里面
注意點:只要是OC對象的方法,必須以減號 - 開頭,類方法以+開頭
OC方法中任何數據類型都必須要用()擴住
OC方法中的小括號():只有一個作用,用來擴住數據類型
3. 類的聲明跟實現
OC中類的聲明值得是用來聲明對象的屬性跟行為,聲明對象的屬性(實例變量或者叫成員變量) , 成員變量默認情況下會做一個初始化,所有成員變量默認都是0
聲明在@interface和@end之間進行,實現在@implementation和@end之間進行
下面我們來通過一個具體實例創建一個類並引出一些知識點跟注意點:
#import <Foundation/Foundation.h> // 因為使用了NSObject
@interface Car : NSObject // NSObject目的是:讓Car這個類具備創建對象的能力
{ @public // @public關鍵字,可以讓外部的指針間接訪問內部的成員變量
int wheels; // 輪胎個數
int speed; // 時速 xxkm/h // 大括號里面只能寫屬性不能寫行為
} - (void)run; // 跑這個方法
@end
//類的實現 用來實現@interface中聲明的方法
@implementation Car - (void)run { NSLog(@"車子跑起來了!"); // 實現聲明的方法
} @end
int main() { //[Car new];會創建出一個新對象,並且會返回新對象本身(新對象的地址) Car *p = [Car new]; // 定義了一個指針變量p,p將來指向的是Car類型的對象 Car *p2 = [Car new]; // [Car new]每次都會創建出一個新的對象
p->wheels = 4; // 給p所指向的wheels屬性賦值,類似於結構體 p->speed = 250; // 給p所指向的對象發送一條run消息,消息機制:給指針所指向的對象發送一條run消息
[p run]; [p2 run]; NSLog(@"車子有%d個輪子,時速為%dkm/h",p->wheels,p->speed); return 0; // 程序退出后會默認把內存回收
}
[Car new]在使用類創建對象之前,會將類加載進內存,類的內存里面只放方法列表,創建的每個對象內部默認有一個指針(isa指針),這個指針指向這個對象所對應的類,所有的對象共用相同的類里面的方法。
類的聲明跟實現常見錯誤:
只有類的聲明,沒有類的實現
漏了@end ,@interface和@implementation嵌套
兩個類的聲明嵌套
成員變量沒有寫在括號里面
方法的聲明寫在了大括號里面
語法細節:
成員變量不能在{}中進行初始化、不能被直接拿出去訪問
方法不能當做函數一樣調用
成員變量\方法不能用static等關鍵字修飾,別跟C語言混在一起(暫時忽略)
類的實現可用寫在main函數的后面,主要在聲明后面就行了
4. 方法跟函數的區別
方法:
對象方法都是以減號-開頭
對象方法的聲明必須寫在@interface和@end之間
對象方法的實現必須寫在@implementation和@end之間
對象方法只能由對象來調用
對象方法歸類\對象所有
函數
函數能寫在文件中的任意位置(@interface和@end之間除外),函數歸文件所有,函數可以定義在@implementation和@end之間,這個是沒有問題完全可以
函數調用不依賴於對象
函數內部不能直接通過成員變量名訪問某個對象的成員變量
5. 方法的聲明和實現
@interface JiSuanQi : NSObject
- (double)pi; // 方法名叫pi,不帶參數的方法
// OC方法中,一個參數對應一個冒號
// 方法名叫pingFang: ,要連上冒號,為了防止方法名的沖突,冒號也是方法名的一部分
- (int)pingFang:(int)num; // 帶一個參數的方法
// 方法名叫: sumWithNum1:andNum2:
- (int)sumWithNum1:(int)num1 andNum2:(int)num2; // 帶兩個參數的方法,可讀性好 冒號前面加一些描述信息,來描述后面的參數是干嘛用的
@end
因此注意在定義方法名時要注意一些規范,保證可讀性好,類似於 sumWithNum1:andNum2:這種的方法名。
6. 方法的練習
下面通過一個練習體會一下OC的方法的聲明跟實現,以及需要注意的地方,方法的命名需要格外注意:
// 設計一個方法,用來和其他車比較車速,返回車速的差距
#import <Foundation/Foundation.h>
@interface Car : NSObject // 類的聲明
{ @public
int speed; // 車速
} // 此處傳遞一個車進來比較速度,車是一個對象,OC中的對象都是指針類型的,數據類型為Car*
- (int)compareSpeedWithOther:(Car *)other; @end
@implementation Car // 類的實現
- (int)compareSpeedWithOther:(Car *)other { // speed當前這輛車的速度 // other->speed 是other傳進來比較的這輛車的速度 // 返回當前這輛車和other這輛車的速度差距
return speed - other->speed; } @end
int main() { Car *c1 = [Car new]; // 創建車對象c1
c1->speed = 300; // 給對象的speed屬性賦值
Car *c2 = [Car new]; // 創建對象c2
c2->speed = 280; int a = [c2 compareSpeedWithOther:c1]; // c2調用方法並傳入c1參數進行速度比較
NSLog(@"%d",a); // 打印速度差距
return 0; }
第三講 三大特性
第三講我們主要講OC的三大特性,OC是一門面向對象的語言,面向對象的開發語言一般共同的特點就是具有三大特性:封裝,繼承和多態。下面我們來學習一下OC的三大特性。
一、 封裝
封裝就是對類中的一些字段,方法進行保護,不被外界所訪問到,有一種權限的控制功能。
封裝的好處:過濾不合理的值,屏蔽內部的賦值過程,讓外界不必關注內部的細節。
1. set方法和get方法
set方法
作用:提供一個方法給外界設置成員變量值,可以在方法里面對參數進行相應過濾
命名規范:
(1)方法名必須以set開頭
(2)set后面跟上成員變量的名稱,成員變量的首字母必須大寫
(3)返回值一定是void
(4)一定要接收一個參數,而且參數類型跟成員變量類型一致
(5)形參的名稱不能跟成員變量名一樣
get方法
作用:返回對象內部的成員變量
命名規范:
(1)肯定有返回值,返回值類型肯定與成員變量類型一致
(2)方法名跟成員變量名一樣
(3)不需要接收任何參數
2. 成員變量的命名規范:一定要以下划線 "_" 開頭
作用:
讓成員變量和get方法的名稱區分開
可以跟局部變量區分開,一看到下划線開頭的變量,一般都是成員變量
3. 經典錯誤
#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
@implementation Person
@end
int main()
{
Person *p = [Person new];
// OC是在運行過程中才會檢測對象有沒有實現相應的方法
[p test];//實現中沒有test方法
return 0;
}
報錯:-[Person test]: unrecognized selector sent to instance 0x7fd2ea4097c0
給Person對象發送了一個不能識別的消息:test
4. 類方法和對象方法
(1)對象方法:
*減號 - 開頭
*只能由對象來調用
*對象方法中能訪問當前對象的成員變量(實例變量)
(2)類方法:
*加號 + 開頭
*只能由類(名)來調用
*類方法中不能訪問成員變量(實例變量)
(3)類方法的好處和使用場合:
*不依賴於對象,執行效率高
*能用類方法盡量用類方法
*場合:當方法內部不需要使用到成員變量時,就可以改為類方法
*可以允許類方法和對象方法同名
5. self關鍵字
self關鍵字是個指針,self指向方法調用者,代表着當前對象,當成員變量和局部變量同名時,采取就近原則,訪問的是局部變量,用self訪問成員變量,區分同名的局部變量
self用途:
(1)誰調用了當前方法,self就代表誰,(指向了當前對象-方法調用者)
* self出現在對象方法中,self就代表對象
* self出現在類方法中,self就代表類
(2)在對象方法中利用“self->成員變量名”訪問當前對象內部的成員變量
(3)[self 方法名] 調用當前對象的某一個方法,可以調用其他對象方法或者類方法
常見錯誤:
*低級錯誤:用self去調用函數
*類方法中用self調用對象方法,對象方法中用self調用類方法
*self死循環
二、 繼承
繼承是類中的一個重要的特性,他的出現使得我們沒必要別寫重復的代碼,可重用性很高。繼承的一些專業術語:父類\超類:superclass 子類:subclass\subclasses
1.繼承的好處:
*抽取重復代碼
*建立了類之間的關系
*子類擁有父類中的所有成員變量和方法
*注意點:基本上所有類的根類是NSObject
2. 方法的重寫
重寫:子類重新實現父類中的某個方法,覆蓋父類以前的做法
注意:
*父類必須聲明在子類的前面,實現可以放在子類的后面
*子類不能擁有和父類相同的成員變量
*調用某個方法時,優先去當前類中找,如果找不到,去父類中找
*壞處:耦合性太強:類之間的關系太緊密了,當某個父類不見了,子類就用不了
3. 繼承的使用場合
當兩個類擁有相同屬性和方法的時候,就可以將相同的東西抽取到一個父類中
當A類完全擁有B類中的部分屬性和方法時,可以考慮讓B類繼承A類
// 動物類的聲明
@interface Animal : NSObject // 基本上所有的類根類是NSObject
{ double _weight; // 體重成員變量
} - (void)setWeight:(double)weight; // set方法
- (double)weight; // get方法
@end
@implementation Animal // 方法的實現,這里主要是get和set方法實現
- (void)setWeight:(double)weight { _weight = weight; } - (double)weight { return _weight; } @end
@interface Dog : Animal // Dog類繼承了動物類
{ double _height; // Dog類完全擁有Animal類的成員變量和方法,並有子類自己的成員變量
} @end
@implementation Dog @end
4. 繼承和組合
當某個類想擁有另一個類當中的東西,考慮兩種方式,一種是繼承一種是組合
繼承:xx 是 xxx 代表什么什么(子類)是什么什么(父類)
組合:xxx 擁有 xxx
類A
{
int _age;
int _no;
}
類B
{
A *_a; // B里面擁有A,這個是組合
int _weight;
}
在實際的使用中,要注意邏輯和設計,區分好繼承和組合的使用。
5. super關鍵字
super的作用和使用場合:
*直接調用父類中的某個方法
*super處在對象方法中,那么就會調用父類的對象方法
*super處在類方法中,那么就會調用父類的類方法
*使用場合:子類重寫父類的方法時想保留父類的一些行為
三、 多態
多態指的是某一類事物的多種形態,OC對象具有多態性
多態的體現:Person *p = [Student new]; p->age = 10; [p walk];
1. 多態的使用注意
*沒有繼承就沒有多態
*代碼的體現:父類類型的指針指向子類對象
*好處:如果函數\方法參數中使用的是父類類型,可以傳入父類,子類對象
*局限性:父類類型的變量 不能 直接調用子類特有的方法。必須強制轉為子類類型的變量后,才能直接調用子類特有的方法。
2. 代碼中的注意點
Animal *a = [Dog new];
//[a run];run方法為Dog獨有,不能直接訪問
Dog *d = (Dog *)a;//強制轉換為Dog *類型才能調用run方法
[d run];
本章學習總結:
本章主要學習了面向對象的一門開發語言Objective-C。本章第一講主要學習了OC的一些基本語法,主要包括關鍵字,字符串,程序框架,注意OC的字符串以@開頭,要注意NSLog和C語言printf的區別。本章第二講主要學習了類和對象,在OC中,類和方法的設計有很多規范和需要注意的地方,養成一種良好的編程習慣是很重要的,這一講要注意類的聲明跟實現的一些注意點,要區分OC的方法跟函數,了解二者分別有什么作用以及使用場合,要注意在聲明和實現方法時帶參數的情況,注意命名的規范(要有意義而且通順連貫)。本章第三講主要學習了OC的三大特性,封裝,繼承和多態。封裝主要講的是set和get方法,注意set和get方法的命名規范和使用注意,有時根據需求要求只讀的話可以很好的利用set和get方法。還學習了類方法和對象方法,要注意二者的使用場合以及調用情況,在一些實際情況中巧妙的互相調用會讓程序精簡很多。此外還學習了self關鍵字,誰調用了當前方法,self就代表誰,注意避免一些self的常見錯誤。第三講的第二大內容是繼承,要了解繼承的好處以及使用場合,繼承中子類可以重寫父類方法,要了解重寫的使用注意,特別需要注意繼承和組合,二者有什么不同,在實際應用開發中要區分開來,此外還學習了super關鍵字,了解了其作用和使用場合。第三部分學習了OC的第三大特性多態,注意多態是基於繼承的,要了解多態的好處和它的局限性。