Writing a Custom Class

编写一个自定义类


当你开发iOS app时,你将发现很多情况都需要你写自己的自定义类。当你需要将包含数据的自定义行为进行封装的时候,自定义类会非常有用。在自定义类里,你能定义你自己的行为来存储、手动操作、和现实你的数据。

例如,考虑iOS 时钟 app的世界时钟选项卡。这个在表示图中的表单元需要现实比基本表视图单元更多的内容。这是一个很好的机会来实现子类,这个子类扩展了UITableViewCell的行为,让你现实让表视图单元显示更多的自定义数据。如果你正在设计这个自定义类,你或许会为添加outlets,以便添加在表单元中显示时钟信息的标签视图和显示自定义时钟的图片视图。



这章教你你需要知道的关于Objective-C的语法和未完成实现ToDoList的类结构。它讨论XYZToDoItem的设计,这个自定义类将代表你to-do list上的一个单一项。在第三个教程中,你将真正的实现这个类并添加它到你的app。


Declaring and Implementing a Class

声明和实现一个类

Objective-C类的规范要求要有两个不同的部分:接口和实现。接口准确的指定什么类型的对象要在其他对象中被使用。换句话说,他指定了一个本类的对象和外部世界的一个公共接口。实现部分包括了在接口文件中声明的方法的实现代码。

一个对象应该被设计成需要隐藏它内部实现的细节。在Objective-C里,接口和实现通常放置在单独的文件中,而你只需要使用公共接口。与C代码一样,你定义头文件和源代码文件到单独的公开声明,从实现你的代码的细节。接口文件有.h扩展名,实现文件有.m扩展名。(你将在Tutorial: Add Data中为XYZToDoItem类实际创建这些文件。现在,只需要跟随所有的介绍。)


Interface

接口

Objective-C语法使用声明和类接口,看上去如下所示:


.@interfaceXYZToDoItem : NSObject

.

.

.

.@end

.

本例声明了一个名为XYZToDoItem的类,它继承自NSObject

公共属性和行为是定义在interface声明里的。在这个例子中,没有指定超类,所以唯一行为是XYZToDoItem继承了NSObject。所有的对象需要一个最小的行为,所以在默认下,他们必须继承NSObject(或一个它的子类)。


Implementation

实现

Objective-C的语法用于声明一个类实现,如下所示:


.#import "XYZToDoItem.h"

.

.

.

.@implementationXYZToDoItem

.

.

.

.@end

.

如果你在类接口中声明了任何方法,你需要在这个文件中实现它们。


Properties Store an Object’s Data

属性存储一个对象的数据

考虑什么信息是to-do item需要有的。你或许需要知道它的名字,当它被创建的时候,还有是否它已经完成。在你自定义的XYZToDoItem类中,你将存储这些信息到属性。

这些属性的声明存在于接口文件中(XYZToDoItem.h)。如下所示:


.@interfaceXYZToDoItem : NSObject

.

.

.

.@propertyNSString*itemName;

.

.@propertyBOOLcompleted;

.

.@propertyNSDate*creationDate;

.

.

.

.@end

.

在这个例子中,XYZToDoItem类声明了三个公共属性。这些属性都是完全公开访问的。使用公共访问,其他对象能够读取和改变这些属性的值。

你或许决定声明这些属性不能被改变(也就是说,它是只读的)。指明是否一个属性是规定为只读——其他事情——Objective-C属性声明包含属性的属性( property attributes)。举个例子,如果你不想XYZToDoItem中的创建日期被改变,你应该更新XYZToDoItem类的接口文件如下所示:


.@interfaceXYZToDoItem : NSObject

.

.

.

.@propertyNSString*itemName;

.

.@propertyBOOLcompleted;

.

.@property(readonly)NSDate*creationDate;

.

.

.

.@end

.

属性可以是私有的或者公有的。有时候建立一个私有的属性让其他类不能看到和访问它是有意义的。举个例子,如果你想让追踪一个属性,这个属性代表项的日期,它在被完成的时候标记,而不让其他类访问这个信息,通过把它放置在你的实现文件(XYZToDoItem.m)顶部的类扩展(class extension)中。


.#import "XYZToDoItem.h"

.

.

.

.@interfaceXYZToDoItem()

.

.@propertyNSDate*completionDate;

.

.@end

.

.

.

.@implementationXYZToDoItem

.

.

.

.@end

.

你使用getters和setters方法来访问属性。一个getter方法返回一个属性的值,一个setter方法改变这个值。通常用点符号(dot notation)语法来访问getter和setter方法。对于读和写来访问属性,你可以使用点符号来操作属性的值。如果你有XYZToDoItem类的toDoItem对象,你可以用下面的方法操作:


.toDoItem.itemName=@"Buy milk";//Sets the value of itemName

.

.NSString*selectedItemName=toDoItem.itemName;//Gets the value of itemName

.


Methods Define an Object’s Behavior

用方法定义对象行为

用方法定义对象能做什么。方法是一段代码,它是你定义的执行一个任务或类的子程序。方法访问存储在类中的数据并能使用这些信息来执行某种操作。

举个例子,给to-do item (XYZToDoItem) 一个能力是来给完成的项做标记,你能在类接口文件中添加markAsCompleted方法。之后,你将在类的实现文件中实现这个方法的行为,具体的描述见Implementing Methods


.@interfaceXYZToDoItem : NSObject

.

.

.

.@propertyNSString*itemName;

.

.@propertyBOOLcompleted;

.

.@property(readonly)NSDate*creationDate;

.

.-(void)markAsCompleted;

.

.

.

.@end

.

在方法名之前的 符号(-)表明这是一个对象方法,它能被该类的对象调用。这个减号有别于类方法,类方法用加号(+)表示。类方法能被该类自身调用。类工厂方法是类方法常见的例子,在Working with Foundation中你已经学过它了。你也能使用类方法来访问一些类共享的相关信息。

关键字通常被放在声明开始前的圆括号里,表明这个方法没有返回值。markAsCompleted方法接收参数。在Method Parameters中将讨论更多参数的细节。


Method Parameters

方法参数

你申明带参数的方法用来在你调用方法的时候传递一些信息。

举个例子,你可以修改前面的方法代码片段markAsCompleted来接受一个参数,这个参数将判断项目是否已经标记为完成或未完成。通过这种方式,你能切换项目的完成状态,而不是只用来对它设置完成。


.@interfaceXYZToDoItem : NSObject

.

.

.

.@propertyNSString*itemName;

.

.@propertyBOOLcompleted;

.

.@property(readonly)NSDate*creationDate;

.

.-(void)markAsCompleted:(BOOL)isComplete;

.

.

.

.@end

.

现在,你的方法接收了一个参数,isComplete,它的类型是BOOL

当你涉及到带参数名的方法时,你需要包含方法名字的一部分,所以现在这个方法的名字更新为markAsCompleted。如果一个方法拥有多个参数,这个方法的名字是由参数名隔开的。如果你想添加另一个参数到这个方法,它的申明看上去如下所示:


.-(void)markAsCompleted:(BOOL)isCompleteonDate:(NSDate*)date;

.

在这里,方法名字是写成。isCompletedate被用在实现访问相应的值,这些值在方法被调用的时候被提供,就像变量一样。


Implementing Methods

实现方法

方法实现使用花括号来包含相关的代码。方法的名字必须对与接口文件中对应的名字相同,而且参数和返回类型必须完全匹配。

这儿有一个你在XYZToDoItem类接口中添加的markAsCompleted方法简单的实现:


.@implementationXYZToDoItem

.

.-(void)markAsCompleted:(BOOL)isComplete{

.

.self.completed=isComplete;

.

.}

.

.@end

.

就像属性一样,方法可以分为私有和公有。公有方法在公有接口中申明,所以可以被其他对象调用。它们相应的实现放置在实现文件中,不能被其他对象看见。私有方法只是在类中实现,这就意味着他们只能在类中被调用实现。这是一个强有力的机制,用来为类添加内部行为,且不能够被其他对象访问。

例如,你若想保持一个to-do 项的completionDate更新,如果to-do项标记为完成,设置completionDate为当前的日期。如果得到未完成标记,设置completionDatenil,因为它还没有完成。因为更新to-do项的completionDate是它自己独立的任务,最好方法是为自己写方法。然而,重要的是它确保其他对象不能调用这个方法——否则,其他对象能够在任何时候设置to-do 项的completionDate。因为这个原因,你要把这个方法设为私有。

现在,来更新XYZToDoItem的实现方法,用来包括私有方法setCompletionDate,它在markAsCompleted中被调用,来更新to-do项的completionDate无论它被标记为完成或者未完成。注意你不要在接口文件中添加任何东西,因为你不想让其他对象看到这些方法。


.@implementationXYZToDoItem

.

.-(void)markAsCompleted:(BOOL)isComplete{

.

.self.completed=isComplete;

.

.[selfsetCompletionDate];

.

.}

.

.-(void)setCompletionDate{

.

.if(self.completed){

.

.self.completionDate=[NSDatedate];

.

.}else{

.

.self.completionDate=nil;

.

.}

.

.}

.

.@end

.

现在,你已经定义了一个基本的使用XYZToDoItem类的to-do list项的表示。XYZToDoItem存储关于它自己的信息——名字、创建日期、完成状态——以属性的形式,并且它定义了它能做什么——对是否完成进行标记——使用方法。这是你在接下来的ToDoList教程中需要完成的程度。但是,你总是能尝试通过添加你自己的属性和方法到类来在app中集成新的行为。

Working with Foundation

Tutorial: Add Data

Copyright  2014 Apple Inc. All rights reserved. Terms of Use | Privacy Policy | Updated: 2013-10-22