首先、引用一篇關於@property與@synthesize的老文。交代一下這兩個屬性的由來、便於下文理解
——————————————————————————————————————
當你定義了一系列的變量時,需要寫很多的getter和setter方法,而且它們的形式都是差不多的,,所以Xcode提供了@property和@synthesize屬性,@property用在 .h 頭文件中用作聲明,@synthesize用在.m 文件中用於實現。
如下,新建一個基於“Command Line Tool”的項目,名爲“property”,再新建一個Student類,
傳統的寫法是:
Student.h
- //
- // Student.h
- // property
- //
- // Created by Rio.King on 13-8-25.
- // Copyright (c) 2013年 Rio.King. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- @interface Student : NSObject
- {
- int age;
- int no;
- }
- //age的getter和setter方法聲明
- - (int)age;
- - (void)setAge:(int)newAge;
- //no的getter和setter方法聲明
- - (int)no;
- - (void)setNo:(int)newNo;
- @end
- //
- // Student.m
- // property
- //
- // Created by Rio.King on 13-8-25.
- // Copyright (c) 2013年 Rio.King. All rights reserved.
- //
- #import "Student.h"
- @implementation Student
- //age的getter和setter方法的實現
- - (int)age
- {
- return age;
- }
- -(void)setAge:(int)newAge
- {
- age = newAge;
- }
- //no的getter和setter方法的實現
- - (int)no
- {
- return no;
- }
- - (void)setNo:(int)newNo
- {
- no = newNo;
- }
- @end
- //
- // main.m
- // property
- //
- // Created by Rio.King on 13-8-25.
- // Copyright (c) 2013年 Rio.King. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import "Student.h"
- int main(int argc, const char * argv[])
- {
- @autoreleasepool {
- // insert code here...
- Student *stu = [[Student alloc] init];
- stu.age = 100;//這句相當於setter方法
- NSLog(@"age is %i", stu.age);//這裏的 stu.age 相當於getter方法
- [stu release];
- }
- return 0;
- }
------------------------------------------------------------------------------------------------------------------------
用@property和@synthesize的寫法是:
Student.h
- //
- // Student.h
- // property
- //
- // Created by Rio.King on 13-8-25.
- // Copyright (c) 2013年 Rio.King. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- @interface Student : NSObject
- {
- int age;
- int no;
- }
- //當編譯器遇到@property時,會自動展開成getter和setter的聲明
- @property int age;
- @property int no;
- @end
Student.m
- //
- // Student.m
- // property
- //
- // Created by Rio.King on 13-8-25.
- // Copyright (c) 2013年 Rio.King. All rights reserved.
- //
- #import "Student.h"
- @implementation Student
- //@synthesize 會自動生成getter和setter的實現
- //@synthesize 默認會去訪問age,no,height同名的變量,,
- //如果找不到同名的變量,會在內部自動生成一個私有同名變量age,no,height,,
- //因此Student.h 中的這幾個變量也可以省略不寫。
- @synthesize age,no;
- @end
main.m
- //
- // main.m
- // property
- //
- // Created by Rio.King on 13-8-25.
- // Copyright (c) 2013年 Rio.King. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import "Student.h"
- int main(int argc, const char * argv[])
- {
- @autoreleasepool {
- // insert code here...
- Student *stu = [[Student alloc] init];
- stu.age = 100;
- NSLog(@"age is %i", stu.age);
- [stu release];
- }
- return 0;
- }
在Xcode4.5及以後的版本中,可以省略@synthesize ,編譯器會自動幫你加上getter 和 setter 方法的實現,並且默認會去訪問
_age這個成員變量,如果找不到_age這個成員變量,會自動生成一個叫做 _age的私有成員變量。
———————————————————————————————————————————————————————————————————————————————————————————————————————————————————
OK進入正題
Objective-C中先有的實例變量,需要給外部類使用的用@public聲明,內部自己使用的用@private或@protect聲明。Objective-C添加了屬性後,屬性用於對外而實例變量主要用於程序內部使用。這樣有利於代碼的分離,由於編譯器會直接給屬性提供對應的實例變量(當然也可以手動指定該屬性所對應的實例變量)和getter/setter方法。
類Class中的屬性property
在老版本的Objective-C語言中,我們需要同時聲明屬性和底層實例變量,那時,屬性是Objective-C語言的一個新的機制,並且要求你必須聲明與之對應的實例變量,例如:
後來,蘋果將默認編譯器從GCC轉換爲LLVM(low level virtual machine),從此不再需要爲屬性聲明實例變量了。如果LLVM發現一個沒有匹配實例變量的屬性,它將自動創建一個以下劃線開頭的實例變量。因此,在這個版本中,我們不再爲輸出口聲明實例變量。
例如:MyViewController.h文件
在MyViewController.m文件中,編譯器也會自動的生成一個實例變量_myButton。那麼在.m文件中可以直接的使用_myButton實例變量,也可以通過屬性self.myButton.都是一樣的。
注意這裏的self.myButton其實是調用的myButton屬性的getter/setter方法。這與C++中點的使用是有區別的,C++中的點可以直接訪問成員變量(也就是實例變量)。
例如在Objective-C中有如下代碼
.h文件
.m文件中,self.name 這樣的表達式是錯誤的。xcode會提示你使用->,改成self->name就可以了。因爲oc中點表達式是表示調用方法,而上面的代碼中沒有name這個方法。
oc語法關於點表達式的說明:”點表達式(.)看起來與C語言中的結構體訪問以及java語言彙總的對象訪問有點類似,其實這是oc的設計人員有意爲之。如果點表達式出現在等號 = 左邊,該屬性名稱的setter方法將被調用。如果點表達式出現在右邊,該屬性名稱的getter方法將被調用。”
所以在oc中點表達式其實就是調用對象的setter和getter方法的一種快捷方式, 例如:dealie.blah = greeble 完全等價於 [dealie.blah setBlah:greeble];
以前的用法,聲明屬性跟與之對應的實例變量:
這種方法基本上使用最多,現在大部分也是在使用,因爲很多開源的代碼都是這種方式。但是ios5更新之後,蘋果是建議以以下的方式來使用:
因爲編譯器會自動爲你生成以下劃線開頭的實例變量_myButton,不需要自己手動再去寫實例變量。而且也不需要在.m文件中寫@synthesize myButton;也會自動爲你生成setter,getter方法。@synthesize的作用就是讓編譯器爲你自動生成setter與getter方法。
@synthesize 還有一個作用,可以指定與屬性對應的實例變量,例如@synthesize myButton = xxx;那麼self.myButton其實是操作的實例變量xxx,而不是_myButton了。
在實際的項目中,我們一般這麼寫.m文件
@synthesize myButton;
這樣寫了之後,那麼編譯器會自動生成myButton的實例變量,以及相應的getter和setter方法。注意:_myButton這個實例變量是不存在的,因爲自動生成的實例變量爲myButton而不是_myButton,所以現在@synthesize的作用就相當於指定實例變量;
如果.m文件中寫了@synthesize myButton;那麼生成的實例變量就是myButton;如果沒寫@synthesize myButton;那麼生成的實例變量就是_myButton。所以跟以前的用法還是有點細微的區別。