(译)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用属性的方式存储了待办事项本身的信息——名称,创建日期,完成状态,该类还定义了能做的行为——把待办事项标记为完成或未完成。现在,是时候把这个类添加到应用中了。
(译)Getting Started——1.3.4 Writing a Custom Class(编写自定义的类)的更多相关文章
- [翻译]Writing Custom Wizards 编写自定义的向导
Writing Custom Wizards 编写自定义的向导 You can extend FastReport's functionality with the help of custom ...
- [翻译]Writing Custom Report Components 编写自定义报表组件
摘要:简单介绍了如何编写一个FastReport的组件,并且注册到FastReport中使用. Writing Custom Report Components 编写自定义报表组件 FastRep ...
- Spring Enable annotation – writing a custom Enable annotation
原文地址:https://www.javacodegeeks.com/2015/04/spring-enable-annotation-writing-a-custom-enable-annotati ...
- TypeScript Writing .d.ts files(编写声明文件)
当使用扩展的JavaScript库或者插件API的时候,将需要使用声明文件(.d.ts)来描述库的类型.本文内容将包括如何编写声明文件相关的一些高级概念,然后用一些例子来展示如何将各式各样的概念与声明 ...
- Writing Your Own Widget(自定义组件)
英文地址:http://dojotoolkit.org/reference-guide/1.10/quickstart/writingWidgets.html#quickstart-writingwi ...
- 《gradle 用户指南中文版》目录
gradle 用户指南 版权所有©2007-2017 Hans Dockter,Adam Murdoch只要您不对这些副本收取任何费用,并且进一步规定,每个副本都包含本版权声明,无论是以印刷版还是电子 ...
- WPF: FishEyePanel/FanPanel - 自定义Panel
原文:WPF: FishEyePanel/FanPanel - 自定义Panel 原文来自CodeProject,主要介绍如何创建自定义的Panel,如同Grid和StackPanel. 1) Int ...
- [python 译] 基于面向对象的分析和设计
[python 译] 基于面向对象的分析和设计 // */ // ]]> [python 译] 基于面向对象的分析和设计 Table of Contents 1 原文地址 2 引言 2.1 ...
- 分享书籍[writing idiomatic python ebook]
你是不是总是觉得学了python好久,蓦然回首,总是感觉写的代码不是那么有pythonic的味道.看看别人的代码(django,webpy),再看看自己的代码,觉得就是一java-python的混合体 ...
随机推荐
- soap-学习
1. SOAP 是一种简单的基于 XML 的协议,它使应用程序通过 HTTP 来交换信息. 简单的说:SOAP是用于访问网络服务的协议. 2. 什么是SOAP SOAP 指简易对象访问协议 SOAP ...
- Chrome/FireFox处理JSON的插件
Chrome/FireFox处理JSON的插件 JSON插件 效果对比 对于json的数据如果不编排一下格式查看起来很费劲,今天推荐一款chrome/Firfox下处理json的插件JSON-ha ...
- 理解JS里的稀疏数组与密集数组
一般来说,JavaScript中的数组是稀疏的. 什么是稀疏呢?稀疏也就是说,数组中的元素之间可以有空隙,因为一个数组其实就是一个键值映射.本文解释了如何创建稀疏数组和不稀疏的数组. 1.稀疏数组 创 ...
- IIS服务器与web.config配置优化指南
摘自: http://www.3lian.com/edu/2012/11-13/43890.html .修改IIS最大工作进程数 a. 请考虑以下几点: .每一个工作进程都会消耗系统资源和CPU占用率 ...
- Java 程序员快速上手 Kotlin 11招
收录待用,修改转载已取得腾讯云授权 作者 | 霍丙乾 编辑 | 迷鹿 前言 最近经常会收到一些 "用 Kotlin 怎么写" 的问题,作为有经验的程序员,我们已经掌握了一门或者多门 ...
- iptables不小心把127.0.0.1封了,导致redis连不上
写了个脚本扫描apache日志,自动把恶意攻击者的ip交给iptables给封掉 谁知道一不小心把127.0.0.1也给封了... 直接导致redis无法链接. redis-server服务正常启动, ...
- Servlet3.0使用@WebServlet注解配置问题记录
文档说@WebServlet的配置属性都是可选的,不是必需的. 经实践,将一个Servlet配置成load-on-startup的Servlet时,若只添加loadOnStartup属性,该Servl ...
- Echarts 获取后台数据 使用后台数据展示 饼装图
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head& ...
- python 静态成员变量
python 静态成员变量 python 也可以定义静态成员变量,就是类的变量. 注意python的静态成员变量只能通过 类.变量名 的形式获取 class A: a1 = 0 def __init_ ...
- Spring之替换Bean的返回结果,替换Bean的方法实例
Spring是一个非常强悍的框架+容器,其中有代理模式(动态代理模式)的极致体现.下面是两个比较让人感觉精彩的代码使用,重点关注main方法中的ClassPathXMlApplicationConte ...