【IT168技术】到目前为止,我们已经学习了两种创建新对象的方法:[类名 new] 和 [[类名 alloc] init]。这两种方法是等价的,不过Cocoa的惯例是使用后者。
有些语言(如C++和Java)使用构造函数在单次操作中执行对象的分配和初始化。Objective-C将这两种操作拆分为两个明确的步骤:分配和初始化。
分配(allocation):向某个类发送alloc消息的结果就是为该类分配一块足够大的内存,以存放该类的全部实例变量。同时,alloc方法还顺便将这块内存区域全部初始化为0。
初始化(initialization)从操作系统取得一块内存,准备用于存储对象。init方法几乎总是返回它们正在初始化的对象。应该像下面这样嵌套调用alloc和init方法:
Car *car = [[Car alloc] init];
而不是像下面这样:
Car *car = [Car alloc];
[car init];
这种嵌套调用技术非常重要,因为初始化方法返回的对象可能与分配的对象不同(见NSString章节末尾的类簇)。
编写初始化方法:
- (id) inti
{
if (self = [super init])
{
// …. 进行初始化
)
return (set);
}
便利初始化函数(convenience initializer),是用来完成某些额外工作的初始化方法,可以减少你自己完成这些工作的麻烦。例如:
// 返回一个空字符串
NSString *emptyString = [[NSString alloc] init];
// 按格式返回字符串
NSString *string = [[NSString alloc]
initWithFormat:@"%d or %d", 25 124];
// 打开指定路径上的文本文件,读取文件内容
NSString *file = [[NSString alloc]
initWithContentsOfFile: @"/tmp/words.txt"];
为了初始化的便利性,一个类可能有多个初始化方法。为了正确完成实例化并且子类继承时不出现问题,请明确一个“指定初始化函数”(designated initializer)。
类中的某个初始化方法被指派为指定初始化函数。该类的所有初始化方法使用指定初始化函数执行初始化操作。子类使用其超类的指定初始化函数实现超类的初始化。通常,接受参数最多的初始化方法最终成为指定初始化函数。
Example:
InitExample.h
1 //
2 // InitExample.h
3 // 示例类的初始化,添加指定初始化函数
4 //
5 // Created by Elf Sundae on 10/26/10.
6 // Copyright 2010 Elf.Sundae(at)Gmail.com . All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10
11
12 @interface InitExample : NSObject
13 {
14 NSString *firstName;
15 NSString *lastName;
16 NSString *fullName;
17 }
18
19 - (void) setFirstName: (NSString *) firstName;
20 - (NSString *) firstName;
21
22 - (void) setLastName: (NSString *) lastName;
23 - (NSString *) lastName;
24
25 - (NSString *) fullName;
26
27 - (id) initWithFirstName: (NSString *) firstName;
28 - (id) initWithLastName: (NSString *) lastName;
29 - (id) initWithFirstName: (NSString *) firstName lastName:(NSString *) lastName;
30
31 @end
InitExample.m
1 //
2 // InitExample.m
3 // Initializer
4 //
5 // Created by Elf Sundae on 10/26/10.
6 // Copyright 2010 Elf.Sundae(at)Gmail.com . All rights reserved.
7 //
8
9 #import "InitExample.h"
10
11
12 @implementation InitExample
13
14 // *************************************************
15 // 属性访问方法
16 - (void) setFirstName: (NSString *) m_firstName
17 {
18 firstName = m_firstName;
19 }
20 - (NSString *) firstName
21 {
22 return firstName;
23 }
24
25 - (void) setLastName: (NSString *) m_lastName
26 {
27 lastName = m_lastName;
28 }
29 - (NSString *) lastName
30 {
31 return lastName;
32 }
33
34 - (NSString *) fullName;
35 {
36 return [NSString stringWithFormat:@"%@ %@",firstName,lastName];
37 }
38
39 // *************************************************
40 // 初始化方法
41
42 // 指定初始化函数(designated initializer)
43 - (id) initWithFirstName: (NSString *) m_firstName
44 lastName:(NSString *) m_lastName
45 {
46 if (self = [super init])
47 {
48 firstName = m_firstName;
49 lastName = m_lastName;
50 }
51 return self;
52 }
53
54 - (id) initWithFirstName: (NSString *) m_firstName
55 {
56 if (self = [self initWithFirstName:m_firstName
57 lastName:@"NoLastName"]){
58
59 }
60 return self;
61 }
62 - (id) initWithLastName: (NSString *) m_lastName
63 {
64 if (self = [self initWithFirstName:@"NoFirstName"
65 lastName:m_lastName]){
66
67 }
68 return self;
69 }
70
71 - (id) init
72 {
73 if (self = [self initWithFirstName:@"NoFirstName"
74 lastName:@"NoLastName"]){
75
76 }
77 return self;
78 }
79
80 @end
SubClass.h
1 //
2 // SubClass.h
3 // 示例子类的初始化
4 //
5 // Created by Elf Sundae on 10/26/10.
6 // Copyright 2010 Elf.Sundae(at)Gmail.com . All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10 #import "InitExample.h"
11
12 @interface SubClass : InitExample
13 {
14 int age;
15 }
16
17 - (void) setAge : (int) age;
18 - (int) age;
19
20 - (id) initWithFirstName: (NSString *) m_firstName
21 lastName: (NSString *) m_lastName
22 age: (int) m_age;
23
24 - (id) initWithAge: (int) age;
25
26
27 @end
SubClass.m
1 //
2 // SubClass.m
3 // Initializer
4 //
5 // Created by Elf Sundae on 10/26/10.
6 // Copyright 2010 Elf.Sundae(at)Gmail.com . All rights reserved.
7 //
8
9 #import "SubClass.h"
10
11
12 @implementation SubClass
13
14 - (void) setAge:(int)m_age
15 {
16 age = m_age;
17 }
18
19 - (int) age
20 {
21 return age;
22 }
23
24 - (NSString *) description
25 {
26 return [NSString stringWithFormat:@"I am %@ ,and I'm %d years old.",
27 self.fullName,self.age];
28
29 }
30
31 // 指定初始化函数
32 - (id) initWithFirstName: (NSString *) m_firstName
33 lastName: (NSString *) m_lastName
34 age: (int) m_age
35 {
36 if (self = [super initWithFirstName:m_firstName
37 lastName:m_lastName])
38 {
39 age = m_age;
40 }
41 return self;
42 }
43
44 // 重写父类的指定初始化函数
45 - (id) initWithFirstName:(NSString *)m_firstName
46 lastName:(NSString *)m_lastName
47 {
48 // age 默认设为0
49 if (self = [self initWithFirstName:m_firstName
50 lastName:m_lastName
51 age:0])
52 {
53 }
54 return self;
55 }
56
57 - (id) initWithAge:(int)m_age
58 {
59 if (self = [super init])
60 {
61 age = m_age;
62 }
63 return self;
64 }
65
66
67
68
69 - (id) init
70 {
71 // age 默认设为0
72 if (self = [self initWithAge:0])
73 {
74 }
75 return self;
76 }
77
78 @end
79
main
1 #import <Foundation/Foundation.h>
2 #import "InitExample.h"
3 #import "SubClass.h"
4
5 int main (int argc, const char * argv[]) {
6 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
7
8 InitExample *myName = [[InitExample alloc] init];
9 NSLog(@"%@",[myName fullName]);
10
11 InitExample *myName1 = [[InitExample alloc] initWithFirstName:@"Elf"];
12 NSLog(@"%@",[myName1 fullName]);
13
14 InitExample *myName2 = [[InitExample alloc] initWithLastName:@"Sundae"];
15 NSLog(@"%@",[myName2 fullName]);
16
17 InitExample *myName3 = [[InitExample alloc] initWithFirstName:@"Elf"
18 lastName:@"Sundae"];
19 NSLog(@"%@",[myName3 fullName]);
20
21 // 子类
22 SubClass *mySubClass = [[SubClass alloc] initWithAge:22];
23 NSLog(@"%@",mySubClass);
24
25 SubClass *mySubClass1 = [[SubClass alloc] initWithFirstName:@"Elf"];
26 NSLog(@"%@",mySubClass1);
27
28 SubClass *mySubClass2 = [[SubClass alloc] initWithFirstName:@"Elf"
29 lastName:@"Sundae"];
30 NSLog(@"%@",mySubClass2);
31
32 SubClass *mySubClass3 = [[SubClass alloc] initWithFirstName:@"Elf"
33 lastName:@"Sundae"
34 age:22];
35 NSLog(@"%@",mySubClass3);
36
37 SubClass *mySubClass4 = [[SubClass alloc] initWithLastName:@"Sundae"];
38 NSLog(@"%@",mySubClass4);
39
40 [pool drain];
41 return 0;
42 }
总结:
在Cocoa中,分配和初始化是两个分离的操作:来自NSObject的类方法alloc为对象分配一块内存区域并将其清零,实例方法init用于获得一个对象并使其运行。
一个类可以拥有多个初始化方法。这些初始化方法通常是便利方法,可以更容易地实现你希望的对象配置方式。你可以从这些初始化方法中选择一个作为指定初始化函数。所有其他初始化方法应该按照指定初始化函数的形式编写。
在你自己的初始化方法中,需要调用自己的指定初始化函数或者超类的指定初始化函数。一定要将超类的初始化函数的值赋给self对象,并返回你自己的初始化方法的值。超类可能返回一个完全不同的对象。