先祝各位假期愉快喽。不知有多少同学和我一样计划把这8天当中的多数时间花在“宅”上;做做博客和小项目,看看live视频,录点demo出来,太赞了这日子。
话说这里我要长出口气先。今次选做的译文蛮科普的,也真是蛮长的,还好之前几天就开始着手来做,也在微博上做了预告;搞到这两天觉得简直是没有尽头的样子。
我之前几个月花了蛮多时间在iOS应用开发的学习上,到目前为止感觉也仍只是入门而已,所以真心觉得这一篇文章即使再长,也无法让人从零开始学会怎样开发一款应用。但之所以建议和我一样的交互或视觉设计师同学们来阅读,主要目的是让我们自己在头脑里建立开发意识,了解这摊子事情大体是怎么一回事。如果你有兴趣,以此为起点,通过学习逐渐掌握了开发技能,这自然不坏;但更实际的效用,我个人看来还是在平时的工作当中,在打造设计方案的过程中,可以结合具体的开发可行性进行考虑和评估。另外,当程序员同学告诉你哪些不能做的时候,我们自己心里也可以有个底;这事不用说太细,大家都明白。OK废话不多说,进入正文。
作为一名交互或视觉设计师,你希望顺应当前大环境的发展趋势,向移动领域拓展自己的视野和能力,于是决定挽起袖子学习iOS应用开发。兴奋之余,你开始做一些初步的研究,但是很快发现,除非自己有足够丰富的编程经验,否则要实现目标还真不是件易事。
确实是这样。苹果提供的开发文档主要是面向技术人员的,市面上多数iOS开发书籍都会一上来就问你是否掌握了足够的Objective-C知识,而网上各种教程的质量又参差不齐,其中有不少还是面向着很旧版本的iOS系统及开发工具的。
本文的目的就是帮助各位设计师在最短的时间内,以实战的方式探索iOS应用开发工具及相关的基础知识。我们将一同了解应用开发流程中的一些重要环节,包括理论讲解及方法演示,即使你没什么编程经验也没问题。
我们的实战案例是一款非常简单的、用来展示设计作品的应用,如下图所示:
本地(原生)开发方式
所谓“本地”,即是指通过苹果原生的开发工具(SDK)及Objective-C语言开发iPhone和iPad应用的方式。在我们对这套方法进行探索之前,最好稍微花点时间了解一下还有哪些替代方案,以及我们之所以选择原生开发方式的原因。
也许很多人已经听说过Web App及“混合型应用”这样的说法,这些就是所谓的“替代方案”。我们确实可以使用基于HTML5、CSS、JavaScript的Web前端开发技术打造应用,这其中最为常见的解决方案包括Titanium Mobile、PhoneGap、jQuery Mobile、Sencha Touch等框架。通过这种方式开发的应用通常具有很好的跨平台特性。(推荐阅读:前端开发者的跨平台移动应用开发策略及工具)
不过,通过这种非原生方式开发的应用有着明显的弊端。基于浏览器(Web App)或“原生应用壳”(混合型应用)的运作方式使它们的效率无法与本地应用媲美,而且对硬件功能的访问及利用能力也是非常有限的。此外,代码框架本身也是需要学习的,它们有着各自不同的使用方式,在框架之外还有各种扩展库需要摸索。另外,框架本身的质量和成熟程度也是必须考虑的因素。
还有其他一些第三方开发方案可以考虑,例如Cocos 2D for iPhone和PugPig。这类方案允许你将框架文件与Objective-C对象建立关联,以达到特定的目标,例如创建游戏或杂志类应用等。要使用这类技术,你最好也要对苹果本地开发工具包具有基本程度的了解。
准备工作
正式起步前的准备工作包括两方面:
- 硬件:一台运行着最新或新近版本OS X系统的Mac机,包括MacBook(Pro/Air)、Mac mini、iMac或是Mac Pro均可。
- 软件:苹果的Xcode应用。
Xcode可以从Mac应用商店(Mac App Store)或是苹果的开发者站点中免费下载到,大约1.5GB的样子。
图片资源
在等待Xcode下载完成的过程中,我们可以同步开始图片方面的工作。
由于要为普通屏幕(320×480)和Retina屏幕(640×960)各自准备一套图像资源(最新的iPhone5规格为640×1136),我们应该在Photoshop中尽量多的使用矢量图形(vector shape)、图层样式(layer style)以及智能对象(smart object)等技术,以确保图像的无损缩放。比较合理的流程是从Retina版本入手进行构建,然后等比缩放到普通版本的规格。在缩放过程中,一些元素的细节有可能发生变形,记得做好手动调整。
另外,我们还可以在网上找到很多原生风格的iPhone界面PSD模板,其中比较著名的一款是来自Teehan和Lax的iPhone 4 GUI PSD。如果要打造的应用在界面方面以iOS原生风格为主,那么这类模板可以帮助我们节省掉很多时间。即使你更倾向于定制化的用户界面,这些模板同样可以在控件规格、布局规则等方面提供精确的参考。(相关阅读:先了解规则,再寻求创新 - 关于iOS应用界面自定义)
在Photoshop或是你更习惯的图像编辑工具中创建一个新文档,规格如下:
- 尺寸:640×960(pixels)
- DPI:72
- 色彩模式:RGB
由于本文的焦点主要将集中在开发的基础知识上,所以在视觉设计方面不做深入探讨。更多关于iOS界面设计技术及流程方面的信息,可以参考Marc Edwards的Designing for iPhone 4 Retina Display一文。
关于图片导出的小贴士
- 虽然你可以在应用中使用多种格式的图片,不过鉴于alpha通道及无损压缩等方面的考虑,我们最为推荐的仍是PNG格式。
- 多数情况下,要将按钮导出为不包含文案的背景图片,以便更加灵活的在开发环境中调整文字属性,或是对多语种进行支持。
- 对于按钮的背景图片,要确保实际按钮的部分(不包括阴影或外发光等效果的区域)处于背景图片的正中,因为我们在Xcode的Interface Builder当中很难对背景图片及前景文字之间的位置关系进行精密的调整。很多时候,我们需要在制作背景图片的过程中,在按钮的另外一侧添加一块空白的区域,以弥补阴影效果所占据的空间,确保按钮自身处于正中央。
- 在设计方案允许的情况下,尽可能将那些在视觉上叠加在一起的元素直接保存在一张背景图片当中,而不要留到开发环节里再进行层叠处理,否则成本将会变的很高。另外,这样做也有助于减少资源文件的数量,提高应用运行的效率,减少内存占用。只有那些需要对用户行为进行交互响应的界面元素需要独立的背景图片或是动画效果。
- 在所有适用于Retina屏的图片文件名中增加特殊的后缀“@2x”作为标示,使系统能够进行识别:
- image.png:适用于普通屏幕。
- image@2x.png:适用于Retina屏幕。
- 可以尝试使用SuperSlicr这样的自动化批处理脚本对PSD中的UI元素进行格式化及导出。
- 所有的资源文件都会保存在app包(app bundle)的同一个路径当中,所以文件名不能有重复的情况。
- Photoshop不大擅长对PNG图片进行压缩。可以试着使用imageOptim这样的工具减小图片尺寸,然后再导入到Xcode当中。另外,Xcode本身也会对导入过来的图片进行一定程度的压缩,不过有时反而会增加图片的尺寸。
Xcode概览
Xcode已经安装好了叭?
接下来我们去下载一套用于本次案例学习的模板文件,其中包括一些PSD、PNG资源,还有一些用来起步的代码文件。进入里面的Begin Here文件夹,找到Portfolio.xcodeproj文件,双击打开。
文件加载成功之后,点击左侧导航栏(Navigator)中的项目(Portfolio,1 target,iOS SDK),这时我们就可以在编辑区中看到这个项目的概况信息了,如下图所示。关于这些概况信息的用处,我们稍后解释。
点击左侧导航栏当中项目名称旁边的箭头,我们可以看到一个资源列表,里面包含了当前项目所涉及到的所有资源文件,例如代码和图片等。我们把注意力放在Portfolio路径当中,其中有三个类型的文件:
- .h文件:头文件(header,也可称为interface文件)。
- .m文件:消息文件(message,也可称为implementation文件)。
- .xib文件:在Interface Builder中进行界面可视化编辑的XML文件,出于历史原因,通常也被称为NIB文件。
中间编辑区(Editor)所呈现的内容会根据当前正在执行的任务而发生变化。当我们像之前那样点击了导航栏中的项目名称时,这里展示的就是目标概况(Target Summary),其中包括当前应用的一些基本信息,例如设备类型、iOS版本、屏幕定向方案等等。此外,应用的图标及加载图片也是在这里进行设置的;我们将会在后文中进行演示。
在导航栏中单击Portfolio路径中的AppDelegate.m文件,编辑区就会相应的进入代码编辑状态。
接下来单击Portfolio路径中的MainWindow.xib文件,这时编辑区所呈现的就是用于编辑用户界面的Interface Builder,如下图所示。我们通常会在这里对应用界面做最基本的构建。
右侧的检查器(Inspector)当中共有6组工具,其中后面4组是开发工作当中最常用的,从右到左依次为连接检查器(Connection Inspector)、规格检查器(Size Inspector)、属性检查器(Attributes Inspector)、识别检查器(Identity Inspector)。
另外一个最常用的操作莫过于Xcode左上角的“运行(Run)”按钮了。这个操作会将项目代码编译成为应用,并在iOS设备模拟器中运行,以便我们直接查看程序的工作情况,而不必每次都部署到实际设备中。
不妨现在就点击“运行”按钮或使用快捷键Command R,来看看我们的模板项目打包成应用之后的样子:
什么也没有。iPhone模拟器的工作机制与实际设备差不多,Home按键是可以点击的,其他的一些内置应用也都是可以正常工作的,包括Safari、照片、联系人、Game Center、最新的Passbook等等,有兴趣的话可以玩玩看。另外,我们还可以在“Stop”按钮右侧的下拉列表中选择iPad作为模拟设备。
更多关于Xcode的使用方法,可以参考苹果官方的“Xcode 4 User Guide”。
将图片导入Xcode
我们下载的模板包当中是包括图片文件的,不过项目默认是不会将这些资源文件加载进来的,我们必须手动导入。方法有两种:你可以在左侧导航栏当中Control单击Images文件夹,选择“Add Files to 'Portfolio'”,然后找到模板包当中PNGs路径下的全部文件,执行添加(Add);或者也可以首先在Finder中找到这些文件,然后全部拖到Xcode导航栏的Images文件夹中。
如果采用第二种方式,在执行导入的时候,Xcode会提供一些操作选项,记得勾选其中的“Copy items into destination group's folder”,确保资源文件最终会被打包到应用项目当中。
应用界面的可视化编辑
iOS开发的圈子当中始终存在一个争论——是完全通过代码的方式创建应用更好,还是使用Interface Builder更加直观的构建界面来的更好些。两种方式都是可行的,而且它们在本质上可以说是互补而不是矛盾的关系,具体的开发策略还是由实际项目的特点所决定。
倾向于纯代码方式的开发者们也许真的忽视了可视化编辑工具在界面创建过程中所体现出的高效与直观。对于我们这些习惯了Adobe系列工具的设计师来说,可视化编辑的方式无疑是最好的切入点;而且我们的案例是很典型的基于视图(view)的应用,在这里使用Interface Builder进行界面构建也是最合理的。
首先,我们来看看怎样创建一些可以通过标签栏(Tab Bar)进行切换的界面,或者说视图(view)。在Xcode左侧的导航栏中点击MainWindow.xib,进入Interface Builder编辑模式。在右下角的库(Library)中选择“Show the Object Library”图标(看上去像个立方体的那个),在下面的列表中找到“View Controller”。
拖拽一个View Controller对象到编辑区左侧的文档结构列表(Document Outline)当中,并在"Tab Bar Controller"上面放开。此时后者会展开,一个View Controller嵌套在里面。
重复执行两次这样的操作,使Tab Bar Controller当中包含3个View Controller,此时我们也可以在编辑区当中看到,默认的View Controller的标签栏里已经有了3个未命名的Tab,如下图所示:
什么是View Controller?
View(视图)和Controller(控制器)都是MVC开发模式(Model View Controller)的组成部分。这种开发模式旨在将程序的数据、业务逻辑与表现进行分离(类似前端的“内容、样式、行为分离”)。其中"Model"包括数据和算法等方面,“View”涉及软件的人机交互界面,而“Controller”负责将这两者衔接起来,对用户行为进行处理;而View Controller即是指专门负责某个特定View的Controller。
关于MVC的概念,可以参考维基百科了解更多。
创建类(Class)
我们需要创建一些“类”来生成视图。在Objective-C这样的面向对象编程语言当中,“类”用来定义对象(Object)所共有的属性与方法。通过“类”,我们可以实例化出更多的同类对象。
在我们的案例当中,每个视图都是一个对象,它们有各自的内容与行为特征。所以我们需要创建3个不同的类,以便对每个视图的属性和方法进行定义。这些类所扮演的就是View Controller的角色。
要创建新的类,使用快捷键Command N,在左侧的列表中选择“Cocoa Touch”中的“Objective-C class”,如下图所示:
点击“Next”,在“Class”文本框中将这个类命名为“HomeViewController”,在下面的“Subclass of”列表中选择“UIViewController”,并勾选“With XIB for user interface”。
继续点击“Next”,在接下来的对话窗中,将类文件的保存路径设置为“Begin Here>Portfolio”,点击“Create”。
以相同的方法再创建两个类,分别命名为“PortfolioViewController”和“ContactViewController”。之后,你可以手动在导航栏中对文件进行拖放排序,使它们看上去更符合逻辑:
为Tab与视图建立关联
回到MainWindow.xib当中,在文档结构列表里选中我们之前添加的第一个View Controller,在右侧的识别检查器(Identity Inspector)中,展开“Class”下拉列表,选择其中的“HomeViewController”。
接下来切换到属性检查器(Attributes inspector),在“Title”中输入“Home”,并在“NIB Name”中选择“HomeViewController”。
在文档结构列表中展开这个View Controller,选中其中的“Tab Bar Item”,然后到属性检查器当中将“Title”设置为“Home”,并在“Image”下拉列表中选择我们之前导入的图片文件之一,tab-icon-home.png,这里你并不需要特别为Retina屏幕指定带有@2x后缀的文件,应用会在运行的时候自动识别。
以同样的方法对另外两个View Controller进行操作,将它们分别与“PortfolioViewController”、“ContactViewController”建立关联、挂上NIB文件,并为它们各自的Tab Bar Item设置相应的Title(Portfolio、Contact)与图标(tab-icon-portfolio.png、tab-icon-contact.png)。
Tab在高亮状态时的颜色也是可以定义的。在文档结构列表中选中“Tab Bar”对象,然后在右侧的属性检查器中找到“Image Tint”,在其中设置我们所需要的配色方案。不过这里所做的设置只有在iOS 5以上的系统中才会有效,对于iOS 4以及更低版本的系统来说,高亮状态仍然时默认的蓝色。
我们已经为Tab与视图建立了关联,要检视它们能否正常工作,我们还需要在每个视图当中添加一些范例内容。
在Xcode左侧的导航栏中选择HomeViewController.xib,然后从右侧的对象库中拖拽一个Label控件到编辑区当中的空白View上面。双击该控件,将文案更改为“Home”。
在PortfolioViewController.xib与ContactViewController.xib当中也执行同样的操作,Label的文案相应的更改为“Portfolio”和“Contact”。
现在点击“Run”按钮,或使用快捷键Command R来运行一下叭。我们可以在iPhone模拟器中看到,应用的标签栏已经可以正常的切换界面了。不赖!
向视图中添加图片和文字
要通过Interface Builder向视图当中添加图片和文字,我们首先需要创建一些对应着不同类型内容的“容器”,也就是“Image View”与“Text View”。与添加View Controller的方式相同,我们也需要将这两类View从右侧的对象库当中拖拽出来放到界面当中。我们还可以在规格检查器(Size inspector)中对这些容器进行精准的定制,包括布局位置、尺寸等。
而在属性检查器(Attributes inspector)中,我们可以为图片容器指定其中所要显示的图片,也可以控制文字容器的各种属性。
接下来我们要向HomeViewController.xib当中添加图片。首先删除之前的Label控件,从库中拖拽一个Image View到界面当中,在属性检查器当中的“Image”下拉列表里选择“home-bg.png”,然后将“Mode”设置为“Top Left”。
到规格检查器(Size inspector)中,确保其中的4个属性值分别为“0”、“-20”、“320”、“480”,如下图所示:
接下来,拖拽一个Text View到界面中,双击编辑其中的文案,例如更改为“A Catchy Slogan Here”,在属性检查器中设置为居中对齐,将字色设置为白色,并禁用背景色,然后将Font类型更改为“Custom”,将其他属性设置为“Snell Roundhand,Regular,24”。
现在我们的HomeViewController.xib看上去大致是这样的:
因为这三个界面都是被放置在Tab Bar Controller体系当中的,也就是说我们在设计这些单独界面的时候必须考虑到底部标签栏的占位。Xcode可以帮助我们在界面当中模拟这类全局元素的占位情况。确保在Xcode左侧的导航栏里选中HomeViewController.xib文件,在文档结构列表中选择“View”对象,然后在右侧的属性检查器(Attributes inspector)中找到最上面的“Simulate Metrics”一栏,在“Bottom Bar”中选择“Tab Bar”,如下图所示:
这个功能并不会向实际应用里又添加一个标签栏,它只是为我们提供一个可视化的设计指引,帮助我们对界面元素进行更精准的定位。
接下来,我们可以向Portfolio及Contact界面中添加图片和文字内容了。具体的样式可以参考本文开始时的目标演示图片,或参考模板包当中提供的PSD文件。
在Portfolio界面当中创建案例缩略图,以及在Contact界面中创建联系方式按钮时,我们需要使用对象库中的Round Rect Button控件,而不是之前那样使用Image View;因为这些地方都是需要响应用户的操作并由此触发相关行为的,按钮类的控件可以帮我们实现这个目标。将Round Rect Button拖拽到界面内,到右侧的属性检查器当中,将按钮类型(Type)设置为“Custom”,然后就可以通过下面的“Image”属性为其设置具体的背景图片了;如果需要的话,还可以进入规格检查器(Size inspector)当中对按钮的尺寸进行设置,使其符合按钮图片的大小。
3个界面都打造完毕后,点击“Run”按钮或使用快捷键Command R来运行应用,通过iPhone模拟器来检视当前的工作成果。
其他技巧
在iPhone模拟器中点击Home按键回到首屏,你会发现我们的App图标只是一个干巴巴的白板,在应用被打开的时候也没有任何额外的加载图像。
回到Xcode中,点击导航栏中的Portfolio项目图标,此时内容区会呈现出应用的信息概况。在其中找到“App Icons”和“Launch Images”,这里就是我们为应用添加图标和加载图像的地方了。
设置的方法很简单,在Finder里面找到模板包App Icons路径下的相关图片文件,直接拖拽到那4个空位当中就OK了。
如果要自己制作应用图标,在尺寸方面要符合以下规格(以像素计):
- 标准:57×57
- Retina:114×114
加载图像的尺寸则与屏幕一致:
- 标准:480×320
- Retina:960×640
除了在iPhone当中显示以外,应用图标的使用环境还有很多,例如两种规格的iPad、系统设置(Settings)、Spotlight搜索结果、iTunes等等。这篇文章很详细的给出了这些上下文环境中所需的图标规格,另外也可以参考iOS Human Interface Guidelines对于图标规格及使用方法的说明。
值得一提的是,iOS会自动为你的图标添加圆角和高光,所以在制作的时候你并不需要自己处理这些效果。如果不希望系统为图标添加高光效果,可以在之前设置图标的地方勾选“Prerendered”。下图演示的是勾选“Prerendered”前后的效果对比:
要改变图标下面显示的应用名称,点击应用概况中的“info”选项卡,这里所呈现的就是应用的.plist文件当中的内容。.plist是一个XML文件,里面包含了应用的主要设置信息:
其中的一些信息,例如“Main nib file base name”,所指向的是应用在第一次打开时需要加载的资源文件。其他信息,例如“Bundle Identifier”,则与通过iTunes Connect向App Store提交应用时的相关环节有关。
在这些信息中找到“Bundle display name”一项,将右侧的“${PRODUCT_NAME}”修改为你想要的名称即可。
辅助编辑器(Assistand Editor)
到目前为止,我们的自定义按钮是可以对点击动作作出响应的,不过也仅此而已,它们还不会做任何其他事情。为了使它们能够工作起来,我们需要借助辅助编辑器的帮助来写一些代码。
在Xcode左侧的导航栏当中选择ContactViewController.xib,然后到Xcode界面的右上角找到辅助编辑器按钮,选中它:
在这种模式下,编辑界面会被分割为两部分,其中左侧是ContactViewController.xib的可视化编辑界面,右侧是与其对应的头文件,即ContactViewController.h。我们可以在下图中看到,文档结构列表和右侧边栏已经被收起了,以便为两个编辑视图提供更多的空间。你可以到Xcode菜单中的“View”一项中找到相关的切换操作。另外你大概也发现了,图中代码编辑区的样式风格与你的有所不同,这是因为我(英文原文作者)使用了“Dusk”主题;你可以在Xcode→Preferences的“Fonts and Colors”更改代码编辑区的主题。
声明属性(Property)与方法(Method)
一个“类”通常包含特定的“属性”和“方法”。我们可以将“属性”理解为“类”所拥有的特性特征,而“方法”则是指“类”能做些什么。
当我们向ContactViewController中添加按钮时,我们需要将这个按钮声明为ContactViewController类的属性,并通过“方法”告诉按钮在被点击时应该做怎样的反应。
在ContactViewController.h文件中,我们可以看到如下代码:
代码语言:javascript复制#import <UIKit/UIKit.h>
@interface ContactViewController : UIViewController
@end
其中,第一行代码的作用是让我们的类可以访问UIKit框架当中的各种预置的UI类。
接下来一行(@interface)的作用是将ContactViewController声明为UIViewController的一个子类。UIViewController是在UIKit库中预先定义的,它的子类可以继承它的所有特性(包括属性和方法)。
我们可以在@interface与@end之间声明各种自定义的属性和方法。按住control键,从ContactViewController.xib里的“WWW”按钮上拖出一条导线,一直拉到.h文件的代码中@interface与@end之间的部分,释放。这时会出现一个对话窗:
确保“Connection”当中所选的是“Outlet”,并在“Name”里输入“websiteButton”,点击“Connect”,Xcode会自动生成一段代码。
接下来再执行一次相同的拖放操作,这次,在对话窗中为“Connection”选择“Action”,并在“Name”中输入“openWebsite”,点击“Connect”,Xcode同样会自动生成一段代码。
到目前为止ContactViewController.h中的代码看上去应该是这样的:
代码语言:javascript复制#import <UIKit/UIKit.h>
@interface ContactViewController : UIViewController
@property (retain, nonatomic) IBOutlet UIButton *websiteButton;
- (IBAction) openWebsite:(id)sender;
@end
还不赖,不过这些代码都是什么意思?
@property用来声明一个新的属性,括号中是两个参数,其中“retain”涉及内存管理,我们将在后文中讲到;而“nonatomic”则与多线程管理相关,多数的属性都要声明为nonatomic,禁用多线程。接下来是关于返回类型的声明,其中“IBOutlet”代表这个属性是绑定于用户界面中某个特定的控件的;“UIButton *websiteButton”的作用是将当前属性命名为“websiteButton”,并使其继承UIKit中定义的UIButton类。
接下来一行代码用来声明新的方法。其中的“- (IBAction)”同样用来将方法与.xib文件中的界面控件绑定起来。“openWebsite”是这个方法的名称,冒号后面的“(id)sender”是参数,用来传递产生动作的对象信息,不过我们现在用不到它。
也许你已经注意到了,我们在创建View Controller类的时候,名称都是以大写字母开头的,但属性和方法的名称却不是这样。这是面向对象编程语言的一种公约,即“类的命名以大写字母开头,属性(变量)和方法(函数)的命名以小写字母开头”。
我们之前演示的“拖动+自动生成代码”的方法是很方便的。我们当然也可以自己手动编码,只是使用辅助编辑器会更加快捷一些。
属性合成(Synthesis)与内存管理
现在,我们将编辑器切换回标准模式(Standard Editor),弹击选中ContactViewController.m,在大约12行的地方,你可以看到系统帮我们自动生成的代码:
代码语言:javascript复制@synthesize websiteButton;
这会告诉编译器在构建应用的时候为属性生成设置器(setter)与访问器(getter),我们不需要手动编写代码就可以使程序具有访问和设置属性值的能力。
再下面,找到这两行代码:
代码语言:javascript复制- (IBAction)openWebsite:(id)sender {
}
觉得眼熟?之前在ContactViewController.h当中,系统确实自动生成了类似的代码,不过在.h文件中的代码只是一种“声明”,真正编写方法函数还是要在.m文件中进行。具体来说,我们需要将按钮的反映行为编写到这里。
你还可以在.m文件中找到类似下面这样的代码:
代码语言:javascript复制- (void) dealloc {
[websiteButton release];
[super dealloc];
}
这段代码与内存管理有关。内存管理对于移动应用编程来说是非常重要的,因为移动设备在内存方面的资源确实很有限。当websiteButton属性被定义时,通过“retain”参数,系统会将一部分内存分配给这个属性。“retain”的具体作用是告诉系统分配出一定的内存,并且在我们进一步下达命令之前不要将这部分内存收回。
而“dealloc”方法只会在当前View的实例被销毁时执行,所以在这个方法中添加“websiteButton release”就相当于告诉系统:“你可以在这里收回这部分内存资源了,我们不再需要它了”。如果没有这行代码,那么即使界面已经切换、websiteButton不再存在,这部分内存依然在被占用;这种情况就叫做“内存泄漏(memory leak)”。如果在开发过程中不做相关处理,那么这种情况就会逐渐累加起来,导致程序运行效率低下甚至崩溃,或是造成系统电量损耗等其他不良后果。
幸运的是,对应着iOS 5以上版本的SDK当中增加了ARC机制(Automatic Reference Counting),它可以帮助我们进行自动化的内存管理。在创建新项目的时候,你可以选择是否启用ARC。在当前案例中,我们并没有用到它,因为我们要在这里对相关知识进行简要的介绍。
代码绑定
之前使用辅助编辑器为按钮自动创建属性和方法的时候,系统不仅帮我们生成了相关的代码,而且还对按钮控件与相关代码进行了绑定。
选择ContactViewController.xib,展开文档结构列表,在“Placeholders”下,选择“File's Owner”,它所代表的就是整个ContactViewController类。现在到Xcode右侧,打开连接检查器(Connections inspector),看上去应该是这样的:
在“Outlets”当中,我们可以看到,websiteButton属性已经被关联到了.xib文件的按钮控件上。
而在“Received Actions”里,openWebsite方法也已经与该按钮的“Touch Up Inside”事件建立了关联。这个事件所代表的就是用户在界面中轻触按钮并抬起手指的整个动作,它是按钮控件的默认事件。
手动编写Objective-C代码
接下来我们要告诉按钮在被点击之后应该做些什么。
在ContactViewController.m中,将定义openWebsite方法的代码更新为:
代码语言:javascript复制- (IBAction)openWebsite:(id)sender {
NSURL *webAddress = [NSURL URLWithString:@"http:www.apple.com"];
[[UIApplication sharedApplication] openURL:webAddress];
}
在这段代码中,我们做了两件事。
首先,我们在第59行的代码中创建了一个临时变量“webAddress”,用来存储一段包含特定URL(http:''www.apple.com")的字符串。这里的写法是一种比较快捷的方式,系统可以自动为NSURL实例分配内存,也会在需要的时候自动释放。
而后面的代码则告诉系统可以使用相关的应用(例如Safari)来打开这个链接。
对于Contact界面中的其他按钮,我们也可以通过类似的步骤来设定响应规则。将上面代码中的“openURL:”替换为“mailto:”,可以使应用触发默认邮件客户端执行相关的邮件工作,而“tel:”则可调出系统的拨号键盘界面,直接拨打预设好的电话号码。
使界面以模态的方式呈现
当前的Portfolio界面中有一些作品的缩略图,我们希望用户在点击它们的时候,对应的大图可以弹出。
要实现这一点,我们可以创造模态视图,使新界面以动画过渡的方式呈现出来,并覆盖在其他界面之上。
创建模态视图
要创建模态视图并不难。首先,我们要创建一个新的类,名字叫做BigImageViewController,具体方式与我们之前创建3个自定义类是相同的。
然后打开BigImageViewController.xib文件,向界面中添加一个Image View作为图片容器,并将它的“Image”设置为portfolio-modal-bg.png图片文件。接下来,在左上角添加一个类型为“Custom”的圆角按钮控件,使用button-close.png作为其背景,并将字色设置为白色,文案为“Close”。
然后在现有界面基础上再添加一个Image View,大致尺寸和位置如下图所示:
切换至辅助编辑器模式,在新添加的空白Image View上执行Control 拖拽,并指向BigImageViewController.h代码当中@interface与@end之间的部分,以此方法分别建立名为“imageFrame”的Outlet,以及名为“closeView”的Action。系统将在.h文件中自动添加如下代码:
代码语言:javascript复制@property (retain, nonatomic) IBOutlet UIImageView *imageFrame;
- (IBAction)closeView:(id)sender;
而具体的closeView代码还需要我们手动添加到.m文件当中:
代码语言:javascript复制- (IBAction)closeView:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
这段代码的作用是关闭当前已经激活的模态视图界面。
加载模态界面的代码
回到标准编辑器模式,打开PortfolioViewController.h文件,将代码手动更新为:
代码语言:javascript复制#import <UIKit/UIKit.h>
#import "BigImageViewController.h"
@interface PortfolioViewController : UIViewController
@property (nonatomic, retain) UIImage *bigImage;
- (IBAction) selectImage1;
- (void) openBigImageView;
@end
我们新写了一行#import代码,用来将之前新建的BigImageViewController类引入到PortfolioViewController当中,这样我们就可以在Portfolio界面中与之通讯,在需要的时候告诉BigImageViewController为自己创建一个实例。
我们还为PortfolioViewController创建了一个属性和两个方法,其中第二个方法openBigImage并不需要与.xib文件中的任何控件建立关联,所以它的返回类型是“void”,而非“IBAction”。
你也许会觉得奇怪,为什么在这里创建属性和方法的时候,我们没有使用副主编辑模式,通过拖拽方法来实现。其实结果是相同的,只是我们在这里刻意使用手动编码的方式来练习一下。所以接下来,我们还要到.m文件中手动输入那些与“属性合成”以及内存释放相关的代码:
代码语言:javascript复制@implementation PortfolioViewController
@synthesize bigImage;
- (void) dealloc {
[bigImage release];
[super dealloc];
}
在dealloc函数的后面,我们要为两个新建的方法编写具体的代码:
代码语言:javascript复制- (IBAction) selectImage1 {
self.bigImage = [UIImage imageNamed: @"image1-big.png"];
[self openBigImageView];
}
- (void) openBigImageView {
BigImageViewController *bigImageView = [[[BigImageViewController alloc] initWithNibName:@"BigImageViewController" bundle:nil] autorelease];
bigImageView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:bigImageView animated:YES];
[bigImageView.imageFrame setImage:bigImage];
}
这次还真是输入了不少东西,我们来看看这些代码的作用是什么。
selectImage1方法为bigImage属性指定了具体的图片,即image1-big.png文件。同时该方法还调用执行了openBigImageView方法。
在openBigImageView中,我们首先创建了一个BigImageViewController类的实例,并将其命名为“bigImageView”。这个实例自身就是一个模态界面,它会以“翻转(flip)”的动画效果出现,并将bigImage作为具体的图片放到其imageFrame容器当中。
因为我们通过代码手动为BigImageViewController的实例分配了内存,所以我们还要在适当的时候将这部分内存释放。问题在于,我们并不知道这些资源会被使用多久,因为大图模态界面会打开多长时间是取决于用户的。要解决这个问题,我们需要使用autorelease命令,它会告诉iOS系统一直保持内存资源的分配状况,直到确认“安全”的时候再进行释放。
模态视图的代码绑定
现在我们需要将代码绑定到XIB当中的控件上。选择PortfolioViewController.xib文件,点击文档结构列表当中的“File's Owner”,然后打开右侧的连接检查器(Connections inspector)。
在“Received Action”中,我们可以看到之前编写的selectImage1方法,它的右侧是一个圆环。点击这个圆环并进行拖拽,一直拖到界面当中的第一个缩略图上面释放,如下图所示:
在弹出的列表当中选择“Touch Up Inside”事件。
试着运行一下我们的应用叭,如果之前的工作没有出现问题的话,现在我们应该可以在Portfolio界面中点击第一个缩略图并查看相应的大图了。
接下来,你可以自己试着对另外三个缩略图进行处理了。你需要创建selectImage2,selectImage3,selectImage4这三个新的方法,不过对于openBigImage方法来说就不需要重复创建了,它是可以被共用的。另外你也可以尝试为模态界面使用不同的动画过渡效果,包括
- UIModalTransitionStyleCoverVertical
- UIModalTransitionStyleCrossDissolve
- UIModalTransitionStyleFlipHorizontal
- UIModalTransitionStylePartialCurl
如果你在这个过程中遇到麻烦,也可以打开模板包,在End Result路径中找到最终完成版的文件进行参考。
总结
本文确实涵盖了不少方面的内容,从Xcode的界面介绍、基本操作,到在Interface Builder中创建界面,以及实际代码的编写。我们通过一个简单而具有代表性的案例了解了iOS应用开发当中的一些关键概念,包括类、属性、方法、内存管理等。
本文只是引领你入门的一个小小的起点。在此基础上,你可以通过更多的资源进一步深入学习iOS开发的相关知识与技能了。好运叭!