分享

Objective

 现在决定明天 2014-03-12
文章来自raywenderlich,这篇文章还可以在这里找到 英语, 葡萄牙语(巴西)
此文是iOS教程组成员Linda Burke(一个独立的iOS开发人员,并且是 canApps创始人)发布的。
你是一个熟练其他平台,但想开始学习iPhone开发(这里主要是说Objective-C的软件工程师吗?坦率的讲,这是我不久之前的情况,我觉得自己有点迟钝,而且离我的开发工作越来越远。
大约2年过去了,我创建许多iPhone和iPad应用。我经常不得不刻苦学习,我想你或许可以从我的尝试和痛苦中受益良多。
此教程的读者是拥有很多编程经验的人。如果完全是一个编程新手,你可能需要去看我们的 iOS for High School Students 系列教程。
此教程目标是给你信心,讲Objective-C基础,而不是讲一些“让我们解释一下每个语法片段”方法,我们想深入浅出并给你一些实战经验和来自工作中的例子。当你需要深入学习的时候,这样会便于你查阅参考手册。
此教程中,教会你创建一个简单的应用,根据存储列表随机生成报价。这样,你就会熟悉Objective-C很多方面,包括:
Variables变量
Arrays数组
Property lists属性列表
Strings字符串
Predicates判断
Random selection随机选择
Simple interface objects and events简单的接口对象和事件
事先警告你-使用Objective-C 做iPhone开发是有趣且容易上瘾的。准备好少睡懒觉,积攒零散时间哦! 
开始之前,请确认你有Apple开发者账户和证书细节设置,以及已安装最新的Xcode版本(你可以从Mac App Store上免费下载)。
这些都完成后,我将带你入门Objective-C。 
Getting Started
首先要做的是:创建一个Xcode工程。
启动xcode并创建一个选择iOSApplicationSingle View Application模版的新的工程。然后点击Next(下一步)。
输入工程名称“QuoteGen”,输入你的默认公司标识,设置设备组为iPhone,确保使用ARC项是选中的(让其他的复选框不选中)。现在点击下一步,并选好你的工程存储位置。

你会注意到你的工程创建了AppDelegate.h, AppDelegate.m, ViewController.hViewController.m文件,还有一个ViewController.xib。
AppDelegate包含了初始化应用的代码。在本教程中,你知道这些就行了。下面是你会直接修改的其他文件的简要说明:
1.ViewController.xib (简而言之就是XIB文件)是一个接口布局文件,你经常用此文件创建/设计显示在iPhone设备上的界面。
2.ViewController.m 是一个接口控制器类,接口布局文件被连接到此类,这是自动发生的,所以此阶段你不需要考虑它,只要知道它是在你的接口类中简单设置对象和事件的。这是你创建的包括Objective-C代码的文件。
3.ViewController.h 是一个接口控制器类的头文件,你会在此声明实例变量,定义访问接口屏幕的对象和事件。
Note: 两种方式都很有效,在本教程中我们使用XIB,但如果你想尝试Storyboard,课后请查阅this tutorial。
Heading in the Right Direction
开始创建你需要存储你的报价的变量属性声明。你需要知道在什么地方增加这些变了。是的,在类的头文件ViewController.h中! 增加一个数组位于@interface 和 @end 之间:
  1. @property (nonatomic, retain) NSArray *myQuotes; 
Property 指令会告诉编译器,变量myQuotes是类的一个属性。不需要太深入了解此话题-日后会遇到复杂的内存管理-属性nonatomic 和 retain 是为了提高效率广泛使用的。 这个nonatomic属性指定属性在非多线程环境下。Retain 意味着指给变量一个指针像已存在的ViewController对象一样会保存在内存中。
Note: 下面仅供参考,retain关键字和strong同义的。在Objective-C中,你经常不得不自己处理内存管理,但现在有一个叫ARC的特性,它是自动的,如果想了解更多关于ARC内容,请查阅 this tutorial。
此应用会存储很多来自电影的对白,所以,你需要第二个数组:
  1. @property (nonatomic, retain) NSMutableArray *movieQuotes; 
这里使用NSMutableArray简单的阐述不同类型的数组的差别。稍后有更多阐述。
Manual Labor手动实现
现在你需要“合成”那些数组————这样,如果你没有在@implementation中提供setter/getter方法,就可以让编译器知道它应该为property声明的属性,合成setter 和/或者 getter方法。
为了实现以上特性,编辑ViewController.m 文件,在@implementation 声明行的下面添加两行:
  1. @synthesize myQuotes; 
  2. @synthesize movieQuotes; 
@synthesize 提供默认的操作对象(object)的getting和setting方法。简单来说,这些方法允许你想数组里面添加数据或者检索数据以便显示。
现在你可以在myQuotes数组中存储你想要的对象的指针。在viewDidLoad方法中做这些操作,这个方法是当View(screen)显示的时候执行的。这个方法只执行一次,因此对象(引用)队列不回改变,所以viewDidLoad是执行这些操作的好的“地方”。
viewDidLoad的[super viewDidLoad];语句后,添加下面的代码。包括你想要添加的对象(指针)这个就是“手动实现-manual labor”的方法,并且对于比较少的数据量来说,这样实现还算ok。
  1. // 1 - Add array of personal quotes 
  2. self.myQuotes = [NSArray arrayWithObjects: 
  3.                       @"Live and let live",  
  4.                       @"Don't cry over spilt milk",  
  5.                       @"Always look on the bright side of life",  
  6.                       @"Nobody's perfect",  
  7.                       @"Can't see the woods for the trees"
  8.                       @"Better to have loved and lost than not loved at all"
  9.                       @"The early bird catches the worm"
  10.                       @"As slow as a wet week"
  11.                       nil]; 
这是调用方法的第一个例子。相比其他语言的语法,这样的语法比较难:
1.当调用方法的时候,你需要用方括号将你想要调用的方法名所属的对象名括起来。在这个例子中,我们将要调用一个NSArray的静态方法。
2.然后,写出方法名(方法的第一个部分),和一个冒号。在这个例子中就是arrayWithObjects。
3.然后写出第一个参数。“arrayWithObjects:”这个方法有一点特殊,因为这是一个变长参数方法,因此我们可以将想要添加的对象列表作为参数传递给数组,并以nil结尾。
4.如果方法有多个参数,你会继续以这样的方式,即使这个方法有一个参数(是一个对象列表)。
如果你还在为语法迷茫,不要担心—— 一会儿,我们还将会看到大量的调用方法的例子。
同时注意,在Objective-C,当你使用字符串的时候,要在字符串的前面添加“@”符号。如果你以前经常使用的是其他语言,很容在字符串前面添加“@”符号,这就会很容易引起app的崩溃。所以,当程序使用字符串的时候崩溃了,仔细检查你是否填添加了“@”符号。
SELF 关键字
使用“self”关键字,默认调用property声明的属性的setting 和 getting方法。“self”关键字和其他语言的“this”关键字相似,引用指向的对象是当前调用方法的对象。

你可以不通过“self”关键字直接访问实例变量,但是通过“self”关键字, 我们可以自动调用property声明的属性的getters和setters方法。除非你知道直接访问实例变量的原因。不然使用self关键字对于初学者是一个好的习惯。
每次分配了一个“保留的(retained)”属性,确保你在ViewDidUnload 方法中清楚了这个属相,如下代码:
  1. movieQuotes=nil; 
  2. myQuotes=nil; 
这很重要, 当view“倾销”的时候(在低内存出现的这种情况, 这是view就不可用了),确保你的对象(指针)数组被正确释放了。基本上代表性地操作就是在ViewDidUnload方法中做的操作和ViewDidLoad方法中的操作相反。 :]
好的,现在我们已经设置了这些对象(指针)数组,让我们试试它们!
首先,声明 要关联到XIB文件的接口元素和动作(interface elements and actions),将下面几行代码添加到ViewController.h文件中:
  1. @property (nonatomic, retain) IBOutlet UITextView *quote_text; 
  2.   
  3. -(IBAction)quote_btn_touch:(id)sender; 
IBOutlet 关键字指的是quote_text这个对象可以关联到XIB文件中的“接口元素(interface element)”,这样“视图控制器(view controller)”就可以访问(或者修改)“接口元素(interface element)”。这种情况下,我们就可以设置UITextView显示的文本,除此之外,我们也可以修改颜色,字体,大小,等等。
IBAction 关键字表明quote_btn_touch是一个响应方法, 是关联到屏幕UI控件事件的响应方法。这个例子中,我们将该方法关联到quote按钮的“触摸事件(touched event)”。
如果你感到意外,id 意味着“任何继承与NSObject类的实例化对象”。通常,当我们设置按钮或者其他控件的响应事件的回调方法,当事件发生,回调响应的方法,他们会将,按钮或者其他控件作为第一个参数传递给回调方法。所以我们不必知道参数是什么类型的,所以我们声明了一个id类型的参数。
一旦,你需要合成(synthesize)你新添加property声明的属性,在ViewController.m文件中添加以下语句:
  1. @synthesize quote_text; 
同时,不要忘记在ViewDidUnload方法property声明的属性:
  1. quote_text=nil; 
现在创建“事件响应方法(action method)”,当quote被点击时,该响应方法被调用。再文件下面部分(@end语句之上),添加下面的声明:
  1. -(IBAction)quote_btn_touch:(id)sender { 
  2.     // 1 - Get number of rows in array 
  3.     int array_tot = [self.myQuotes count]; 
  4.     // 2 - Get random index 
  5.     int index = (arc4random() % array_tot); 
  6.     // 3 - Get the quote string for the index  
  7.     NSString *my_quote = [self.myQuotes objectAtIndex:index]; 
  8.     // 4 - Display the quote in the text view 
  9.     self.quote_text.text = [NSString stringWithFormat:@"Quote:nn%@",  my_quote];       
arc4random 方法是用来产生随机数的。这种情况下,我们想要随机访问“对象(指针)队列里”的对象,随机数的最大值是数组中的有效的元素个数,最小值是0。再Objective-C(类似其他语言),数组的第一个元素是0,而不是1。
index 仅仅是一个临时变量,用来存储产生的随机数字 ,我们通过随机数字访问数组中特定的对象(指针),例子中的数组是一个简单的字符串数组,通过调用objectAtIndex: 方法来获得对象(指针),并将该指针存储再一个字符串类型的临时变量中。
然后你就可以使用临时的字符串变量my_quote 来设置quote_text控件的文本显示。
调用stringWithFormat方法格式化最终显示的字符串。它显示的是替代变量,和C/C++的printf类似。%f指的是float类型变量,%d 指的是 integer 类型变量,%@ 指的是 Objective-C 对象(object)类型。
现在,为了再屏幕中看到响应的字符串,你需要将类中的outlet的text field的对象和XIB文件中的text field控件相关联。
我们已经有所提升!
为了看到所有的响应事件的类型,打开ViewController.xib文件。接下来,查看一下xcode窗口的右侧边栏。如果没有看到右侧边栏,你可能需要在顶部的工具栏中,在设View部分点击最右边的按钮,这样就可以,显示右侧边栏。
再右侧边栏的下侧有4个标签,你可以通过点击图标切换。下部可以查看UI控件的“Object Library”。
从“Object Library”中,拖拽一个Text View控件和Round Rect 按钮控件到view上。按照你一意愿在view上排列这些控件。在按钮上添加标题,例如“Quote”。你可以按照意愿改变控件的颜色和字体。你可以在右侧边栏的上半部分的几个标签中修改控件的大部分属性——这样你可以在“Attributes Inspector”标签定制控件的外观。
因为text field只是用来显示,还有相应的事件——可编辑。
现在你需要将那个button和text view关联到类中声明的outlet 和 action。
关联选中text view右击鼠标,点击“New Reference Outlet”那个圆圈,拖拽到“File’s Owner”,松开,再弹出框中选择quote_text。
二者择一,你可以简单的在“File’s Owner”中操作,或者在右侧边栏的顶部切换到“Connections Inspector”标签。在File’s Owner中你可以看见controller类中所有的可关联的变量。你现在可以简单关联中拖拽到要关联的UI控件上。
现在,你可以通过代码修改quote_text对象,来设置设置text view文本显示的内容。
同样,我们也可以绑定添加到XIB文件中按钮的触摸事件到quote_btn_touch响应方法。选中xib中要关联的按钮,再右侧边栏中在Touch Up Inside选项前拖拽到“Files’s Owner”,并再弹出框中选择 quote_btn_touch。
另外, 你可以简单的选中XIB 视图中的 button,在右侧边栏Connections Inspector中,你可以看见button事件的列表。现在从“Touch Up Inside”事件拖拽到“File’s Owner”,然后你就会获得一个可能的响应事件方法的列表。选择一个你想要的。
想不到吧?你可以准备游戏啦。点击Xcode的Run 按钮(Xcode窗口顶部的第一个按钮)。在你的模拟器里完成应用程序的编译和运行。
如果这有报错,不要恐慌。这个阶段,报错应该是自说明的,通常是你声明的变量类型有误。记住,xcode是区分大小写。
如果你的应用程序通过编译并运行,点击Quote 按钮获取随机的对白对象。没有那么多对白限制了一点兴奋度。但是别担心,你将要加载另外一组数组,通过它你可以添加任意数量的对白,因为它们不会在代码中。
你问,“那又怎样?”。
啊,属性列表的乐趣将要显露!我是属性列表的忠实粉丝。
Property Lists Rule!
用iOSCocoa TouchObjective-C 模板创建一个新文件。命名为 SMNote, 然后设置其为 UIDocument的子类。
在左侧边栏(项目导航栏)的你的项目的根节点处点击右键,选择“New File …”来创建一个新文件。选择 iOSResourceProperty List,然后点击“Next”。选择一个位置来保存你的新文件(在教程中我们通常选择在项目文件夹的里面)并命名为“quotes”。
你可以在XCode的网格视图中编辑属性表或者像文本文件一样编辑。如果你想要像文本文件一样处理,在导航栏的quotes 文件点击右键然后选择Open AsSource Code。
因为我们要通过复制黏贴来快速的添加所有对白,以源码的形式打开(即以文本文件方式)可能会更加快捷。如果你想的话,你也可以尝试在网格视图的方式来尝试弄清楚怎样增加下面框框中同样的内容。
现在,复制黏贴以下的电影对白信息到quotes 中(在文本编辑模式下)
  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"
  3. <plist version="1.0"
  4.   
  5.     <array> 
  6.         <dict> 
  7.             <key>category</key>  <string>classic</string> 
  8.             <key>quote</key>  <string>Frankly, my dear, I don't give a damn.</string> 
  9.             <key>source</key>  <string>Gone With the Wind</string> 
  10.         </dict> 
  11.   
  12.         <dict> 
  13.             <key>category</key>  <string>classic</string> 
  14.             <key>quote</key>  <string>Here's looking at you, kid.</string> 
  15.             <key>source</key>  <string>Casablanca</string> 
  16.         </dict> 
  17.   
  18.         <dict> 
  19.             <key>category</key>  <string>classic</string> 
  20.             <key>quote</key>  <string>There's no place like home.</string> 
  21.             <key>source</key>  <string>The Wizard of Oz</string> 
  22.         </dict> 
  23.     <dict> 
  24.         <key>category</key>  <string>classic</string> 
  25.         <key>quote</key>  <string>Play it again, Sam.</string> 
  26.         <key>source</key>  <string>Casablanca</string> 
  27.     </dict> 
  28.      <dict> 
  29.         <key>category</key>  <string>classic</string> 
  30.         <key>quote</key>  <string>Elementary, my dear Watson.</string> 
  31.         <key>source</key>  <string>Sherlock Holmes</string> 
  32.     </dict> 
  33.   
  34.         <dict> 
  35.             <key>category</key>  <string>modern</string> 
  36.             <key>quote</key>  <string>Go ahead, make my day.</string> 
  37.             <key>source</key>  <string>Dirty Harry</string> 
  38.         </dict> 
  39.   
  40.         <dict> 
  41.             <key>category</key>  <string>modern</string> 
  42.             <key>quote</key>  <string>May the Force be with you.</string> 
  43.             <key>source</key>  <string>Star Wars</string> 
  44.         </dict> 
  45.         <dict> 
  46.             <key>category</key>  <string>modern</string> 
  47.             <key>quote</key>  <string>Hasta la vista, baby.</string> 
  48.             <key>source</key>  <string>Terminator 2: Judgement Day</string> 
  49.         </dict> 
  50.         <dict> 
  51.             <key>category</key>  <string>modern</string> 
  52.             <key>quote</key>  <string>It takes a great deal of bravery to stand up to your enemies, but a great deal more to stand up to your friends.</string> 
  53.             <key>source</key>  <string>Harry Potter and the Sorcerer's Stone</string> 
  54.         </dict> 
  55.         <dict> 
  56.             <key>category</key>  <string>modern</string> 
  57.             <key>quote</key>  <string>I solemnly swear that I am up to no good.</string> 
  58.             <key>source</key>  <string>Harry Potter and the Prisoner of Azkaban</string> 
  59.         </dict> 
  60.   
  61.         <dict> 
  62.             <key>category</key>  <string>modern</string> 
  63.             <key>quote</key>  <string>You like pain? Try wearing a corset.</string> 
  64.             <key>source</key>  <string>Pirates of the Caribbean</string> 
  65.         </dict> 
  66.     </array> 
  67. </plist> 
这里只是使用一些对白来作为例子。你乐意的话可以增加一些你喜欢的。如果你懒,示例项目中有一个有很多对白的属性表。对白被分类成了经典和现代两个种类,稍后用来说明一个非常实用的功能。
你也可以切换到属性表视图(在quotes 文件右键然后选择Open AsProperty List)来看看你刚才加的值以及他们的组织形式。现在你已经懂得如何在不同的编辑方式下处理,你可以随你喜欢的来回切换。
属性表看起来很酷,但是如果有错误的时候你可能会很不爽。新手常见错误就是忘记增加末尾标识或者意外的删除了< or >。如果你的属性表不能正常加载,那你就必须去找出为什么。
如果你卡在这里,你需要有条不紊的浏览你的文件。我常常这么做以求变的更简单:复制我的plist文件,然后一次删除一个代码块来大致的确定我的错误的位置。
创建完你可爱的属性表后,你现在已经做好把它加载进一个数组来使用的准备。切换回 ViewController.m ,在viewDidLoad后面加上以下内容:
  1. // 2 - Load movie quotes 
  2. NSString *plistCatPath = [[NSBundle mainBundle] pathForResource:@"quotes" ofType:@"plist"]; 
  3. self.movieQuotes= [[NSMutableArray arrayWithContentsOfFile:plistCatPath] copy]; 
就是这么简单—-现在你有了一个你输入进属性表的所有电影对白数据的数组。
看看你的新数组,你可能认为你现在最需要做的是改变从电影对白数组中随机获得的数据。所以,在 quote_btn_touch 中有简单的把movieQuotes的数据替换成myQuotes 的例子。
但是如果你尝试过你会发现这不会生效。这是因为因为myQuotes 是一个字符串数组。但是movieQuotes 并不是一个字符串数组。恰恰相反,这这是一个字典数组,字典是一个有着一个列表的值,你可以通过一个独一无二的键来访问他们。
为什么呢?因为那就是你设置成属性表的的样式。(再看看它!)
注解: 字典是用来保存键/值的,和其他语言的哈希表很像。你可以看看字典中的valueForKey 方法。
因此用下文的内容来替换quote_btn_touch,代码中使用movieQuotes 数组,来获取每个字典,而且根据正确的键值获取了对白:
  1. -(IBAction)quote_btn_touch:(id)sender { 
  2.     // 1 - Get number of rows in array 
  3.     int array_tot = [self.movieQuotes count]; 
  4.     // 2 - Get random index 
  5.     int index = (arc4random() % array_tot); 
  6.     // 3 - Get the quote string for the index  
  7.     //NSString *my_quote = [self.myQuotes objectAtIndex:index]; 
  8.     NSString *my_quote = [[self.movieQuotes objectAtIndex:index] valueForKey:@"quote"]; 
  9.     // 4 - Display the quote in the text view 
  10.     self.quote_text.text = [NSString stringWithFormat:@"Quote:nn%@",  my_quote];       
让第三行代码保持在注释状态,因为这稍后会派上用场。编译运行然后享受你的新成果!
现在,你可以有点花俏的允许用户在myQuotes 或movieQuotes中选择经典电影或现代电影台词了。
选项, 选项, 选项
首先你需要回到你的ViewController.h,头文件并增加一个属性。
  1. @property (nonatomic, retain) IBOutlet UISegmentedControl *quote_opt; 
在这里你增加了一个允许你从一堆选项选出一项的分段控件-这对于我们选取对白的种类是多么完美。
当然,你需要synthesize 你的新属性。在 ViewController.m 的头部(其他@synthesize语句那一带)增加以下内容:
  1. @synthesize quote_opt; 
现在切换到ViewController.xib 并且拖一个分段控件(UISegmentedControl )到你的视图上。
根据以下内容改变控件的属性:
Style: Bar (my personal preference)
Tint: whatever you like
Segments: 3
Select Segment: 0 and change the title to: Classic
Select Segment: 1 and change the title to: Modern
Select Segment: 2 and change the title to: Mine
这达到了有3个不同的对白种类的效果,更确切的说,你可以在3个选项中选择一个了。
H创建完了分段控件,你必须把它和类文件中的outlet 属性连接起来。你可以使用同样的方法,就像之前把控件和File‘s owner中的quote_opt联接起来一样。
对于这个控件,你不需要定义动作事件。
在你做其他事情之前,记得清理 ViewDidUnload里这个新的属性。
  1. quote_opt=nil; 
为什么不在屏幕上看看你的新控件? 它现在还不能做任何事,不过看到它在那儿还是挺不错的。
判断的乐趣
判断是一个过滤数组非常有用的对象。有点儿像SQL语句中select的从句。我发现他们对于分类属性列表很有用。这使我不必再创建单独的属性列表。
不要恨我,你要回到并改变 quote_btn_touch: 在 ViewController.m 中用myQuotes 代替
movieQuotes,你很快会为你的电影对白做一些很不同的事。你需要设置一个条件,所以只有当你选择Segmented控件的第三个选项才能使用它。
或者,如果你愿意,只需要用下面的代码来更换 quote_btn_touch: :
  1. -(IBAction)quote_btn_touch:(id)sender { 
  2.     // 1 - Get personal quotes when the final segment is selected 
  3.     if (self.quote_opt.selectedSegmentIndex == 2) { 
  4.         // 1.1 - Get number of rows in array 
  5.         int array_tot = [self.myQuotes count]; 
  6.         // 1.2 - Get random index 
  7.         int index = (arc4random() % array_tot); 
  8.         // 1.3 - Get the quote string for the index  
  9.         NSString *my_quote = [self.myQuotes objectAtIndex:index]; 
  10.         // 1.4 - Display the quote in the text view 
  11.         self.quote_text.text = [NSString stringWithFormat:@"Quote:nn%@",  my_quote]; 
  12.     } 
现在只有当用户选择第三个选项,才能看见myQuotes。正如你会发现剩下的代码跟以前一样,唯一的不同是只有当选择控制器index为2的选项被选择的时候我们显示一个对白(并且这个对白来自这个人的对白列表)。你可能还记得,选择控制器是从index为0开始的,index 2就意味着第三个选项。
编译并测试你的代码,确保它能像你期望地那样运行,仅当“Mine”选项被选时quotes才出现。
为了判断的乐趣,你得基于选择部分的控件断定类别,然后使用类别来创建一个过滤后符合该类别的对白数组。继续跟我做!
这些代码是quote_btn_touch: 中if语句的另一部分 – 将这添加到这个方法的末尾来完成section #1中的“if”语句是如此简单:
  1. // 2 - Get movie quotes 
  2. else { 
  3.     // 2.1 - determine category 
  4.     NSString *selectedCategory = @"classic"
  5.     if (self.quote_opt.selectedSegmentIndex == 1) { 
  6.         selectedCategory = @"modern"
  7.     } 
  8.     // 2.2 - filter array by category using predicate 
  9.     NSPredicate *predicate = [NSPredicate predicateWithFormat:@"category == %@", selectedCategory]; 
  10.     NSArray *filteredArray = [self.movieQuotes filteredArrayUsingPredicate:predicate]; 
  11.     // 2.3 - get total number in filtered array 
  12.     int array_tot = [filteredArray count]; 
  13.     // 2.4 - as a safeguard only get quote when the array has rows in it 
  14.     if (array_tot > 0) { 
  15.         // 2.5 - get random index 
  16.         int index = (arc4random() % array_tot); 
  17.         // 2.6 - get the quote string for the index  
  18.         NSString *quote = [[filteredArray objectAtIndex:index] valueForKey:@"quote"]; 
  19.         self.quote_text.text = [NSString stringWithFormat:@"Movie Quote:nn%@",  quote]; 
  20.     } else { 
  21.         self.quote_text.text = [NSString stringWithFormat:@"No quotes to display."]; 
  22.     } 
好了,编译并运行吧。检查你所选择对白的正确类型.如果你总是取到同样的类型,我猜测你没有链接选择控制器到你的类中。
字符串交响乐
到目前为止,都很不错!现在让我们一起探索Objective-C中不同的字符串设置和语法。
如果对白是属性列表中的一个数据源,那么程序会将它显示出来。检查下如果字符串中有值,你就能核对字符串的长度。
在section #2的第一行后添加如下代码到 quote_btn_touch:(t第一行不包括他们的评论):
  1. // 2.7 - Check if there is a source     
  2. NSString *source = [[filteredArray objectAtIndex:index] valueForKey:@"source"]; 
  3. if (![source length] == 0) { 
  4.     quote = [NSString stringWithFormat:@"%@nn(%@)",  quote, source]; 
  5. // 2.8 - Set display string 
你从数组中获得数据并检查它包含一个确保长度不为零的值。! 当你检查一个整数是否等于另一个值时,不要用 == 。
接着你可以使用stringWithFormat创建一个新的显示字符串连接对白和数据源。
为了让事情更有趣,为什么不让经典电影的对白显示得稍显不同?这需要检查所选择的对白类别值。
用以下代码替换section #2.8 quote_btn_touch: 中的内容:
  1. // 2.8 - Customize quote based on category 
  2. if ([selectedCategory isEqualToString:@"classic"]) { 
  3.     quote = [NSString stringWithFormat:@"From Classic Movienn%@",  quote]; 
  4. else { 
  5.     quote = [NSString stringWithFormat:@"Movie Quote:nn%@",  quote]; 
  6. // 2.9 - Display quote 
  7. self.quote_text.text = quote; 
检查字符串是否等于一个特定的值,在这个例子中是“classic”,并基于类别自定义对白的label。
如果你想检查一个特定的电影标题(或针对这方面的其他字符串属性)开始于一个特定的值,你也可以这么做。你说如果对白引自《哈利·波特》电影想显示一些额外的文本--在section #2.9上添加如下代码:
  1. if ([source hasPrefix:@"Harry"]) { 
  2.     quote = [NSString stringWithFormat:@"HARRY ROCKS!!nn%@",  quote]; 
你也能猜到,hasPrefix 是用来检查是否一个字符串的开始是否有一个特定的文本值。
构建并运行你的应用程序以确保它如你期望得那样运行。注意,确保不同的类别和哈利·波特电影对白都正确运行。
It’s ARRAYning Quotes
为了娱乐,当对白不是很多时,你要把所有的对白连结在一起。这将说明如何循环数组,如果你想遍历数组中的每一项并做处理。
quote_btn_touch: 中用以下部分替换section #1:
  1. // 1 - Display all personal quotes 
  2. if (self.quote_opt.selectedSegmentIndex == 2) { 
  3.     // 1.1 - Get array count 
  4.     int array_tot = [self.myQuotes count]; 
  5.     // 1.2 - Initialize string for concatenated quotes     
  6.     NSString *all_my_quotes = @""
  7.     // 1.3 - Iterate through array     
  8.     for (int x=0; x < array_tot; x++) { 
  9.         NSString *my_quote = [self.myQuotes objectAtIndex:x]; 
  10.         all_my_quotes = [NSString stringWithFormat:@"%@n%@n",  all_my_quotes,my_quote]; 
  11.     } 
  12.     self.quote_text.text = [NSString stringWithFormat:@"%@", all_my_quotes];      
使用for循环来遍历该数组从0行到最后一行。x 是这些行的计数。
现在运行并检查这些结果。
最后一件事,我在前面提到过,有不同类型的数组:NSArray NSMutableArray。到目前为止,它们在这个项目中做同样的工作。
如果你想更改或更新数组,那么使用NSMutableArray。正如其名所提示的,可变数组能改变,然而普通的数组是静态的,你不能方便地在数组中添加项或删除项。
举个例子,如果你想在一行被选中后更新数组来展示已经被显示的对白,就需要NSMutableArray。
在这个项目中,movieQuotes就是NSMutableArray。你要使用一个判定, 所以首先你要在movieQuotes中找到该行接着更新。在quote_btn_touch:里添加如下代码到section #2.9后:
  1. // 2.10 - Update row to indicate that it has been displayed 
  2. int movie_array_tot = [self.movieQuotes count]; 
  3. NSString *quote1 = [[filteredArray objectAtIndex:index] valueForKey:@"quote"]; 
  4. for (int x=0; x < movie_array_tot; x++) { 
  5.     NSString *quote2 = [[movieQuotes objectAtIndex:x] valueForKey:@"quote"]; 
  6.     if ([quote1 isEqualToString:quote2]) { 
  7.         NSMutableDictionary *itemAtIndex = (NSMutableDictionary *)[movieQuotes objectAtIndex:x]; 
  8.         [itemAtIndex setValue:@"DONE" forKey:@"source"]; 
  9.     } 
你遍历该数组并检查每一行以确认它是不是你正找的那行。再使用isEqualToString;,然而这次是比较两个字符串的值。
为了更新数组中的行,你在问题中检索行中的对象并更新它。对于本教程来说这有点超前,但这是有必要知道的。
在我们更新了数据字符串,这个数据字符串是用来选择每个类别中的对白,如果你使用NSPredicate来过滤数组,下次该行将不会被包含在内。这相当方便。
去哪儿?
下面是一个包含上面教程所有代码的示例项目 。
好了,你已经到了这个小项目的结尾。你学到了用不同的方法使用数组、通过接口事件初始化action、在一份XIB文件中通过Interface Builder连接对象、各种字符串的比较和连结。如果这是你的第一个iPhone应用程序,那么会有不错的效果!
现在你知道一些基础知识了,你可能想要试下我们的How To Create a Simple iPhone App 系列指南,或者注册我们每月的时讯,里面有为初学者制作的史诗般长度的iOS教程。
关于你已经完成的,如果你有任何问题,都可以使用我们论坛。同时,如果你喜欢这个教程并希望看到这个系列的更多内容,请在论坛上让我知道!
与此同时,祝你们好运和保持快乐! :]
此文由iOS教程团队成员Linda Burke发布,她是一个印度的iOS开发者、canApps的创始人。

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多