在开发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用属性的方式存储了待办事项本身的信息——名称,创建日期,完成状态,该类还定义了能做的行为——把待办事项标记为完成或未完成。现在,是时候把这个类添加到应用中了。

(译)Getting Started——1.3.4 Writing a Custom Class(编写自定义的类)的更多相关文章

  1. [翻译]Writing Custom Wizards 编写自定义的向导

    Writing Custom Wizards  编写自定义的向导   You can extend FastReport's functionality with the help of custom ...

  2. [翻译]Writing Custom Report Components 编写自定义报表组件

    摘要:简单介绍了如何编写一个FastReport的组件,并且注册到FastReport中使用.   Writing Custom Report Components 编写自定义报表组件 FastRep ...

  3. Spring Enable annotation – writing a custom Enable annotation

    原文地址:https://www.javacodegeeks.com/2015/04/spring-enable-annotation-writing-a-custom-enable-annotati ...

  4. TypeScript Writing .d.ts files(编写声明文件)

    当使用扩展的JavaScript库或者插件API的时候,将需要使用声明文件(.d.ts)来描述库的类型.本文内容将包括如何编写声明文件相关的一些高级概念,然后用一些例子来展示如何将各式各样的概念与声明 ...

  5. Writing Your Own Widget(自定义组件)

    英文地址:http://dojotoolkit.org/reference-guide/1.10/quickstart/writingWidgets.html#quickstart-writingwi ...

  6. 《gradle 用户指南中文版》目录

    gradle 用户指南 版权所有©2007-2017 Hans Dockter,Adam Murdoch只要您不对这些副本收取任何费用,并且进一步规定,每个副本都包含本版权声明,无论是以印刷版还是电子 ...

  7. WPF: FishEyePanel/FanPanel - 自定义Panel

    原文:WPF: FishEyePanel/FanPanel - 自定义Panel 原文来自CodeProject,主要介绍如何创建自定义的Panel,如同Grid和StackPanel. 1) Int ...

  8. [python 译] 基于面向对象的分析和设计

    [python 译] 基于面向对象的分析和设计 // */ // ]]>   [python 译] 基于面向对象的分析和设计 Table of Contents 1 原文地址 2 引言 2.1 ...

  9. 分享书籍[writing idiomatic python ebook]

    你是不是总是觉得学了python好久,蓦然回首,总是感觉写的代码不是那么有pythonic的味道.看看别人的代码(django,webpy),再看看自己的代码,觉得就是一java-python的混合体 ...

随机推荐

  1. jQuery最佳实践:如何用好jQuery

    一.用对选择器 在jQuery中,你可以用多种选择器,选择同一个网页元素.每种选择器的性能是不一样的,你应该了解它们的性能差异. (1)最快的选择器:id选择器和元素标签选择器 举例来说,下面的语句性 ...

  2. CF无法全屏怎么办

    方法1:把桌面的分辨率调成800X600,然后运行CF就全屏了,接着再退出游戏,把桌面重新调回原来的分辨率. 方法2:在运行中输入regedit.可以打开打开注册表编辑器,定位到HKEY_LOCAL_ ...

  3. Gstreamer学习

    Gstreamer学习笔记----Gstreamer架构设计思想 http://blog.csdn.net/tx3344/article/details/7497434 Gstreamer到底是个啥? ...

  4. jQuery EasyUI API 中文文档 - 表单(form补充)

    继承(表单验证) 第一个参数如果是true那么就算key相同也会接着追加,相反怎会覆盖 $.extend([bool],obj,obj1); var obj = {name:"zhangsa ...

  5. h5移动端百分比

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 001-使用idea开发环境安装部署,npm工具栏,脚本运行

    一.概述 参看官方文档:https://ant.design/docs/spec/introduce-cn 其中包含了设计价值观.设计原则.视觉.模式.可视化.动态等. 其中Ant Design 的 ...

  7. [Spring MVC - 2A] - java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)

    严重: Servlet.service() for servlet [springMVC] in context with path [/ExceptionManageSystem] threw ex ...

  8. XAudio2学习之混音

    XAudio2不仅能够进行採样率转换.还能够进行混音.所谓混音就是将多路音频混合成一路进行输出.混音主要是IXAudio2SubmixVoice进行此项功能. 数据由IXAudio2SourceVoi ...

  9. Unity 使用 Stripping Level == Use micro mscorlib 导致 MD5.Create() 返回NULL

    这几天在弄资源更新,昨天导出Android APK 到手机上測试,发现MD5 校验的时候一直出错.打出Log 又一次导包測试发现 MD5.Create() 返回NULL 可是在电脑上是好好的,在手机上 ...

  10. Public Private Protect Inheritance and access specifiers

    In the previous lessons on inheritance, we've been making all of our data members public in order to ...