(译)Getting Started——1.3.4 Writing a Custom Class(编写自定义的类)

  在开发IOS应用中,当你编写自定义的类时,你会发现很多的特殊场合。当你需要把自定义的行为和数据包装在一起时,自定义的类非常有用。在自定义的类中,你可以定义自己的存储、处理和显示数据的方法。

    例如,IOS Clock应用中的World Clock面板。table view中的单元格需要显示比标准table view单元格更多的显示内容。这就是一个很好的机会来实现一个继承了UITableViewCell类的子类,用于在给定的table view单元格中显示更多的自定义内容。如果你正在设计自定义的类,你或许给某个label添加了outlet用于在信息前显示时间,还可以在单元格的右边,在自定义的时钟前显示图片等。

    本节的主要内容就是让你知道Objective-C的语法和类的结构,这样就可以完成ToDoList应用的剩余行为了。从前面章节已经讨论过的ToDoItem的设计中可以知道,自定义的类在待办列表中扮演着单独的角色。在今天的教程里,你就会实现这个类并把它添加到应用中。

类的申明与实现

    Objective-C中,一个类被分为两部分:接口和实现。接口中精确的定义了外部对象如何使用类中给定类型的对象。换句话说,接口定义了类实例与外部环境之间的接口。实现类中,包含了接口中申明的所有方法的可执行代码。

    对象的设计思路是隐藏内部的实现细节。在Objective-C中,接口与实现通常被分开放置在单独的文件夹中,这样,你只需要让接口对外公开就可以了。使用C语言编程时,通过定义头文件和源文件的方法来把公共的申明与代码的实现细节分开。接口文件的后缀是.h,实现文件的后缀是.m。

接口

    Objective-C中,接口申明的代码如下:

  

@interface ToDoItem : NSObject


@end

 

    上面的代码中,申明了一个名为ToDoItem的类,它的父类是NSObject。

    接口中,公用的属性和行为都定义在@interface申明中。上面的代码中,子类没有指定与父类不一样的东东,因此,ToDoItem的实例可以使用的行为全都继承自NSObject类。所有的对象都会有一个最小行为,因此,所有类都默认继承NSObject(或者NSObject的子类)。

实现

    Objective-C语法中,类的实现如下所示:

#import "ToDoItem.h"


@implementation ToDoItem


@end

 

  如果你在接口中申明了方法,你需要在实现类中实现这些方法。

存储对象数据的属性

    从待办列表项要存储的数据来分析,应该显示待办事项的名称,待办事项创建的时间,和待办事项计划完成的时间。因此,在自定义的ToDoItem类中,你需要在属性中存储这些信息。

    在接口文件(ToDoItem.h)中,申明这些属性,如下所示:

  

@interface ToDoItem : NSObject


@property NSString *itemName;

@property BOOL completed;

@property NSDate *creationDate;


@end

 

    在本例中,ToDoItem类申明了三个公共的属性。除非你再申明了其它的属性,否则,其它的对象只能对这三个属性的值进行读写。

    要申明只读的属性,你需要在属性前再指定限定词。例如,如果你不想其它对象改变待办事项的创建时间,那你需要 这样做:

  

@interface ToDoItem : NSObject


@property NSString *itemName;

@property BOOL completed;

@property (readonly) NSDate *creationDate;


@end

 

    属性可以是私有(private)的,也可以是公开(public)的。当把一个属性设置为私有类型时,其它的类就不能看到和获取它。例如,如果你想跟踪一个代表了项目日期的属性,又不想其它的类获取这个信息,那你可以在类实现(ToDoItem.m)文件的#import语句之后,在类的扩展里添加该属性,如下所示:

  

#import "ToDoItem.h"


@interface ToDoItem ()

@property NSDate *completionDate;

@end


@implementation ToDoItem


@end

 

   使用getter和setter来获取属性。getter返回了属性的值,setter改变了属性的值。访问getter和setter的常见语法是点语法。对于要读写的属性来说,你可以使用点语法来对属性进行读写。如果你有一个对象:toDoItem,它是ToDoItem类的实例,那你可以这样做:

  

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

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

 

方法定义了对象的行为

    方法定义了对象可以做什么。方法是在类中定义的,用于执行任务的代码片断。方法可以获取定义在类中的数据,也可以使用数据来执行某个操作。

    例如,要想给待办事项添加被标记为完成状态的能力,你需要在接口中添加名为markAsCompleted的方法。然后,在实现类中实现这个方法的细节,如下所示:

  

@interface ToDoItem : NSObject


@property NSString *itemName;

@property BOOL completed;

@property (readonly) NSDate *creationDate;

- (void)markAsCompleted;


@end

 

    方法前的-号表明了该方法是一个实例方法,由对象的实例调用,方法前面是一个+号的方法是类方法,类方法由类本身调用。类方法调用的常见例子是类的构造方法,你可以使用类方法获取与类相关的共享信息。

    void关键字表示方法没有返回值。上面的代码中,markAsCompleted方法没有参数。

方法参数

    在方法被调用时,方法里的参数会被当作方法信息的一部分被传递。

    例如,你可以修改上面的代码,把markAsCompleted方法改为有一个参数的方法,这个参数用于决定某个待办事项到底是被标记为已完成还是未完成。这样,你就可以通过这个方法对待办事项设置完整的状态(完成和未完成),而不只是设置完成状态了。

  

@interface ToDoItem : NSObject


@property NSString *itemName;

@property BOOL completed;

@property (readonly) NSDate *creationDate;

- (void)markAsCompleted:(BOOL)isComplete;


@end

 

    如上所示,已经给markAsCompleted方法添加了一个名为isComplete的参数,参数的类型是BOOL。

    如果一个方法有多个参数,那么,方法名称就会被分成几个部分,每个部分都是参数的名称。如果你想给markAsComplete方法添加参数,那该方法的申明应该如下所示:

  

- (void)markAsCompleted:(BOOL)isComplete onDate:(NSDate *)date;

 

    注意:上述代码中,方法的名称是markAsCompleted:onDate:。在实现过程中,当方法被调用时,isComplete和date这两个名字用于获取提供的值,就好像这两个名字就是变量一样。

实现方法

    方法的实现是把相关的代码放在括号内。方法的名称、参数、返回类型必须与接口中定义的一样。

    下面的代码是markAsCompleted:方法的实现:

  

@implementation ToDoItem

- (void)markAsCompleted:(BOOL)isComplete {

   self.completed = isComplete;

}

@end

 

    与属性类似,方法的类型可以是private的,也可以是public的。申明在公共接口中的公共方法可以被其它对象看见和调用,其它对象看不到公共方法的具体实现。私有的方法只是在类的内部可见,也就是说私有的方法只能在类的内部被调用。这种机制非常强大,可以保证添加的类内部行为不会被其它对象调用。

    例如,如果待办事项被标记为完成,那就给completionDate属性设置当前的日期。如果被标记为未完成,就把completionDate属性设置为nil。因为更新待办事项的completionDate属性是一个内部任务,因此,最佳的做法就是写类方法。但是,又得确保其它对象不能调用这个方法——否则,其它对象就可以在任意时间去改变待办事项的completionDate属性了。基于以上的考虑,应该把这个方法设置为private。

    要完成上述内容,你需要更新ToDoItem的实现,在实现中添加私有的setCompletionDate方法,这个方法由类内部的markAsCompleted:方法调用,用于在待办事项被标记为完成或未完成时,更新待办项目的completionDate属性的值。注意:你并没有给接口文件添加任何东东,这是因为你不想让其它对象看到这个方法:

  

@implementation ToDoItem

- (void)markAsCompleted:(BOOL)isComplete {

   self.completed = isComplete;

   [self setCompletionDate];

}

- (void)setCompletionDate {

   if (self.completed) {

       self.completionDate = [NSDate date];

   } else {

       self.completionDate = nil;

   }

}

@end

 

    到现在为止,你使用ToDoItem类已经设计了一个待办事项的基本表现形式。ToDoItem用属性的方式存储了待办事项本身的信息——名称,创建日期,完成状态,该类还定义了能做的行为——把待办事项标记为完成或未完成。现在,是时候把这个类添加到应用中了。

posted @ 2015-06-27 18:10  wchhuangya  阅读(809)  评论(0编辑  收藏  举报