天天看點

oc中,對象聲明成員變量的幾種方式,以及對應的一些擴充知識@interface中聲明成員變量@property時代在特殊的匿名分類Category中聲明變量在@implementation中聲明變量

oc繼承自c,c的變量聲明方式這裡就不說了,進入正題。

@interface中聲明成員變量

oc最原始的變量聲明,就是在@interface中聲明。預設的聲明方式就是隐性的@protected

@interface ClassA :NSObject
{
    NSInteger oneInteger;  //隐含@protected的意思
}
@end
           

oc中也支援繼承,是以如果想聲明私有變量,不允許子類通路該變量,可以 加 @private辨別符

@private
NSInteger oneInteger;
           

如果想聲明公有變量,想在對象的外部進行通路,可以這樣:

@public
NSInteger oneInteger;

//通路的方式如下
classA->oneInteger = 123;
           

後來蘋果又提供了一個新的聲明辨別@package,使變量隻能在framework内才是public。蘋果官方文檔摘抄如下

@package is a new instance variable protection class, like @public and @protected. @package instance variables behave as follows:
(@package是一個新的成員變量保護域,就像@public和@protected。使用@package作用域的成員變量,有如下特征:)

@public in 32-bit;
@public in 64-bit, inside the framework that defined the class;
@private in 64-bit, outside the framework that defined the class.
(在32位系統中,@package和@public等同
在64位系統中,framework内的@package變量,可以像@public變量一樣使用
在64位系統中,framework外不能通路@package變量,甚至繼承framework中的類都不可以,類似@private)
           

@property時代

後來有一本紅寶書,風靡一時,大家都看過吧,叫 《Objective-C.2.0程式設計》

在這本書中,介紹了屬性聲明@property以及存取器@synthesize。屬性聲明使得一個變量可以在對象外部進行通路,而存取器則預設生成了變量的setter和getter方法。

//頭檔案
@interface ClassA :NSObject
{
    NSInteger oneInteger;
}
@property(nonatomic)NSInteger oneInteger;
@end

//實作檔案
@implementation ClassA
@synthesize oneInteger;
@end
           

這樣的話,想通路ClassA的變量就友善了許多

classA.oneInteger = 12;  //setter方法設定變量
NSLog(@"%d", classA.oneInteger);  //getter方法擷取變量
           

如果要隐藏成員變量名,還可以給變量取别名

//頭檔案
@interface ClassA :NSObject
{
    NSInteger oneInteger;  //成員變量
}
@property(nonatomic)NSInteger propertyInteger;  //别名
@end

//實作檔案
@implementation ClassA
@synthesize propertyInteger = oneInteger;  //别名,映射到成員變量上
@end
           

存取器預設生成setter和getter方法,如果有需要仍可以自定義,自定義的方法會覆寫系統生成的方法。setter和getter方法的定義規則:

//setter方法名為  set+首字母大寫的變量名 ,參數類型必須是變量的類型。
- (void)setOneInteger:(NSInteger)aInt;
//getter方法名與變量同名,傳回類型必須是變量的類型;
- (NSInteger)oneInteger;
           

聲明屬性時,還可以指定setter和getter的方法

@property(nonatomic,[email protected](setAnInteger:))NSInteger oneInteger;
           

此時,oneInteger的set方法就變成了 -(void)setAnInteger:(NSInteger)aInt;

後來蘋果推出新特性,允許不聲明變量,隻寫@property和@synthesize。

//頭檔案
@interface ClassA :NSObject
@property(nonatomic)NSInteger oneInteger;
@end

//實作檔案
@implementation ClassA
@synthesize oneInteger;
@end
           

此時編譯器預設幫助生成一個變量,與@property同名。即,預設生成了一個NSInteger oneInteger;

如果在不聲明變量的情況下,存取器使用别名,則聲明的變量名與=後面的名字相同。

@synthesize oneInteger = abc;   //生成的變量為abc
           

除了可以不聲明變量,甚至存取器都可以省略了

//頭檔案
@interface ClassA :NSObject
@property(nonatomic)NSInteger oneInteger;
@end
           

此時有所不同的是,預設生成的變量名為 下劃線+屬性名。即,預設生成了一個NSInteger _oneInteger;

在特殊的匿名分類Category中聲明變量

oc中的分類大家都用過,分類不允許聲明成員變量,可以聲明屬性和方法。

以ClassA為例,可以聲明一個分類

@interface ClassA (Category1)
@property(nonatomic)NSInteger cateInt;  //允許聲明@property
- (void)cateFunc;  //允許聲明方法
@end
           

使用分類,使得隐藏@property成為可能,将Category寫在.m檔案中,則其他檔案都無法通路到,相當于變相的@private。

但是有一個特殊的分類,不寫分類名,稱之為 匿名分類。匿名分類的一個重要特征,就是允許聲明成員變量,且預設@private熟悉

@interface ClassA ()
{
    NSInteger cateInt;  //匿名分類,允許聲明成員變量
}
@end
           

當然,可以使用@protected等辨別來改變它的作用域。

在@implementation中聲明變量

蘋果對變量的作用域一直如此糾結,現在又推出一種新的變量聲明方式,變量聲明在實作檔案@implementation中。這樣就變成了隻能在對象内使用,相當于@private。

//頭檔案
@interface ClassA :NSObject
@end

//實作檔案
@implementation ClassA
{
    NSInteger oneInteger;  //相當于私有變量 @private
}
@end
           

以上就是幾種變量的聲明方式,真是走馬觀燈,眼花缭亂。

不過在日常開發中,一半較少遇到變量作用域的問題,正常使用就好。這些各種各樣的方式,還是留給有需要的人去用吧。

繼續閱讀