【总结回顾】iOS Apprentice Tutorial 2:Checklists(一)

书籍封面 iOS Apprentice 2 Checklists

这本书看了几遍也记不清了,总之好多遍,第一遍照着书中的代码敲了一遍,结果还出现了好多bug,删掉重新敲,没有问题之后,又看了一遍,理解一下大体意思,再看的时候稍微自己设计了一个相似的应用,然后利用学到的知识开发出来,功能运行没有问题,就是界面太丑了。

iOS Apprentice系列一共有四本,这是第二本。目前看的这版是第四版,V4.1,升级到了iOS 9、Xcode7和Swif2.0,适合完全没有编程基础的人和初学者来阅读。这本书的可以在RayWenderlich官网注册后订阅Newsletter免费获得:获取地址。需要花钱购买,价格不菲,美国本来书就贵,美元汇率的原因导致随笔买本书就三四百RMB出去了,肉疼。

这本书比起第一本来说,难度上立马上了一个层次,不多看几遍,还真有时候会跟不上节奏。我总感觉需要看上十遍八遍的方能放心。

好了,废话不多说,下面就开始总结一下书中的重点知识。

1. Upside down

在设计App的时候,尽量不使用这个方向。如果你的App支持这个方向,Home按钮可以出现在上方,当用户接到电话时会带来不便,麦克风会在上方离职嘴巴比较远,而不是下面靠近嘴巴的地方。
不过对于iPad应用来说,最好是能够支持全部的四个方向,毕竟人们在使用iPad时,一般没有接电话的需求。(不过类似facetime微信视频之类App在iPad可能需要注意一下麦克风了)

不勾选upside down

2.UItableView object

这个控件用来展示清单列表。有两种风格: “plain” 和 “grouped”,请见下图(左边是plain风格,右边是grouped风格):


两种风格: “plain” 和 “grouped”

数据是以行的形式展示,一行(row)就是一条数据。
你可以有成千上万行的数据,尽管这种设计模式我们不推荐,大部分用户会讨厌一直往下滑成千上万行才能找到他们想要看到的内容。

UItableView控件使用cell来展示数据。一个cell对应一个row,但是cell和row不完全相同。首先cell是一个view,cell的数量,是由在某一刻,可以看到的row(行)的数量决定的。加入在iPhone屏幕上一次最多能展示10rows,想看到更多row就需要往上滑动屏幕,这时候,这里只有10个cell,尽管实际上可能会有成千行(row)数据。

当一行数据被往上移动移出屏幕不可见后,cell会被重复利用,接着用来展示新出现在屏幕中的那些行数据。下图展示了row和cell的区别:


row和cell的区别

在过去,你需要写好多代码才能复用cell,但是现在Xcode给出了一个非常有用的特性名为prototype cells,可以让你在界面上直接设计cell,然后复用cell。

创建cell的最简单的方法:
1.在storyboard中添加一个prototype cell;
2.在prototype cell上设置它的reuse identifier;
3.调用tableView.dequeueReusableCellWithIdentifier(forIndexPath)方法

3. The data source(数据来源)

使用UITableView首先需要你把storyboard中的UITableView和对应的.swift文件建立关联,同时也需要遵守data source protocol。

UITableView和对应的.swift文件建立关联最快的方法:
在storyboard中选中UITableView,同时按住Control键,鼠标拖向红点(见下图)

当然了,如果你在创建.swift文件的时候,SubClass选择了UITableViewController,Xcode会自动帮你建立关联(delegate和data source都自动建立)。如果你选择的是普通的UIViewController,那么就需要使用上图中的方法手动建立。

除了鼠标拖动,还有代码方法:
delegate = self

遵守data source protocol
协议中有2个方法是必须有的,其他的方法可选。
下列代码中的2个方法是必须要有的:

override func tableView(tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
    return 1
}

override func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("ChecklistItem", forIndexPath: indexPath)
    return cell
}

至于为什么必须要有这两个方法,看下图,下图中UITableViewDataSource是一个协议protocol,我用红色线框和黄色线框标注出来了,红色是public func,黄色是optional public func。


public protocol UITableViewDataSource

综上所述,分为3步吧:

  1. 表示当前的这个view controller(一般就是.swift文件)是你(UITableView)的data source(数据来源),当我们使用delegate = self时,我们就把view controller(视图控制器,以.swift结尾的文件)和UITableView连接起来了。
  2. 当table view需要知道自己有多少行时,就会发给controller一个“numberOfRowsInSection”的message,来获取当前table view一共有多少行。
  3. 当table view需要知道自己某一行呈现哪些内容时,就会发给controller一个“cellForRowAtIndexPath” 的message,来获取这当前行cell的数据。

你会在iOS中经常看到这种模式:一个对象代表另外一个对象做一些事情。在这里的例子中,ChecklistViewController是给table view提供数据,不过只有在table view请求的时候才会提供。

4. Return语法

在上面的代码中,numberOfRowsInSection方法中返回了数值1,表示当前table view只有一行数据。

return语法在swift中非常重要,return允许一个方法能够将数据返回给方法的调用者(caller)。在这里的例子中,调用者(caller)就是UITableView对象,UITableView对象想知道table里有多少行。

返回的数值经常被叫做是方法的结果。

5. 调用次数(重点!重点!!重点!!!)

当我们使用tableView(numberOfRowsInSection)方法时,如果返回值是5(return 5),那么实际上你是在让table view显示5行。

同时,table view会把“cellForRowAtIndexPat”消息发送5次,一行一次。

如果不理解这一点,在后面使用tableView(cellForRowAtIndexPath)方法时,容易出错或者不知所措~

6. Index paths讲解

什么是index path?

首先NSIndexPath是一个对象(object),这个对象用来指出table中某个具体的行(row),NSIndexPath里面包含了row number(行数)和section number(区域数),仅此两个。当tableview需要获取某个cell的数据data source时,你可以通过indexPath.row属性查找row number,然后找出当前cell到底想获取哪行row的数据。

table也可以将rows行分布到不同的section中,例如在手机通讯录中,可以通过姓氏来排列组合,所有的同一姓氏联系人为一个section。

想要找出某row属于哪个section,可以使用indexPath.section属性。

顺便说一下,NSIndexPath的前缀NS是NextStep的缩写,带有NS前缀的object都是由Foundation框架提供的。NextStep是一个操作系统,是Mac OS X 和iOS的前身。

7. Tag

Tag就相当于是用数字做的标识符(identifier),我们之前使用的identifier都是自己输入的字符串,Tag相当于是用数字做identifier,这样使controller(.swift文件)能够知道自己控制的是storyboard上哪个控件。Tag的默认值是0,所以当你使用Tag时,数字要大于0,

为什么在用cell时要用tag呢?我们之前学会的control拖动法建立Outlet连接在这里为什么不能用?
回答:有时候table上有很多个cell,每个cell都有自己的label等控件,如果我们使用Control拖动法建立outlet连接,这个outlet只是表示当前cell的label,而table上有很多个cell。而且label控件是输入cell的,不是输入View controller,所以不能使用outlet。

我觉得这里有必要附上英文原文,以防我理解有误,引起误会:
Answer: There will be more than one cell in the table and each cell will have its ownlabel. If you connected the label from the prototype cell to an outlet on the view controller, that outlet could only refer to the label from one of these cells, not all of them. Since the label belongs to the cell and not to the view controller as a whole,you can’t make an outlet for it on the view controller. Confused? Don’t worry aboutif for now.

8. 小知识点

  • 从零开始,不是从一开始。
    计算机计算都是从零开始的,第一个数值是0,第二个数值是2,在Array类型中最常见。如果数组中有4个数字,那么序列就是0,1,2,3。一开始可能不太习惯,毕竟我们平时都是从一开始数数的,不过这就是电脑数数的方式,习惯就好。
  • 取模运算,求余数,符号是%。

9. 奇怪的崩溃

如果你的程序奇怪的崩溃了,首先你要确认一下你是否不小心在代码中设置了一个断点(breakpoint)。断点是一种调试代码的工具,能让你的程序在执行到某行代码时停止编译,同时显示Xcode的debugger窗口,看起来像是程序崩溃,其实只是程序停止执行。

断点就是下图中左边边界上的蓝色箭头,箭头方向朝右:

断点 breakpoint

10. 用户体验的小细节(细节决定成败)

当你点击某行cell后,这行会显示灰色。然后灰色就会一直存在,直到你点击另外一行,另外一行变灰色。如果想在点击时灰色,手松开后灰色就消失不见,可以使用table view中的delegate中的方案来实现。

我们之前了解到,cell的显示内容也就是数据由data source控制,那么用户点击cell或者和cell的其他手势交互则由delegate控制。

11. 委托模式 The delegation pattern

在iOS中,delegation的概念非常常见。一个object常常借助另外一个object来实现某个任务,这样做的好处很多,因为每个object只需要做自己最擅长的事情,然后让其他的object做它们更擅长的事情,这种理念在table view中得到了很好的提现。

因为不同的App对于自己的数据有不同的要求,所有table view必须具有处理各种不同类型数据的能力。为了不让table view过于复杂,UIKit的设计者选择委托其他对象(也就是data source)来完成填充cell显示内容这项任务。

table view不关心谁是它的data source,也不关心目前处理的数据是何种类型,只要这个data source能够把消息发送给cellForRowAtIndexPath,table view收到一个cell作为返回值,就行了。这种模式能够让table view更轻盈,table view把处理数据的责任转给了:你的代码。

同样的,table view也能识别出用户点击了某行row,但是之后要做出哪些事情来回应用户的点击行为呢?在我们这本书checklist应用中,点击之后是出现一个对勾,但是其他的App会有不同的反应。

使用委托delegate,table view需要做的只是发送消息而已,比如消息是:一个点击事件发生了,然后让delegate处理之后的事情。

override func tableView(tableView: UITableView,didSelectRowAtIndexPath indexPath: NSIndexPath) {

    tableView.deselectRowAtIndexPath(indexPath, animated: true)

}

通常情况下只需要一个delegate就可以了,但是table view有两个delegate:UITableViewDataSource处理数据,UITableViewDelegate处理点击事情和其他事件。

12. tableView.cellForRowAtIndexPath()tableView(cellForRowAtIndexPath)区别

override func tableView(tableView: UITableView,didSelectRowAtIndexPath indexPath: NSIndexPath) {
  
   if let cell = tableView.cellForRowAtIndexPath(indexPath) {
        if cell.accessoryType == .None {
            cell.accessoryType = .Checkmark
        } else {
            cell.accessoryType = .None
        }
}
    tableView.deselectRowAtIndexPath(indexPath, animated: true)}

获取被点击的Row的NSIndexPath

if let cell = tableView.cellForRowAtIndexPath(indexPath)

为了找到这行cell,你需要调用tableView.cellForRowAtIndexPath()方法,你需要意识到,这和之前在data source中方法tableView(cellForRowAtIndexPath)不是一回事,这点很重要。尽管从方法名字上看起来挺像的,但是这两个方法是不同对象中的不同的方法,达成不同的任务。这看起来很容易让人混淆,对吧?

data source中tableView(cellForRowAtIndexPath)的方法是创建或者复用cell,你永远不会调用这个方法,只有UITableView可以调用data source方法。

tableView.cellForRowAtIndexPath()返回的是cell对象,但是这个cell是当前被展示在屏幕上的某一行(row)所在的cell。tableView.cellForRowAtIndexPath()不会创建新的cell。如果当前界面上没有所需的cell,就会返回一个nil值。

记得我在之前的章节中说过,方法的命名要简洁明确有描述作用吗?UIKit在这方面做的一直不错,但是这两个方法是一个特例,两个相同的名字用在了不同的地方,这样会给开发者带来困惑和麻烦。要小心这个坑 ,别跳进去了!

13. UITableViewController的优势

在这图中可以看到,data Source和delegate都已经连接到对应的view controller中了,这是 UITableViewController的标准设置,如果你使用的是 UIViewController,就需要手作关联data source和delegate了。

关联data source和delegate
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容