跳转到内容

Cocoa 编程/Objective-C 基础

来自维基教科书,开放的书籍,为开放的世界

Objective-C 是 Cocoa 应用程序的原生语言。它是 ANSI C 的面向对象超集,允许开发人员在程序中包含“纯 C”语句和代码。任何 ANSI C 程序都是有效的 Objective-C 程序。

Cocoa 中使用的 Objective-C 与“纯”Objective-C 有些不同,因为 Cocoa 运行时系统定义了一个新的根类,NSObject。所有 Cocoa 对象都应该是 NSObject 的后代,以便从其改进的内存管理模型中获益。

NSObject 在头文件 <Foundation/NSObject.h> 中定义。

NSObject 生命周期

[编辑 | 编辑源代码]

要创建一个 NSObject,向其类发送 allocnew 消息

id anObject = [NSObject new];  // Creates and returns an initialized object

id anotherObj = [NSObject alloc];   // Not yet ready for use...
anotherObj = [anotherObj init];     //...now it is.

// good style: combine alloc and init:
id oneMoreObj = [[NSObject alloc] init];  // identical to using new

尽管“new”和“alloc 后跟 init”方法看起来相同,但 Apple 文档似乎更喜欢后一种方法。这使开发人员能够分别覆盖 allocinit 以实现特定结果(如果需要)。

请注意,初始化对象有时可能会失败:例如,包含初始化数据的文件可能不可用。在这种情况下,init 将返回 nil。因此,在使用对象之前始终检查 init 的返回值!

对象初始化后,就可以使用了。要使用对象,向其发送消息

[anObject aMessage];

如果对象理解该消息,它将对其做出反应。否则,将生成一个陷阱。

当不再使用对象时,必须将其释放。要释放对象,向其发送 release 消息。

[anObject release];

这将导致对象的销毁(除非它仍在其他地方使用,请参阅Cocoa 内存管理了解详细信息)。

当对象即将被销毁时,它将收到 dealloc 消息。如果对象保留了任何资源,现在应该释放它们。

扩展 NSObject

[编辑 | 编辑源代码]

Cocoa/Objective-C 应用程序中的所有类都应该是 NSObject 的派生类。因此,在定义新类时,您应该遵循一些基本规则

  • NSObject 派生
  • 直接或从派生类派生
  • 定义初始化器和析构器
  • 调用基类初始化器和析构器

NSObject 派生

[编辑 | 编辑源代码]

要将您的类创建为 NSObject 的子类,请按如下方式定义它(在接口定义文件“MyClass.h”中)

#import <Foundation/NSObject.h>

@interface MyClass : NSObject
{
@private
  /* instance variable declarations */
  AnotherClass* myMember;
}
/* method declarations */
@end

定义初始化器和析构器

[编辑 | 编辑源代码]

初始化器是初始化对象的方法。在 Cocoa 中,NSObject 的初始化器称为 initNSObjectinit 方法不知道用户定义的类,因此无法正确初始化它们的实例。因此,必须为您的类编写一个初始化器方法。如果初始化不需要任何参数,则要定义的方法称为 init(即,您应该覆盖基类初始化器)。这使得可以使用从 NSObject 派生的 new 类方法创建您的类的实例

MyClass* myObj = [[MyClass alloc] init];   // allocate and initialize the object

上面的代码创建了一个新的 MyClass 实例。由于 MyClass 没有名为 allocinit 的方法,因此消息会自动发送到其基类。

要覆盖您的类的初始化器,可以选择在接口文件中定义它

/* In MyObject.h, in the method declarations part */
- (id) init;

并在.m 文件中实现它

/* In MyObject.m */
@implementation MyObject
- (id) init
{
    /* first initialize the base class */
    self = [super init]; 
    /* then initialize the instance variables */
    myMember = [AnotherClass new];
    /* finally return the object */
    return self;
}
@end

如果初始化需要其他参数,您应该定义一个类似 initWithParam: 的初始化器,例如

- (id) initWithMember: (AnotherClass) member
{
    self = [super init];
    myMember = [[AnotherClass alloc] initWithValue: member];
    return self;
}

即使这样,也建议定义一个“默认”初始化器,它使用合适的默认参数调用您的 initWithXXX 方法

- (id) init
{
    return [self initWithMember: someDefaultValue];
}

析构器是一个负责释放对象持有的所有资源的方法。析构器在释放对象之前被调用,从而确保一切被正确清理。在 Cocoa 中,析构器方法是 dealloc。每个持有任何资源的类都应该定义一个 dealloc 方法。例如

- (void) dealloc
{
   [myMember release];
   [super dealloc];
}

调用基类初始化器和析构器

[编辑 | 编辑源代码]

当一个类从另一个类派生(例如,MyClassNSObject 派生)时,从它创建的实例不仅是派生类的实例,也是基类的实例。这称为is-a 关系。派生类是基类的扩展:它可以做基类不能做的事情,但它可以做基类能做的一切。因此,派生类的对象总是包含基类对象包含的一切。如果 NSObject 包含一个保留计数成员变量,那么 MyClass 对象也会包含它。因此,在初始化和销毁派生对象时,需要初始化和销毁派生对象的“基类部分”。

要初始化对象的基类部分,请编写

self = [super init];

到您的类的初始化器的开头。要销毁对象的基类部分,请编写

[super dealloc];

到您的类的析构器的结尾

更多信息

[编辑 | 编辑源代码]

有关 Cocoa 中 Objective-C 的更多信息,请参阅

华夏公益教科书