@property命名時的要點與要注意的問題

@property命名時的要點與要注意的問題

1、@property命名規範

(1)用@property的命名規範一:在@interface的{}定義“成員型別  _成員名”格式的成員變數,@property  成員型別  成員名;在實現中用@synthesize  成員名=_成員名;訪問方式:物件名/self/super  . 成員名   注意:@synthesize  成員名=_成員名;表示訪問的是”_成員名”這個成員變數,即為“_成員名”這個變數提供了set與get方法,且方法名以不帶下劃線的成員名為主即
set 成員名(首字母大寫)和成員名的set/get方法。這種規範舉例如下:假設類宣告中:@interface A{int _age; } @property int age; @end 且在類宣告中@implementation A  @synthesize  age=_age; @end  這種情況下系統將為_age提供一個方法名為“setAge”的set方法和一個方法名為“age”的get方法。

(2)用@property的命名命名規範二:在@interface的{}定義“成員型別  成員名”格式的成員變數,@property  成員型別  成員名;在實現中用@synthesize  成員名;訪問方式上同:物件名/self/super  . 成員名   此規範舉例如下:假設類宣告中: @interface A{int age;} @property int age;@end且類的實現部分:@implementation
A     @synthesize age; @end 這種情況下:系統將直接為age提供一個名為”setAge”的set方法和名為”age”的get方法,簡單清楚。

(3)用@property的命名規範三:省去@synthesize部分,即去除與@implementation實現檔案中與@interface內@property宣告的變數對應的@synthesize部分。然後在類宣告的{}中宣告一個和@property中宣告變數的型別相同且名字為”_變數名(變數名指:@property中宣告的變數的名稱)”   的例項變數。這樣命名的好處是:在省去了對應的@synthesize的情況下,系統將不再重新為@property中的變數提供型別相同且名為”_變數名”的私有例項變數,而是直接為{}內的“_變數名”提供方法名為“set變數名”(變數名首字母大寫)的set方法和方法名為“變數名”(首字母不大寫)的get方法。
繼承此類的子類以及子類的子類不僅可以呼叫set/get方法來訪問這個名為“_變數名”的父類定義的例項變數也可以直接用“super->_變數名”的方式來訪問這個帶下劃線的例項變數。這種規範舉例如下:假設類宣告中:@interface{ int _age;} @property int age; @end  且@implementation部分不寫對應的@synthesize部分。這樣系統直接為{}內的_age
提供一個名為”setAge”的set方法和一個名為”age”的get方法。且_age 是protected型別,可以被子類直接用指標訪問。

   注意:在使用 @synthesize  xxx=yyy;(xxx在@property已被宣告過)這種方式時,表示為yyy這個繫結的變數提供方法名為 setXxx的set方法和方法名為xxx的get方法。如果yyy在@interface中的{}內沒有被宣告時,系統會先自動為類提供一個名字為yyy且型別與xxx相同的私有型別的例項變數,再提供以上的set/get方法操作。

2、用@property宣告變數並和@synthesize配套使用時的多種情況:

(1)當@property宣告的變數和@interface內{}中的變數相同且在@implementation中用@synthesize時沒有將宣告的此變數繫結別的變數時,這時僅僅為已宣告的即{}內的例項變數(預設是protected型別)提供set/get方法。

(2)當@property宣告的變數和@interface內{}中的變數相同時但在@implementation中用@synthesize時將宣告的此變數繫結了別的變數,這時不是在為@interface內{}中的變數提供set/get方法,而是為繫結的那個變數提供set與get方法。

(3)當@property宣告的變數和@interface內{}中的變數不同且在@implementation中用@synthesize時沒有將宣告的此變數繫結別的變數時,系統將提供一個和這個@property中宣告的變數完全相同的私有型別的變數,並以此變數名為參考為此變數自動提供set/get方法。

(4)當@property宣告的變數和@interface內{}中的所有變數都不同且在@implementation中用@synthesize時將宣告的此變數繫結別的變數時,如果繫結的這個變數與類宣告中{}內的某個變數完全相同(包括變數名和型別),系統將為{}內與繫結的變數完全相同的那個變數自動提供set/get方法。如果@interface中{}內沒有與繫結的這個變數完全相同的例項變數時,系統將自動提供一個與繫結的這個變數完全相同的私有變數,並以@property中宣告的變數名為基準為自動提供的這個私有變數自動生成set/get方法。

注意:無論哪種形式,@property自動提供的所有方法都是公有的;其次@property提供的set與get方法名完全與在@property中宣告的變數有關,set方法名都是”set變數名“,變數名的首字母都是大寫;get方法都是”變數名“。此變數名僅指@property中宣告的變數。

3、當僅有@property宣告部分但省去對應的@synthesize實現部分的情況下又分為以下三種形式:

(1)形式一:當@property中的宣告的變數與@interface類宣告的{}內宣告的任何變數都不相同時,系統會自動為這個類提供一個名字為“_變數名”的私有型別的例項變數,併為這個私有的例項變數提供一個方法名為“set變數名(變數名首字母要大寫)”的set方法和一個方法名為“變數名”的get方法。此時的“變數名”指前面@property中宣告的那個變數的名稱。例如:@property  int  age;系統在當前所述的情況下會自動為類提供一個名為“_age”且為私有型別的int型例項變數,併為這個私有型別的例項變數”_age”提供一個方法名為”setAge”的set方法和一個方法名為”age”的get方法。

 (2)形式二:當@property中的宣告的變數與@interface類宣告的{}內宣告的變數有相同的時,仍然與形式一相同,並不會因為變數與{}宣告中的變數相同而僅僅為{}內的相同變數提供set/get方法  不要造成這種誤解。

(3)形式三:形式一雖然省掉很多程式碼,但也有很大弊端,例如當我們想讓繼承此類的子類能直接訪問此類的@property宣告自動提供的私有型別的例項變數是不可能的。想解除這種弊端有一種很好的方法,就是在此類的宣告中{}內提供名字為“_變數名(注意:此變數名為@property中宣告的變數名)”的例項變數,系統將不再提供名為“_變數名”的例項變數,而是直接將@property語句與{}內的“_變數名”的例項變數進行了繫結,而且繼承此類的子類也可以直接訪問此變數。例如:@interface{int
_age;} @property  int age; @end;  系統將不再自動提供一個名為“_age”的變數,而是為_age提供一個方法名為setAge的set方法和方法名為age的get方法。

  注意:當為@property中宣告的某變數省去對應的@synthesize部分時,不論什麼情況系統都會自動為這個變數提供一個私有型別的例項變數且再為這個私有的例項變數提供set/get方法,具體步驟與形式一完全相同。

 4、私有型別的例項變數是不能被子類直接訪問的,子類只能通過set/get方法來訪問。注意以上情況下那些會產生私有型別的例項變數

5、實質剖析:@property僅僅表示宣告,即僅僅宣告set/get方法名  假設  @property int xxx;  僅僅表示宣告瞭方法名為setXxx的set方法和方法名為xxx的get方法。即set、get方法名完全由@property宣告決定。  而@synthesize  僅僅表示對哪個變數進行實現set與get方法。總之一句話:@property指定set與get方法名,@synthesize指定訪問變數。當無@synthesize部分時,系統才提供以下劃線開頭的私有變數。

6、如果我們手動為變數提供了“set(變數名)”(變數名首字母大寫)的set方法或者“變數名”(首字母不大寫)的get方法,系統將 不再自動提供set或get方法。也就是說Xcode比較尊重程式設計師的選擇,我們已經為變數提供的方法,Xcode將不再自動生成。

7、在使用@property自動生成set/get方法時,凡是Xcode自動生成的例項變數都是私有型別的。子類是無法直接用self->或super->來訪問的。

程式碼驗證(專案一)例項如下:

主要驗證手動提供的set/get方法,Xcode不再自動生成:

新建c.h編輯如下:

//
//  c.h
//  @property_3
//
//  Created by apple on 15/8/16.
//  Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface C : NSObject
{
@public
int  age;
double height;
}
@property int age;
@property double height;
-(int)age;
-(void)setHeight:(double) height;
@end

編輯c.m程式碼如下:

//
//  c.m
//  @property_3
//
//  Created by apple on 15/8/16.
//  Copyright (c) 2015年 liu. All rights reserved.
//
#import "c.h"
@implementation C
@synthesize age,height;
-(int)age{
return  250;
}
-(void)setHeight:(double) height{
self->height=500;
}
@end

在main.m中呼叫如下:

//
//  main.m
//  @property_3
//
//  Created by apple on 15/8/16.
//  Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "c.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
C *c=[[C  alloc] init];
c.age=100; //呼叫了自動生成的setAge方法為age賦值為100;
c.height=125;//呼叫了手動提供的setHeight方法為height賦值為500。
printf("%d %d %.2lf %.2lf\n",c.age,c->age,c.height,c->height);
[c release];
}
return 0;
}

執行結果如下:

程式碼驗證(專案二)例項如下:

主要驗證省去@synthesize部分將會出現的幾種情況

新建a.h編輯如下:

//
//  a.h
//  @property_2
//
//  Created by apple on 15/8/15.
//  Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface A : NSObject{
@public
NSString* t; //沒有給t提供set/get方法
NSString*  _t;
}
@property (nonatomic,copy) NSString * t;//為{}內的_t提供了名為setT的set方法和名為t的get方法;
@property (nonatomic,copy)NSString * t1;//因為{}內不存在NSString型別的_t1,所以系統先為此類提供私有的例項變數_t1,然後為_t1提供方法名為setT1的set方法和方法名為t1的get方法。
-(void)Test;
@end

編輯a.m程式碼如下:

//
//  a.m
//  @property_2
//
//  Created by apple on 15/8/15.
//  Copyright (c) 2015年 liu. All rights reserved.
//
#import "a.h"
@implementation A
-(void)Test{
self->[email protected]"t";
self->[email protected]"_t";
self->[email protected]"_t1"; //系統提供的_t1是私有型別的,在外部和子類中是無法直接訪問的。
NSLog(@"類存在例項變數:%@\n",self->t);
NSLog(@"類存在例項變數:%@\n",self->_t);
NSLog(@"類存在例項變數:%@\n",self->_t1);
NSLog(@"存在方法self.t:%@\n",self.t);
NSLog(@"存在方法self.t1:%@\n",self.t1);
}
@end

在main.m檔案中呼叫如下:

//
//  main.m
//  @property_2
//
//  Created by apple on 15/8/15.
//  Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "a.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
A  *a=[[A alloc] init];
[a Test];
[a release];
}
return 0;
}

執行結果如下:

=============================================================================

 程式碼驗證(專案三)例項如下:

驗證存在對應的@synthesize部分將會出現的幾種情況。

新建a.h編輯如下:

//
//  a.h
//  @property_problem
//
//  Created by apple on 15/8/15.
//  Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface A : NSObject
{
@public
int  x, _x, _y, y ;
}
@property  int   x,  _x ;
@property  int   y,  _y ;
@property  int   z ;
@property  int   z1 ;
-(void)Test;
@end

編輯a.m如下:

//
//  a.m
//  @property_problem
//
//  Created by apple on 15/8/15.
//  Copyright (c) 2015年 liu. All rights reserved.
//
#import "a.h"
@implementation A
@synthesize x  ; /* 完全可以寫到同一個@synthesize宣告中用“,”隔開 */
@synthesize _x;
@synthesize y =_y ;
@synthesize _y = y ;
@synthesize z =_z ;
@synthesize z1;
-(void)Test{
printf("======================成員方法Test檢測驗證=====================\n");
printf("self->x = %d\t   self.x = %d\t self->_x = %d\t self._x = %d\t\n", self->x, self.x, self->_x, self._x );
printf("self->y = %d\t   self.y = %d\t self->_y = %d\t self._y = %d\t\n", self->y, self.y, self->_y, self._y );
printf("self->_z = %d\t  self.z = %d\t self->z1= %d\t  self.z1 = %d\t\n", self->_z, self.z,self->z1, self.z1); //不存在例項變數z,存在_z
}
@end

編輯main.m如下:

//
//  main.m
//  @property_problem
//
//  Created by apple on 15/8/15.
//  Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "a.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
A *a=[[A alloc] init];
a.x=100;
a._x=200;
a.y=300;
a._y=400;
a.z=500;
a.z1=600;
NSLog(@"a.x=%d  a->x=%d",a.x,a->x);
NSLog(@"a._x=%d  a->_x=%d",a._x,a->_x);
NSLog(@"a.y=%d  a->y=%d",a.y,a->y);
NSLog(@"a._y=%d  a->_y=%d",a._y,a->_y);
NSLog(@"a.z=%d  a.z=%d",a.z,a.z);
NSLog(@"a.z1=%d  a.z1=%d",a.z1,a.z1);
[a Test];
}
return 0;
}

執行結果如下:

分析程式如下圖所示:

首先在類的物件方法實現中觀察self用.和->訪問時的提示

其次在main.m中觀察類的物件指標用.和->訪問時的提示如下: