Objective-C之成魔之路【9-类构造方法和成员变量作用域、以及变量】

重开发者的劳动成果,请勿转载

构造方法

出于初始化类中的成员变量的需要, 可以提供一个方法用于此目的,

这个方法就叫构造方法或构造方法(Constructor)。

与C++和Java不同, Objective-C命名是没有限制的, 并且有返回值本身类型指针。

以音乐类举例:

Song.h文件

@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

在Song类的定义中添加了一个方法, 它一般用 init开头命名,

它的返回值很特殊, 是返回值本身类型指针。 并且有返回值本身类型指针。

实现代码如下:

@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

代码说明:

1、头文件引用规则

导入的文件要用一对引号引起来,而不是<Foundation/Foundation.h>中的“<”和">"字符。双引号适用于本地文件(你自己创建的文件),而不是系统文件,这样就通知编译器在哪里能够找到指定的文件。

2、构造方法的实现代码几乎就是模式代码, 基本上都是如下写法:

-(id)init
{
    self = [super init];
    if (self) {
        //初始化代码
    }
    return self;
}

其中使用 [super init] 来调用父类默认构造方法。

对象的初始化的常见的编程习惯是类中所有的初始化方法都以init开头。

如果希望在类对象初始化时做一些事情。可以通过覆写init方法达到这个目的。

这个方法返回的实例对象指派给另一新个关键词: self。

self很像 C++ 和 Java 的 this。

3、还有if ( self ) 跟 ( self != nil ) 一样, 是为了确定调用父类构造方法成功返回了一个新对象。

当初始化变量以后, 用返回self 的方式来获得自己的地址。

4、父类默认构造方法 -(id) init。

技术上来说, Objective-C中的构造方法就是一个 "init" 开头的方法,

而不像 C++ 与Java 有特殊的结构。

5、必须将父类init方法的执行结果赋值给self,

因为初始化过程改变了对象在内存中的位置(意味着引用将要改变)。

如果父类的初始化过程成功,返回的值是非空的,通过if语句可以验证,

注释说明可以在这个代码块的位置放入自定义的初始化代码。

通常可以在这个位置创建并初始化实例变量。

注意,

init被定义为返回id类型,这是编写可能会被继承的类init方法的一般规则。

程序开始执行时,它向所有的类发送initialize调用方法。

如果存在一个类及相关的子类,则父类首先得到这条消息。

该消息只向每个类发送一次,并且向该类发送其它任何消息之前,保证向其发送初始化消息。

实例成员变量作用域限定符

在接口中声明的实例变量可以通过子类进行继承。

可以把下面指令放在实例变量之前,以便更精确地控制其作用域:

即便从封装的角度出发, 实例成员变量应该定义为@private,

但作为一种面向对象的语言, Objective-C支持@public、 @private和@protected作用域限定。

如果一个实例变量没有任何的作用域限定的话, 那么缺省就是@protected。

[email protected]作用域限定的实例变量,可以被本类、其他类或者模块中定义的方法直接访问,即可在任何情况下访问;

[email protected]作用域限定的实例变量,只能在这个类里面才可以访问;

在实现部分定义的实例变量默认属于这种作用域。

[email protected]作用域限定的实例变量, 可以在这个类里面和这个类的派生子类里面可以访问这个变量,

在类外的访问是不推荐的,
但也可以访问。在接口部分定义的实例变量默认是这种作用域。

?@package,对于64位映像,可以在实现该类的映像中的任何地方访问这个实例变量。

@public指令使得其他方法或函数可以通过使用指针运算符(->)访问实例变量。

但实例变量声明为public并不是良好的编程习惯,

因为这违背了数据封装的思想(即一个类需要隐藏它的实例变量)。

以一个简单的例子说明作用域:

访问定义如下:

#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;
}

注意:

@public、 @private和@protected作用域限定只能修饰的实例成员变量,
不能修饰类变量, 更不能修饰方法。

什么是类变量和类方法

再以一个简单的例子说明下:

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

代码说明:

init方法是默认构造方法,

在这个构造方法中累计类变量count,

在实例方法中可以访问类变量的, 但是类方法不能访问实例变量。

initCount 方法是一个普通的类方法, 用于返回类变量count,

initialize方法是非常特殊的类方法,它是在类第一次访问时候被自动调用 ,

因此它一般用来初始化类变量的,

类似于C#中的静态构造方法。

调用的main函数

#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开头,之后是枚举数据类型的名称,然后是标识符序列(包含在一对花括号内),它们定义了可以给该类型指派的所以的允许值。

在代码中定义的枚举类型的作用域限于块的内部。

另外,在程序的开始及所有块之外定义的枚举数据类型对于该文件是全局的。

定义枚举数据类型时,必须确保枚举标识符与定义在相同作用域之内的变量名和其他标识符不同。

时间: 2024-12-06 01:44:19

Objective-C之成魔之路【9-类构造方法和成员变量作用域、以及变量】的相关文章

Objective-C之成魔之路【1-序章】

重开发者的劳动成果,请勿转载 C语言首创于AT&T实验室, UNIX OS的发展促进了C语言的快速普及,UNIX OS几乎完全是由C语言编写的. Brad J.Cox在20世纪80年代早期设计了Objective-C语言,它以一种叫做SmallTalk-80的语言为基础. SmallTalk-80可以参考: http://zh.wikipedia.org/wiki/Smalltalk Objective-C在C语言的基础上加了一层,这意味着对C进行了扩展, 从而创造出一门新的程序设计语言,支持面

Objective-C之成魔之路【17-内存管理】

郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 如果文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额随意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源码下载:点我传送 内存管理关心的是清理(回收)不用的内存,以便内存能够再次利用. 提供给Objective-C程序员的基本内存管理模型有以下三种: 1)自动垃圾收集.(iOS运行环境并不支持垃圾收集,在这个平台开发程序时没有这方面的选项,只能用在Mac OS X 程序上开发.这个机制挺恶心的,用mac电脑的人知道,当内存不足的时

Objective-C之成魔之路【15-Foundation框架】

郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 如果文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额随意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源码下载:点我传送 概述 Mac OS X开发会使用 Cocoa框架, 它是一种支持应用程序提供丰富用户体验的框架, 它实际上由: Foundation和Application Kit(AppKit)和 Core Data框架组成. iOS开发, 会使用 Cocoa Touch框架, 它实际上由: Foundation.Core

Objective-C之成魔之路【11-多态性、动态类型和动态绑定】

郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 如果文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额随意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源码下载:点我传送 多态这个其它语言也有.动态类型有类似的,但不完全相同. 动态绑定别的语言也有类似,但没有objective-c用的这么多. 多态能够使来自不同类的对象定义相同名称的方法. 动态类型能使程序直到执行时才确定对象所属的类. 动态绑定则能使程序直到执行时才确定实际要调用的对象方法. 多态性是指在父类中定义的成员变量和

Objective-C之成魔之路【3-数据类型】

重开发者的劳动成果,请勿转载 数据类型. 运算符和表达式在任何的计算机语言中都比较重要的, 在面向对象的Objective-C语言中, 除了常规的基本类型, 还有对象类型等. 运算符和表达式完全遵守C语言规范. Objective-C数据类型可以分为:基本数据类型. 对象类型和id类型. 基本数据类型有: int. float. double和char类型. 对象类型就是类或协议所声明的指针类型, 例如: NSAutoreleasePool * pool, 其中NSAutoreleasePool

Objective-C之成魔之路【5-选择结构】

重开发者的劳动成果,请勿转载 Objective-C中的控制语句有以下几类: ? 分支语句: if-else, switch ? 循环语句: while, do-while, for ? 与程序转移有关的跳转语句: break, continue, goto 对于任何程序语言来说,有能力进行判断是一项基本特性. if-else语句 分支语句提供了一种控制机制, 使得程序的执行可以跳过某些语句不执行, 而转去执行特定的语句. 1. 条件语句 if-else 2. 多分支语句 switch 条件语句

Objective-C之成魔之路【16-使用文件】

郝萌主倾心贡献,尊重作者的劳动成果.请勿转载. 假设文章对您有所帮助,欢迎给作者捐赠.支持郝萌主,捐赠数额任意.重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源代码下载:点我传送 语言的设计主要是被应用于实践, 而Objective-C应用最广的地方就是Mac OS X或iOS的Foundation框架. Foundation框架同意你利用文件系统对文件或文件夹运行基本操作,这些基本操作是由NSFileManager类提供的. 使用NSFileHandle类提供的方法,能够打开文件并对

Objective-C之成魔之路【10-继承性】

重开发者的劳动成果,请勿转载 继承性是面向对象的重要概念之一, 子类能够继承父类的某些方法和成员变量. 作用域限定符为private的成员变量是不可以被继承的. 子类还可以重写父类的方法. 当然,这一切要从根类开始: 没有父类的类,位于类层次结构的最顶层,称为根(Root)类. NSObject是层次结构的最顶端(也就是它上面没有任何类),因此称为根类. 如果使用术语,可以将类称为子类和父类.同样,也可以将类称为子类和超类. 需要注意的是,要在子类中直接使用实例变量,必须先在接口部分声明. 在实

Objective-C之成魔之路【1-Objective-C特点】

重开发者的劳动成果,请勿转载 Objective-C与其它面向对象有这明显的不同, 它有这自己鲜 明的特色, 下面我们从这个方法介绍它的特点: 兼容性. 字 符串. 类. 方法. 属性. 协议和分类. 1.兼容性 Objective-C可以说是一种面向对象的C语言, 在Objective-C的代码中可以有C和C++语句, 它可以调用 C的函数, 也可以通过C++对象访问方法. 2.字符串 Objective-C通常不使用C语言风格的字符串. 大多数情况下是使用Foundation框架的NSStr