#### 構造方法
出于初始化類中的成員變量的需要, 可以提供一個方法用于此目的,?
這個方法就叫構造方法或構造方法(Constructor)。?
與C++和Java不同, Objective-C命名是沒有限制的, 并且有返回值本身類型指針。
以音樂類舉例:
Song.h文件
~~~
@interface?Song?:?NSObject?{??
NSString?*title;??
NSString?*artist;??
long?int?duration;??
}??
//操作方法??
-?(void)start;??
-?(void)stop;??
-?(void)seek:(long?int)time;??
//訪問成員變量方法??
@property(nonatomic,retain)?NSString?*title;??
@property(nonatomic,retain)?NSString?*artist;??
@property(readwrite)?long?int?duration;??
//構造方法??
-(Song*)?initWithTitle:?(NSString?*)?newTitle??
andArtist:?(NSString?*)?newArtist??
andDuration:(?long?int?)?newDuration;??
@end??
~~~
在Song類的定義中添加了一個方法, 它一般用 init開頭命名,?
它的返回值很特殊, 是返回值本身類型指針。 并且有返回值本身類型指針。
實現代碼如下:
~~~
@implementation?Song??
@synthesize?title;??
@synthesize?artist;??
@synthesize?duration;??
//構造方法??
-(Song*)?initWithTitle:?(NSString?*)?newTitle??
andArtist:?(NSString?*)?newArtist??
andDuration:(long?int)?newDuration?{??
self?=?[super?init];??
if?(?self?)?{??
self.title?=?newTitle;??
self.artist?=?newArtist;??
self.duration?=?newDuration;??
}??
return?self;??
}??
...?...??
@end??
~~~
#### 代碼說明:
1、頭文件引用規則
導入的文件要用一對引號引起來,而不是中的“"字符。雙引號適用于本地文件(你自己創建的文件),而不是系統文件,這樣就通知編譯器在哪里能夠找到指定的文件。
2、構造方法的實現代碼幾乎就是模式代碼, 基本上都是如下寫法:?
~~~
-(id)init??
{??
????self?=?[super?init];??
????if?(self)?{??
????????//初始化代碼??
????}??
????return?self;??
}??
~~~
其中使用 [super init] 來調用父類默認構造方法。?
對象的初始化的常見的編程習慣是類中所有的初始化方法都以init開頭。
如果希望在類對象初始化時做一些事情。可以通過覆寫init方法達到這個目的。
這個方法返回的實例對象指派給另一新個關鍵詞: self。?
self很像 C++ 和 Java 的 this。?
3、還有if ( self ) 跟 ( self != nil ) 一樣, 是為了確定調用父類構造方法成功返回了一個新對象。?
當初始化變量以后, 用返回self 的方式來獲得自己的地址。?
4、父類默認構造方法 -(id) init。?
技術上來說, Objective-C中的構造方法就是一個 "init" 開頭的方法,?
而不像 C++ 與Java 有特殊的結構。
5、必須將父類init方法的執行結果賦值給self,
因為初始化過程改變了對象在內存中的位置(意味著引用將要改變)。
如果父類的初始化過程成功,返回的值是非空的,通過if語句可以驗證,
注釋說明可以在這個代碼塊的位置放入自定義的初始化代碼。
通常可以在這個位置創建并初始化實例變量。
注意,
init被定義為返回id類型,這是編寫可能會被繼承的類init方法的一般規則。
程序開始執行時,它向所有的類發送initialize調用方法。
如果存在一個類及相關的子類,則父類首先得到這條消息。
該消息只向每個類發送一次,并且向該類發送其它任何消息之前,保證向其發送初始化消息。
實例成員變量作用域限定符
在接口中聲明的實例變量可以通過子類進行繼承。
可以把下面指令放在實例變量之前,以便更精確地控制其作用域:
即便從封裝的角度出發, 實例成員變量應該定義為@private,?
但作為一種面向對象的語言, Objective-C支持@public、 @private和@protected作用域限定。?
如果一個實例變量沒有任何的作用域限定的話, 那么缺省就是@protected。

?@public作用域限定的實例變量,可以被本類、其他類或者模塊中定義的方法直接訪問,即可在任何情況下訪問;?
?@private作用域限定的實例變量,只能在這個類里面才可以訪問;
在實現部分定義的實例變量默認屬于這種作用域。
?@protected作用域限定的實例變量, 可以在這個類里面和這個類的派生子類里面可以訪問這個變量,
在類外的訪問是不推薦的, 但也可以訪問。在接口部分定義的實例變量默認是這種作用域。
?@package,對于64位映像,可以在實現該類的映像中的任何地方訪問這個實例變量。
@public指令使得其他方法或函數可以通過使用指針運算符(->)訪問實例變量。
但實例變量聲明為public并不是良好的編程習慣,
因為這違背了數據封裝的思想(即一個類需要隱藏它的實例變量)。
以一個簡單的例子說明作用域:
訪問定義如下:
~~~
#import???
??
@interface?Access:?NSObject?{??
@public??
????int?publicVar;??
@private??
????int?privateVar;??
@protected??
????int?protectedVar;??
}??
??
@end??
~~~
調用的main函數如下:
~~~
#import???
#import?"Access.h"??
??
int?main?(int?argc,?const?charchar?*?argv[])?{??
??
????Access?*a?=?[[Access?alloc]?init];??
??????
????a->publicVar?=?5;??
????NSLog(@"public?var:?%i\n",?a->publicVar);??
??????
??????
????a->protectedVar?=?6;??
????NSLog(@"protectedVar?var:?%i\n",?a->protectedVar);??
??????
??????
????//不能編譯??
????//a->privateVar?=?10;??
????//NSLog(@"private?var:?%i\n",?a->privateVar);??
??????
????return?0;??
}??
~~~
注意:
@public、 @private和@protected作用域限定只能修飾的實例成員變量, 不能修飾類變量, 更不能修飾方法。
什么是類變量和類方法

再以一個簡單的例子說明下:
ClassA.h文件
~~~
#import???
??
static?int?count;??
??
@interface?ClassA:?NSObject?{??
????int?aaa;??
??????
}??
+(int)?initCount;??
+(void)?initialize;??
@end??
~~~
ClassA.m文件
~~~
#import?"ClassA.h"??
??
@implementation?ClassA??
??
-(id)?init?{??
????self?=?[super?init];??
????count++;??
????return?self;??
}??
??
+(int)?initCount?{??
????return?count;??
}??
??
+(void)?initialize?{??
????count?=?0;??
}??
@end??
~~~
#### 代碼說明:
init方法是默認構造方法,?
在這個構造方法中累計類變量count,?
在實例方法中可以訪問類變量的, 但是類方法不能訪問實例變量。?
initCount 方法是一個普通的類方法, 用于返回類變量count,?
initialize方法是非常特殊的類方法,它是在類第一次訪問時候被自動調用 ,?
因此它一般用來初始化類變量的,?
類似于C#中的靜態構造方法。
調用的main函數
~~~
#import???
#import?"ClassA.h"??
??
int?main(?int?argc,?const?charchar?*argv[]?)?{??
????ClassA?*c1?=?[[ClassA?alloc]?init];??
????ClassA?*c2?=?[[ClassA?alloc]?init];??
??????
????//?print?count??
????NSLog(@"ClassA?count:?%i",?[ClassA?initCount]?);??
??????
????ClassA?*c3?=?[[ClassA?alloc]?init];??
????NSLog(@"ClassA?count:?%i",?[ClassA?initCount]?);??
??????
????[c1?release];??
????[c2?release];??
????[c3?release];??
??????
????return?0;??
}??
~~~
#### 代碼說明:
在第一次實例化ClassA時候會調用兩個方法:?
initialize類方法和實例構造方法init,?
然后再次實例化ClassA時候只是調用實例構造方法init, 而沒有調用 initialize類方法。?
這樣類變量count被一直累加,?它隸屬類;
因此c1 實例可以訪問, c2和c3都可以訪問。
關于屬性、存儲方法和實例變量:
編碼規范(Xcode4已經采用的)目前的趨勢是使用下劃線(_)作為實例變量名的起始字符。
@synthesize window = _window;
表明合成(synthesize)屬性window的取值方法和設置方法,
并將屬性與實例變量_window(實例變量并沒有顯性聲明)關聯起來。
這對區別屬性和實例變量的使用是有幫助的。
[window makeKeyAndVisible]; //錯誤
[_window makeKeyAndVisible];//正確
[self.window makeKeyAndVisible];//正確
#### 全局變量:
在程序的開始處(所有的方法、類定義)編寫一下語句:
int gMoveNumber = 0;
那么這個模塊中的任何位置都可以引用這個變量的值。
這種情況下,我們說gMoveNumber被定義為全局變量。
按照慣例,用小寫的g作為全局變量的首字母。
外部變量是可被其他任何方法或函數訪問和更改其值的變量。
在需要訪問外部變量的模塊中,變量聲明和普通方式一樣,只是需要在聲明前加上關鍵字extern。
使用外部變量時,必須遵循下面這條重要的原則:變量必須定義在源文件中的某個位置。
即在所有的方法和函數之外聲明變量,并且前面不加關鍵字extern,如:int gMoveNumber;
確定外部變量的第二種方式是在所有的函數之外聲明變量,
在聲明前面加上關鍵字extern,同時顯式地為變量指派初始值。
記住,聲明不會引起分配變量的內存空間,而定義會引起變量內存空間分配。
處理外部變量時,變量可以在許多地方聲明為extern,但是只能定義一次。
注意,如果變量定義在包含訪問該變量的文件中,那么不需要單獨進行extern聲明。
#### 靜態變量:
在方法之外定義的變量不僅是全局變量,而且是外部變量。
如果希望定義全局變量且只在特定模塊(文件)中是全局的,就可以使用static來修飾。
注意,重載alloc并不是好的編程實踐,因為這個方法處理內存的物理分配。
#### 枚舉數據類型:
枚舉數據類型的定義以關鍵字enum開頭,之后是枚舉數據類型的名稱,然后是標識符序列(包含在一對花括號內),它們定義了可以給該類型指派的所以的允許值。
在代碼中定義的枚舉類型的作用域限于塊的內部。
另外,在程序的開始及所有塊之外定義的枚舉數據類型對于該文件是全局的。
定義枚舉數據類型時,必須確保枚舉標識符與定義在相同作用域之內的變量名和其他標識符不同。