首页 > 代码库 > Objective-C之成魔之路【9-类构造方法和成员变量作用域、以及变量】
Objective-C之成魔之路【9-类构造方法和成员变量作用域、以及变量】
重开发者的劳动成果,请勿转载
出于初始化类中的成员变量的需要, 可以提供一个方法用于此目的,
以音乐类举例:
@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
实现代码如下:
@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
-(id)init { self = [super init]; if (self) { //初始化代码 } return self; }
对象的初始化的常见的编程习惯是类中所有的初始化方法都以init开头。
如果希望在类对象初始化时做一些事情。可以通过覆写init方法达到这个目的。
3、还有if ( self ) 跟 ( self != nil ) 一样, 是为了确定调用父类构造方法成功返回了一个新对象。
4、父类默认构造方法 -(id) init。
5、必须将父类init方法的执行结果赋值给self,
注意,
init被定义为返回id类型,这是编写可能会被继承的类init方法的一般规则。
程序开始执行时,它向所有的类发送initialize调用方法。
如果存在一个类及相关的子类,则父类首先得到这条消息。
该消息只向每个类发送一次,并且向该类发送其它任何消息之前,保证向其发送初始化消息。
在接口中声明的实例变量可以通过子类进行继承。
可以把下面指令放在实例变量之前,以便更精确地控制其作用域:
?@private作用域限定的实例变量,只能在这个类里面才可以访问;
?@protected作用域限定的实例变量, 可以在这个类里面和这个类的派生子类里面可以访问这个变量,
#import <Foundation/NSObject.h> @interface Access: NSObject { @public int publicVar; @private int privateVar; @protected int protectedVar; } @end调用的main函数如下:
#import <Foundation/Foundation.h> #import "Access.h" int main (int argc, const char * 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; }注意:
再以一个简单的例子说明下:
ClassA.h文件
#import <Foundation/NSObject.h> 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
#import <Foundation/Foundation.h> #import "ClassA.h" int main( int argc, const char *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开头,之后是枚举数据类型的名称,然后是标识符序列(包含在一对花括号内),它们定义了可以给该类型指派的所以的允许值。
在代码中定义的枚举类型的作用域限于块的内部。
另外,在程序的开始及所有块之外定义的枚举数据类型对于该文件是全局的。
定义枚举数据类型时,必须确保枚举标识符与定义在相同作用域之内的变量名和其他标识符不同。
Objective-C之成魔之路【9-类构造方法和成员变量作用域、以及变量】