• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

《iOS开发全然上手——使用iOS 7和Xcode 5开发移动与平板应用》之Objective-C新手训练 ...

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
     编写Hello World应用程序通常被觉得,是学习不论什么编程语言的第一步。在这一章,你将创建iOS版的Hello World应用程序作为起步,高速了解Xcode这个开发iOS应用程序的主要工具。
     下一步。你将学习Objective-C的基础知识。在此基础之上。将探索类(class)与对象(object)的知识。它们是构建应用程序的主要基石。与此同一时候,你将创建CarValet应用程序,练习一些类的编写。并学习属性(property)的知识。在本章末尾,你将在指导下完毕编程挑战题以探索子类扩展的知识。

当学完本章时,你将获得CarValet应用程序的初始版本号。以及足够完毕本书学习的Objective-C知识。
2.1 使用模板创建Hello World 应用程序
     创建Hello World演示样例应用程序的最简单方法,就是使用Xcode的预设模板。在接下来的步骤中,你将创建一个新的项目。然后改动它,使之能打印“Hello World”,并能在iOS模拟器上执行。在创建第一个Xcode项目时,你将学到关于Xcode这一关键工具的整体介绍,以及怎样创建和操纵项目。
2.1.1 创建Hello World 项目
     启动Xcode。你将看到如图2-1所看到的的Xcode欢迎页面(假设不小心关闭了这个页面。可通过选择Window | Welcome to Xcode(欢迎使用Xcode)或按下Cmd+Shift+1组合键来又一次显示)。

单击Create a New Project。

也能够在Xcode中选择File | New | Project(或按下Cmd+Shift+N组合键)。之后将会出现如图2-2所看到的的模板选择窗体。

默认情况下,模板选择窗体被嵌套在一个新的、名为工作区(workspace)的大窗体中。这个单独的工作区窗体中包括Xcode所有的编辑器和检查器(inspector)特性。

图2-1 Xcode 的欢迎页面

   在图2-2所看到的的模板选择窗体中,选择左边的iOS菜单下的Application,然后选择SingleView Application(单视图应用程序),单击Nextbutton。


图2-2 Xcode 模板选择窗体

警告:截图和功能可能会有所不同
Xcode 会定期更新,这意味着以上操作指令可能会与Xcode 中或苹果公司站点上的实际界面元素有细微不同。当遇到这样的情况时,通常能够找到一些显而易见且能完毕同样指令的办法,比方能够在不同的位置查找同名的控件或组件,此外还能够在类似的区域寻找类似的名称。假设以上方法都行不通。请查看本书配套网址(www.infomit.com/title/9780321862969)上的更新内容。假设还是找不到。请发送反馈信息。

      接下来显示的是Xcode项目选项面板(project options panel),如图2-3所看到的。

在这个窗体中,请遵循下列步骤:
(1) 在Product Name中输入HelloWorld。
(2) 将Company Identifier(公司标识符)设置为你所在的公司,使用反向域名命名法。比如,Maurice的公司标识符是com.mauricesharp或com.klmapps,Rod的公司标识符是com.strougo,而Erica的公司标识符是com.sadun。

假设没有公司标识符。苹果公司建议使用edu.self。

(3) 单击Nextbutton。


图2-3 Xcode 项目选项面板
     Class Prefix(类前缀)能够让你指定包括在类名中的前缀。Xcode会在定义类时,自己主动将其加入在类名前。使用前缀是一种好的方式,能有效地避免类名与现有或将来的iOS系统类发生命名冲突。比如,假设创建了类SlideMenuViewController。而某次iOS系统更新时添加了一个同名的类,那么至多可能是应用程序无法编译。更糟糕的情况是,应用程序说创建的实例是同名系统类的实例,不是自己所写的类的实例,这会带来很糟糕的bug。

但假设指定前缀为“MS”。那么Xcode会创建名为MSSlideMenuController的文件和类,从而避免潜在的冲突。


     在本书中。为了让命名更简短。并未使用前缀,可是你应当依据自己的开发人员名称或公司名称设置前缀。
专家提示:前缀格式
最典型的类前缀是一小串大写字母(苹果公司推荐使用3 个字母),一般是你或你公司名称的单词首字母。

在公司内部项目或开源项目中,这样的格式非经常见。但可读性并非最好。下面是一个滑动菜单类的各种不同的名称。这并非我实际编写过的一个类。是我想出来的。但最好还是试着观察一下列表中的这些类名条目,依照你浏览代码时的方式,看看哪一个更easy高速识别:
SlideMenuViewController
MSSlideMenuViewController
MS_SlideMenuViewController
msSlideMenuViewController
ms_slideMenuViewController

极其可能的是,所有大写且没有分隔符的版本号最难识别。小写的稍稍easy点。但难以识别的程度仅次于前者。更easy识别的是那些带有分隔符的版本号。你应当选择能与符号名称简易搭配使用的类前缀。

长远来看,你将节省大量的开发与调试时间。


项目选项面板中的其它条目包含下面这些:
• Product Name (产品名称)——应用程序的名称。它会被显示到设备屏幕上。如你在第15 章“部署应用程序”中将要看到的。兴许还能够对其改动。
• Organization Name (组织名称)——作为自己主动生成的源文件头部凝视的一部分。用作版权属性。


• Devices(设备)——应用程序的目标设备平台。能够是iPhone、iPad 或Universal(通用应用程序)——能够同一时候执行在这两种平台上的应用程序。

      上一个Xcode窗体面板询问你Hello World项目的存储位置。

假设愿意的话,Xcode还能够为项目创建本地的git仓库。针对当前这个Hello World演示样例。将Source Control(源代码控制)复选框保持为未选中状态。

选择一个目录并单击创建。如图2-4所看到的。

     在单击Createbutton之后,你应该能看到在Xcode中,自己的Hello World新项目已被打开。它带有一些Xcode自己主动生成的文件。至此,你得到一个看似不怎么有趣,可是功能完备的应用程序。假设立马单击Run(执行)button,你的app会显示一个顶部带有状态条的白色屏幕。


图2-4 Xcode 项目目录位置面板
2.1.2 Xcode 项目界面高速导航

      开发应用程序时,你将在Xcode中花费大量时间。图2-5显示了展开项目文件并选择ViewController.m文件后的Xcode界面。


图2-5 Xcode 项目界面的组成部分

     以下是对Xcode界面的高速导航。

接下来的几章将探讨Xcode界面中不同组件的很多其它细节知识。以下的数字与图2-5中显示的数字一一相应:

(1) 单击Runbutton(在左边),编译应用程序,并在模拟器或设备中启动应用程序。

单击并保持(长按)Runbutton。你会看到额外的选项,比方用于測试或分析项目的选项。

右側的button可用于停止正在执行的应用程序、正在执行的构建或已发起的其它动作。
(2) 在这个分为两段的弹出式菜单button中,左段用于选择和编辑方案(Scheme),也就是关于你想执行什么以及怎样执行该应用程序。右段用于选择在哪儿执行应用程序:是在某种模拟器中还是在某个已连接的设备上。
(3) Status(状态)区域向你展示上一动作的执行结果或当前动作的进度。

动作包含构建应用程序、执行应用程序或是下载应用程序到设备上。


(4) Editor(编辑器)button用于配置编辑器(图2-5中标为7的区域)中显示的内容。

左側button在图中已被选中,仅仅显示一件东西。即主编辑区。中间的Assistant(辅助编辑)button将编辑区划分为两块,在右側会显示与主编辑器相关的文件。在右側通常情况下会显示头文件。

最后一个button用于显示源码差异,而且能够查看文件的不同版本号。

这一点在使用源码仓库跟踪代码变动时很实用。

注意,不能同一时候显示辅助编辑和源码视图。
(5) 这个区域控制Xcode中工作区视图的整体布局。第一个button显示或隐藏Navigation(导航器,图2-5中的区域6)。第二个button控制Debugger(调试器。区域10)。

最后一个button显示Utilities(区域8和9)。


(6) Navigator(导航器)能够显示项目的不同视图。顶部的图标控制视图的类型。在图2-5中,被选中的是目录图标,因此这个区域显示的是文件以及基于组(group)的项目导航器。其它图标是:项目符号导航器。用于在全项目范围内进行搜索的放大镜图标,用于查看构建问题的警告三角形图标。还有单元格測试导航器。调试导航器,断点列表。最后是日志视图。easy混淆的一点是,文件和组导航器中显示的文件结构和Finder中的文件结构。这两者能够是不同的。在导航器中,组被显示为目录图标。但这些与Finder中的目录是不同的。假设想让组和Finder目录保持一致。就须要在Finder中加入这些目录,并将源文件保存在正确的位置。


(7) Editor(编辑器)是你将在Xcode中花费大多数时间的地方。眼下,它显示的是源代码编辑器。

它还能够显示Interface Builder(界面生成器)、数据模型编辑器或执行时调试測量仪器。
(8) 工具区域显示了不同种类的工具,包含文件信息、高速帮助(当前被选中的内容)、数据模型细节查看器、视图属性(比方颜色、button标题以及尺寸,包含屏幕大小和约束)。
(9) 工具区域的底部为库区域。

在此处你可以找到Interface Builder中构造应用程序所需的可拖曳组件、代码片段,甚至包含图片和其它媒体文件。注意在工具区域的底部可能仅仅看到含有库选择图标的一行。要展开库。请单击并向上拖动选择器工具栏。
(10) 调试区域包括三个主要部分。

顶部工具栏的左边包括用于在执行中暂停以及单步执行的控件。右側包括当前选中的文件。底部被切割成两个主要区域,一个用于检查变量,另一个用于打开控制台。在整本书中,你将学习到有关的很多其它详细知识,特别是在第14章“Instruments和调试”中。如今你对Xcode已有一定了解,该创建第一个应用程序了。
2.1.3 加入Hello World 标签
      默认情况下。Xcode创建设置为执行在iPhone或iPad上的项目;当创建一个项目时。下一个项目使用前一次的设置。新项目一開始就包括你创建自己的应用程序所需的全部类和支持文件。

当执行一个新项目时。它会显示一个空白的白色屏幕。


在屏幕上看到Hello World的最快方法是往项目里加入标签。保持项目打开,运行下面步骤(见图2-6):
(1) 通过观察方案弹出菜单的右側(图2-5中的区域2),确认项目被设置为执行在模拟器中。假设右側没有显示“iPhone Retina(4-inch)”,单击方案弹出菜单的对应一边而且选择这一条。注意下拉菜单包括两部分:左側是方案弹窗,右側同意你选择应用程序在哪里执行。你应仅仅将Hello World标签加入到iPhone故事板中。于是。应用程序在iPhone而不是iPad上执行是很重要的。
(2) 在Xcode项目导航器中单击并选择Main_iPhone.Storyboard文件。

Interface Builder会在编辑区域打开。在很罕见的情况下,Interface Builder并没有打开。这时你要检查并确定没有单击显示源码差异的第三个button(參见图2-5中的区域4)。假设源码控制button未选中,尝试选择一个.m或.h文件。然后再次选择故事板文件。假设还是无论用,那么退出Xcode并重新启动。


(3) 在右下方的查找面板中。输入label并将这个标签对象拖曳到故事板的画布中。
(4) 在Xcode工作区左側在Utility区域中,在Attributes检查器的文本框内输入Hello World,将这个标签调整得好看一些。

图2-6显示这个标签在视图控制器(view controller)的顶部水平居中。


(5) 单击Runbutton,编译并执行Hello World应用程序。


图2-6 通过Xcode 的界面生成器加入Hello World 标签
      当执行Hello World应用程序时,能够看到iPhone模拟器,记得使用方案弹出菜单,将运行的目的地设置为iPhone模拟器。
这就是创建简单Hello World应用程序所需的全部步骤。

你甚至不须要编写不论什么代码。在下一节。你将学习一些Objective-C基础知识,回到这个Hello World应用程序,并加入一些代码以练习Objective-C。



图2-7 执行在iPhone 模拟器中的Hello World 应用程序
使模拟器适应你的屏幕

图2-7 所看到的的模拟器是全尺寸的、4 英寸Retina 显示屏,而且可能很大,特别是当在笔记本电脑屏幕上工作时。

能够使用Simulator Window | Scale 菜单更改显示屏的显示大小。


2.2 Objective-C 新兵训练营

要成为熟练的iOS开发人员,你须要学习Objective-C。它是iOS和Mac的主要编程语言。Objective-C是一种强大的面向对象编程语言,同意你利用苹果公司的Cocoa和Cocoa Touch框架,构建应用程序。在这一章,你将学习主要的Objective-C技巧,開始iOS编程。你将学到接口、方法以及很多其它其它知识。要想完毕这些学习。必须往Hello World应用程序中加入一些自定义的类,练习所学的知识。


注意:
这一节涵盖的Objective-C 知识足以让你理解本书所展示的代码,并实现大多数章末尾的挑战题。

然而。Objective-C 有太多的内容。我们没法在这么小的一节里边所有涵盖,而这些没有涵盖的内容中,有一些对于编写产品级质量的应用程序是很重要的。

学习Objective-C的一份重要材料是Learning Objective-C 2.0:A Hands-on Guide to Objective-C for Mac and iOS Developers,2nd edition。作者是Robert Clair。

还能够使用Objective-C Programming:The Big Nerd

Ranch Guide,作者是Aaron Hillegass。这本书涵盖了更高级的知识。


2.2.1 Objective-C 编程语言
      Objective-C是ANSI C的严格超集。C语言20世纪70年代早期由AT&T开发的一种面向过程的编译型语言。Objective-C由Brad J. Cox在20世纪80年代早期开发。向C语言添加了面向对象的特性。

它将C语言的组成部分与Smalltalk-80中产生的概念加以混合。
Smalltalk是最老和最有名的面向对象编程语言之中的一个。是由Xerox PARC开发的一种动态类型的交互式语言。Cox将Smalltalk的对象和消息传递系统层叠到标准C语言之上,从而构建了一种新的语言。这样的方法同意应用程序猿在继续使用熟悉的C语言进行开发的同一时候。在那种语言内部使用基于对象的特性。在20世纪80年代后期,Objective-C被史蒂夫·乔布斯的计算机创业公司Next的NeXTStep操作系统选作主要开发语言。NeXTStep成为OS X直到iOS的精神和字面意义上的先驱。
      Objective-C 2.0在2007年10月随着OS X Leopard一起公布,它引入了很多新特性,如属性和高速迭代。

在2010年,苹果公司更新了Objective-C语言,添加了Block这个C语言扩展。它提供了匿名函数。并同意开发人员将Block作为对象进行处理(你将在第13章中学习很多其它内容)。在2011年夏,苹果公司引入了自己主动引用计数(Automatic Reference Counting,ARC),这个扩展大大简化了开发,它同意应用程序猿将注意力集中在应用程序语义上,而不用操心内存管理(准确地说,ARC是编译时扩展而非语言扩展)。近期,Objective-C被扩展为支持字面量(定义静态对象的方式)以及索引(訪问数组和字典中元素的方式)。苹果公司持续改进Objective-C语
言。所以要注意新的iOS和Xcode更新版本号的公布说明。

面向对象编程使用了ANSI C没有的表特性。

对象是一种数据结构。它关联了一组公开声明的函数调用。Objective-C中的每一个对象包括一些实例变量(instance variable)。也就是这样的数据结构的数据域(或字段)。还包括一些方法(method)。也就是该对象所能运行的函数调用。面向对象的代码使用这些对象、变量和方法来引入一些编程抽象来添加代码的可读性和可靠性。你有时候可能会看到实例变量被缩写为iVar,方法被称作消息(message)。

      对象使用类(class)进行定义。

能够将类觉得是决定对象终于长什么样的模板:怎样查看状态(实例变量),以及支持什么行为(消息)。

      类本身通常不做太多事情。它们的主要用途是创建功能完整的对象。

对象被称作实例(instance),也就是基于类所提供模板的起作用的实体。之所以命名为“实例变量”。是由于它们仅仅存在于类的实例中。而不是类自身的内部。当往第4步的文本框中输入“Hello World”时。实际上也就设置了一个UILabel对象的text实例变量的值。

UILabel类本身并没有text变量可被设置。

全部这些事情,以及创建标签实例的代码已经自己主动完毕了。

      面向对象编程让你构建可重用的代码并从面向过程开发的正常控制流中解耦。

面向对象的应用程序环绕着对象和它们的方法所提供的自己定义数据结构来开发。iOS的Cocoa Touch以及Mac OS X的Cocoa提供了一个包括大量这样的自己定义对象的仓库。

Objective-C解锁了那个仓库,并同意你用最少的努力和代码。基于苹果公司的工具箱创建有效而强大的应用程序。


注意:

iOS 的Cocoa Touch 中以NS 开头的类名。比如NSString 和NSArray,可追溯到NeXT公司。NS 代表NeXTStep,执行在NeXT 计算机之上的操作系统。苹果公司于1996 年收购了NeXT。


调用函数:也就是消息传递
      Objective-C是C语言的超集,正由于如此,它沿用了大多数同样的语法。

让大多数Objective-C的学习者感到困惑的一点,在于消息传递的语法——用于调用或执行类实例所实现的方法。不像函数调用时使用的“函数名(參数列表)”语法。传递消息给对象时要使用方括号。
      一条消息让一个对象运行一个方法。

实现这种方法。产生一个结果,是这个对象的职责。方括号里的第一个元素是消息的接收者,也就是实现这种方法的对象;第二个元素是方法名称以及可能会有的传给那个方法的一些參数。它们一起定义了你想要发送的消息。在C语言中。你可能会这么写:

<span style="font-size:14px;">printCarInfo(); // This function prints out the info on the default car</span>

可是在Objective-C里,你这么写:

<span style="font-size:14px;">[self printCarInfo]; // This method prints out the info on the default car</span>

      在C语言中,想要执行这个函数的目标对象被假定为当前的对象。

在某些语言中,你可能看到this.printCarInfo()。

在Objective-C中,self代表当前对象,大体上与this类似。
      在其它语言中,你可能会使用类似someOtherObject.printCarInfo()的代码。在还有一个对象上调用方法,如果someOtherObject拥printCarInfo()函数。在Objective-C中,能够使用下面代码:

<span style="font-size:14px;">[someOtherObject printCarInfo]; // This method prints out the info on the default car</span>

      虽然语法不同,但方法(method)基本上讲就是在对象上运行的函数(function)。

除了Objective-C的类型之外,方法中的类型能够使用标准C语言中相同的类型。

不像函数调用。Objective-C限制了能够实现和调用方法的主体。方法属于类。而且类的接口定义了哪些方法是公开的。或者说。是面向外部世界的声明。
      当函数包括一个或多个參数时,代码就開始看起来不一样了。假定必须将汽车对象myCar 传递给printCarInfo()函数。

在C语言中,你会这么写:
printCarInfo(myCar); // Print the info from the myCar object
在Objective-C中,你会这么写:

<span style="font-size:14px;">[self printCarInfo:myCar]; // Objective-C equivalent, but with poor method name</span>

在Objective-C中。你被鼓舞依次放置方法名和參数。因此极其可能将printCarInfo方法重命名为:

<span style="font-size:14px;">[self printCarInfoWithCar:myCar]; // More clear as to which car it will print out</span>


如今将演示样例再深入推进一步。假定必须传递显示信息时的字体大小。

在C语言中,你会这么写:

<span style="font-size:14px;">printCarInfo(myCar,10); // Print the info using a font size of 10</span>

在Objective-C中。你会使用例如以下代码:
<span style="font-size:14px;">[self printCarInfoWithCar:myCar withFontSize:10]; // Print using a font size of 10</span>

通读代码时能够立马发现Objective-C清晰了不少。

让我们再深入一步。如今假定你有三个參数:汽车对象,信息的字号。还有表示文字是否须要粗体显示的布尔值。

在C语言中,你会使用例如以下代码:

<span style="font-size:14px;">printCarInfo(myCar, 10, 1); // Using 1 to represent the value of true in C</span>

在Objective-C中,你会这么写:
<span style="font-size:14px;">[self printCarInfoWithCar:myCar withFontSize:10 shouldBoldText:YES];</span>

注意:
      在Objective/Cocoa 中,布尔值由BOOL 类型提供。BOOL 类型的标准值是YES/NO而不像C 语言中的true/false。虽然也能够引入C 标准库,而且使用C 语言的Boolean 类型,但不推荐。

      方法名与參数依次交错放置,能有效地让Objective-C 的消息传递变得easy阅读和理解。在C 语言和其它语言中,你不得不时常參考函数定义以确定每一个參数是什么以及參数的顺序。在Objective-C 中。这些都非常清晰。就在你面前。在使用一些含有5 个或很多其它个參数的UIKit 方法调用时,你会特别明显地体会到这一点。


在Objective-C中,方法的參数由冒号(:)字符进行分隔,在參数值之间带有方法名称中的一部分。你的方法可能返回一个值或对象。相同C语言也能够返回一个值。

在C语言中。你会使用下面代码:

<span style="font-size:14px;">float mySpeed = calculateSpeed(100,10); // returns the speed based on distance / time</span>

在Objective-C中。你的方法调用看起来例如以下所看到的:
<span style="font-size:14px;">float mySpeed = [self calculateSpeedWithDistance:100 time:10];</span>

注意:
假设Objective-C 的方法声明和消息传递语法对你来说还是不清楚,不要操心。在本章的下一节。你将有充分机会加以练习。
苹果公司提供图2-8 所看到的的文字来阐述Objective-C 方法调用的组成部分。

要看到很多其它信息,
请看https://developer.apple.com/library/iOS/#referencelibrary/GettingStarted/RoadMapiOS/Languages/
WritingObjective-CCode/WriteObjective-CCode/WriteObjective-CCode/html。

图2-8 Objective-C 方法调用的组成部分
      除了让參数更清晰,方法还引入了一个更加强大的特性。

方法能够訪问类中定义的全部东西。换句话说,能够訪问实例变量以及随意类实例中实现的方法。

在这样的意义上。方法如何执行对于调用者对象是透明的。

某个特定方法的实现代码甚至是整个类能够全然改变而不须要将别的不论什么地方改动。

这在升级或替换应用程序中的特性时是很实用的:可能是让它们更有效地更新新的硬件特性,甚至彻底替换通信的处理方式。



2.2.2 类和对象

       对象是面向对象编程的核心。

能够通过构建类定义对象。类即为创建对象的模板。

Objective-C中。类定义描写叙述了怎样构建属于这个类的新对象。比如,要创建汽车对象。须要定义Car类。而且在须要时用这个类创建新的对象。

与C语言类似。在Objective-C中实现类需要分两处进行:头文件和实现文件。头文件规定了外部世界怎样与这个类交互:实例变量及其类型。方法及其參数和返回值类型。就像契约,头文件承诺类的实例怎样与别的对象对接。

      实现文件的内容即为类怎样提供实例变量的值,以及方法被调用时怎样响应。除了头文件里定义的公有变量和方法。在实现文件里也能够定义变量与方法,而且实现文件一般会包括私有的变量和方法。

       每一个类使用标准的C.h约定。在头文件里列出实例变量和方法。比如。你可能会像代码清单2-1那样定义SimpleCar对象。

此处所看到的的Car.h头文件包括声明SimpleCar对象结构的接口。
代码清单2-1 声明SimpleCar 接口(SimpleCar.h)

<span style="font-size:14px;">#import <Foundation/Foundation.h>
@interface SimpleCar : NSObject {
NSString *_make;
NSString *_model;
int _year;
}
@property float fuelAmount;
- (void)configureCarWithMake:(NSString*)make
model:(NSString*)model
year:(int)year;
- (void)printCarInfo;
- (int)year;
- (NSString*)make;
- (NSString*)model;
@end</span>

      在Objective-C中,类、变量和方法採用驼峰式命名法。

在Objective-C中。你会使用identifiersLikeThis而不是identifiers_like_this。

类名首字母大写,而其它的名称首字母小写。

能够在代码清单2-1中看到。类名SimpleCar以大写首字母开头。实例变量fuelAmount採用驼峰式命名法。可是以小写字母开头。

示比例如以下:
- (void) printCarInfo

      在Objective-C中。@符号用在特定的一些keyword中。此处展示的两个元素(@interface和@end)划分了类接口定义的开头与结尾。类定义描写叙述了一个含有5个方法与4个实例变量的对象。

      在这4个变量中,仅仅有fuelAmount是公有的(public),意思是它在SimpleCar类的外部能够使用。

花括号里的其它三个变量仅仅能被SimpleCar及其子类使用。这三个变量也能够定义在.m实现文件里,但那样的话它们将仅仅对SimpleCar类可见。假设想让子类(比方ElectricCar)共享这些变量的话,这就成问题了。

      私有变量中有两个(_make和_model)是字符串类型。Objective-C通常使用基于NSString对象的类,而不是基于字节(byte)的用char *声明类型的C字符串。正如在这本书中到处可见的。NSString提供的功能远远多于C字符串。

对于这个类。能够找出字符串的长度。查找和替换子字符串,颠倒字符串。提取文件扩展名。以及很多其它。这些特性都被编写到iOS(和Mac OS)的对象库里。

私有的_year变量和公有的fuelAmount变量都属于简单类型。前者是int类型,后者是float类型。


      使用前置的下划线字符(_)是Objective-C中区分实例变量和getter方法的一般做法。使用x=_year是直接从实例变量获得值,而x=[self year]是调用getter方法-(int)year。能够做一些必要的计算或者在返回之前暂时计算值。setter方法类似getter,仅仅只是是用于设置实例变量的值。
      反复一下,使用setter能够运行一些额外的工作,比方更新屏幕上的计数器。

你将在下面内容中以及全书中学习创建与使用getter和setter。
      第一个公有方法例如以下所看到的:

<span style="font-size:14px;">configureCarWithMake:model:year:</span>

      这个完整的包括三段的声明(包括冒号)。才是该方法的名称或选择器(selector,有时也称为签名)。那是由于Objective-C在方法名中交替放置參数,使用冒号分隔每一个參数。在C语言中,能够使用setProperties(char *c1,char *c2,int i)这种函数。Objective-C的方式,虽然更繁重,但提供更好的清晰性和不言自明的文档。你不须要推測c1和c2的作用,由于它们的用途直接在方法名称里声明了:
<span style="font-size:14px;">[myCar configureWithMake:c1 model:c2 year:i];</span>

      每一个方法都有返回參数。printCarInfo返回void,year返回int。而make和model都返回NSString*类型。与C一样。这些代表方法返回的数据类型。

void代表这种方法不返回不论什么东西。

在C语言中。与printCarInfo和year方法等价的函数声明是void printCarInfo()和int year()。

      使用Objective-C的“方法名分散在參数中”的方式。对新应用程序猿来说可能看起来非常奇怪,可是非常快就会变成你非常喜爱的特性。

当方法名告诉你什么什么參数该在哪儿时,就不需要推測该传递什么參数。

你会在iOS编程中多次见到这个。特别是当使用respondsToSelector:这种方法调用时,这种方法让你在执行时检查对象能否响应特定的消息。

      注意代码清单2-1中的头文件使用#import载入头文件,而不是#include。

当导入(import)头文件时,Objective-C自己主动跳过已经被加入了的文件。

因此能够往各种各样的头文件里加入@import指令,而不会有不论什么损失。
1. 定义实现文件
.h文件告诉外界怎样与类的对象交互。.m文件或实现文件包括了赋予对象生命与力量的代码。代码清单2-2展示了SimpleCar类的某种实现。


代码清单2-2 SimpleCar 类的实现文件(SimpleCar.m)

<span style="font-size:14px;">#import "SimpleCar.h"
@implementation SimpleCar
- (void)configureCarWithMake:(NSString*)make
model:(NSString*)model
year:(int)year {
_make = [make copy];
_model = [model copy];
_year = year;
}
- (void)printCarInfo {
NSLog(@"--SimpleCar-- Make: %@ - Model: %@ - Year: %d - Fuel: %0.2f",
_make, _model, _year, [self fuelAmount]);
}
- (int)year {
return _year;
}
- (NSString*)make {
return [_make copy];
}
- (NSString*)model {
return [_model copy];
}
@end</span>


      实现文件通常与头文件配对,因此第一件事情即为导入那个头文件。在此处是SimpleCar.h。大多数类会导入其它头文件,而且可能声明常量或做其它事情。类实现的主要部分位于@implementation和@end之间。


      configureCarWithMake:model:year为每一个私有实例变量设置值。

除了fuelAmount之外,不能为当前的汽车对象单独设置某个值。

使用訪问器方法(access method)读取不论什么单个元素的值是可行的。比如代码清单2-2底部定义的-(int)year。

由于头文件为fuelAmount使用了@property,所以setter和getter方法,以及下划线版本号的变量已经为你创建好了。

你将在本章后边的“2.3.2节“属性”中看到相关很多其它内容。
      第一个方法设置三个非公有实例变量的值。printCarInfo将全部实例变量的当前值打印到日志中。最后三个方法是私有实例变量的getter方法。

你可能注意到的一点是。配置方法和getter方法都与字符串的副本打交道。这是一种普遍的防御性实践。避免代码意外地改动字符串的值。但当你意识到每一个变量是一个指向NSString对象的指针时,就会理解了。假设将这个指针赋值给字符串參数。那么它将与这个字符串的拥有者指向同样的内存位置。假设原始拥有者改变了字符串的值。汽车对象会得到新的值,由于它指向同样的内存地址。
       赋值并返回字符串的副本,会得到不同内存区域的新对象。

这些副本能够被改动。而不会改变当前汽车对象的make和model。注意。你唯一须要注意的是,这仅仅适用于长期存在的实例变量。暂时字符串和对象不须要被拷贝。


2. 创建对象

      你已经学到,类定义一个或很多其它个对象。

类在执行时怎样变成对象?要创建对象。你需要让类为新对象分配足够的内存,而且返回一个指向这块内存的指针。

然后让新对象初始化自己。你通过调用alloc方法处理内存分配,而且初始化发生在调用init时。假设正在创建SimpleCar对象。那么能够使用例如以下两行代码:

<span style="font-size:14px;">SimpleCar *myCar = [SimpleCar alloc];
[myCar init];</span>

      虽然看起来没有多少代码,但这将是你时常须要输入的。幸运的是,Objective-C支持嵌套消息发送。这意味能够使用一个方法的结果作为还有一个方法的接收者。

一组嵌套消息的返回值来自最后一条消息。
       在之前的代码中,第一行为汽车对象分配内存而且返回一个指向那个对象的指针。第二行拿到了分配好的汽车对象而且加以初始化。init方法返回初始化之后的对象。

由于myCar已经指向正确的对象,而第二行不须要使用这个返回值。使用嵌套能够将这两行缩短为一行:

<span style="font-size:14px;">SimpleCar *myCar = [[SimpleCar alloc] init];</span>

      此处。将消息alloc发送到SimpleCar对象的源码得到一个新的汽车对象,然后将消息init发送到新分配好的SimpleCar对象并返回初始化后的汽车对象。这样的嵌套在Objective-C中是非常典型的。


      你在此处看到的“分配后紧跟init”的模式是实例化对象的最常见方式。SimpleCar类指向alloc方法。

它分配足够存储类定义中全部实例变量的新内存块,将全部实例变量清理为0或nil,并返回指向这个内存块開始位置的指针。

新分配的块是实例,代表内存中单独的对象。

某些类,比方视图。使用自己定义的初始化方法,比如initWithFrame:。如你在本章后边将看到的,能够编写自己定义的初始化方法。比方initWithMake:model:year:fuelAmount:。这种紧随内存分配进行初始化的模式广泛存在。

你在内存中创建这个对象。然后预设全部关键的实例变量。

3. 继承方法
      对象在继承实例变量的同一时候会继承方法实现。SimpleCar是一种NSObject,因此全部NSObject可以响应的消息Simple Car也可以响应。这就是myCar可以使用alloc和init进行初始化的原因。

这两个方法是由NSObject定义的,可用于创建和初始化不论什么SimpleCar实例。由于它继承自NSObject类。Objective-C中的全部类都终于继承自NSObject,NSObject处于它们继承树的顶端。


提示:继承的方法
      假设查看Hello World 项目的AppDelegate 或ViewController 类的.h 文件。就会看到AppDelegate 继承自UIResponder,而且ViewController 继承自UIViewController。而UIViewController 接下来继承自UIResponder。

假设选择并右击UIResponder,选择Jump to Definition(跳到定义),那么Xcode 会为你显示UIResponder 的声明。在那里能够看到,它也继承自NSObject。
      作为还有一个演示样例,当应用程序中有数组时,你有可能会使用NSArray或NSMutableArray—— 一种同意你增删元素的NSArray。全部数组方法都能够被可改动的数组以及它们的子类使用。能够统计数组中元素的个数。依据索引数字取出对象等。
警告:
有些类对“子类化”(subclassing)并不友好。

它们是作为类簇(class cluster)来实现的。也就是,类自身会依据一些标准,创建一些其它类的对象。NSArray 和NSString 都是类簇的演示样例。它们以最能有效利用内存的方式。使用不同的类创建对象。全部这些类都在文档中做了清晰标记。在子类化系统类之前,要细致检查一下其是否为类簇。
      子类能够实现与超类具有同样选择器的方法。

在子类对象上调用此方法将运行新的方法。这取决于这种方法怎样实现,要么特殊化。要么覆盖超类行为。

特殊化(Specializing)的意思是(运行新逻辑的同一时候)还让超类方法运行,方法是将消息发送到super对象,super是代表超类的特殊标识符。覆盖(Overriding)的意思是并不将消息发送到超类,超类的行为从不运行。一个不错的演示样例就是初始化方法。须要确保继承链中的每个类都有计划初始化自身。

只是方法仅仅须要记得调用自身的超类。

初始化方法总是包括下面形式的一行:

<span style="font-size:14px;">self = [super init];</span>

      这会将当前对象的实例设置为超类创建的实例。接下来就是初始化对象的剩余部分。
警告:先初始化超类
       很重要的是,要在做不论什么特定于类的事情之前调用超类初始化。假设试着首先操作对象。此时不论什么超类,包含NSObject,所提供的一切东西都没有建立起来。虽然实例变量能够返回一个值。而且方法调用可能顺利进行。可是这个对象将处于一种没有定义的状态。

      最好的情况是。在初始化时遇到一次应用程序崩溃(crash),而更有可能的是,在之后某一天将遇到一些随机性的崩溃或者奇怪的行为。你将在后边学到怎样编写正确的init 方法。


4. 指向对象
      你已经了解到,使用类创建对象是很easy的事情。当拥有一个新创建(分配)和初始化的对象时。下一步就是引用并使用这个新对象。在Objective-C中,你使用*字符表示变量是指向对象的指针,这在代码清单2-2中的_make和_model变量声明处能够看到。_make和_model变量都指向对象(NSString)而且变量名前边必须有*。
      其它变量属于原始类型,不是对象。

变量自身,或更准确说内存地址,保存的是值而不是对象的地址。_year变量是原始类型(int)的演示样例,因此不须要*字符。
      当向对象发送消息时。要去掉*字符。在下面代码片段中。myCar对象被创建为SimpleCar类的实例,而且printCarInfo方法被调用:

<span style="font-size:14px;">SimpleCar *myCar = [[SimpleCar alloc] init];
[myCar printCarInfo];</span>

假设想创建指向同一个SimpleCar对象的还有一个指针,能够使用下面代码:
<span style="font-size:14px;">SimpleCar *sameCar = myCar;</span>

或这段代码:
<span style="font-size:14px;">id sameCar = myCar;</span>

      id是一种会被翻译为NSObject *的特殊类型,这个翻译结果已经包括*字符。表示指向对象的指针。
      意识到myCar和sameCar指向同样对象是很重要的。假设使用sameCar指针改动make、model和year,那么[myCar printCarInfo]会显示新的值。
2.3 CarValet 应用程序:实现Car 类
       如今是时候练习使用Objective-C语言创建方法、变量和类了。一開始先为CarValet应用程序创建项目。当继续阅读这本书时,你会将这个应用程序从简单逐步開始变成完整的iOS应用程序,它能够执行在iPhone和iPad上,使用原生用户界面元素和iOS的其它部分。
第一步是创建CarValet应用程序项目。

使用与创建HelloWorld项目时同样的步骤:
(1) 在Xcode中,选择File | New | Project(或按下Cmd+Shift+N组合键)。


(2) 选择iOS Single View Application模板,与你创建HelloWorld项目时选中的模板同样。
(3) 在下一个面板中,在应用程序的名称文本框中输入CarValet。

确保Devices被设置为Universal。Organization和Company Identifier文本框中应该已经填入你在创建HelloWorld项目时填写的内容。

假设须要的话能够改动这些内容,然后单击Nextbutton。


(4) 保存项目,Xcode就会在新窗体中打开这个项目。假设已经打开一个项目。那么在Save面板的底部可能会有Add To(加入到)选项。假设是这种话。确保选中的是类似“Don’t Add to Any Project or Workspace”(不要加入到不论什么项目或工作区)的选项。
注意:
      这个演示样例应用


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap