天天看点

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
           

以上就是几种变量的声明方式,真是走马观灯,眼花缭乱。

不过在日常开发中,一半较少遇到变量作用域的问题,正常使用就好。这些各种各样的方式,还是留给有需要的人去用吧。

继续阅读