Objectively Speaking: A Crash Course in Objective-C for iOS 6 平心而论:一堂专门为IOS 6准备的 objective-C 速成班【肥牛翻译】

Tweet

If you're new here, you may want to subscribe to my RSS feed or follow me on Twitter. Thanks for visiting!

QuoteGen_sign1-e1334922514301

Warning: Objective-C Crash Course Ahead!

Note from Ray: This tutorial is now fully up-to-date for iOS 6, and uses Modern-Objective-C syntax. Here’s the pre iOS 6 version if you need it!

This is a post by iOS Tutorial Team Member Linda Burke, an indie iOS developer and the founder of canApps.

原作者为Linda burke,一个独立IOS开发者,以及canApps公司的创始人。

Are you a software developer skilled in another platform, but want to start learning iPhone development (and hence Objective-C)? This was my situation not so long ago, and frankly, I’d gotten a bit rusty from moving further and further away from development in my day job.

或许屏幕前的你曾是其他语言/平台的程序员,踌躇不定是否投入到iPhone开发的浪潮去。而这正是我不久前遇到的情况,不过随着我狠下心来,并且越多地在晚上对objective-c投入钻研,到现在反而对早班一直运用的语言感到些许生疏了。

Some two years later, I’ve created a lot of apps for the iPhone and iPad. While I often had to learn the hard way, I’d like you to be able to benefit from some of my trials and tribulations.

两年后,楼主我已经创建了一定数量的iphone及ipad上的应用,不过期间过程相当艰难,特在此奉上我的被爆菊经验,希望大家能从中受益。

This tutorial is for readers who already have some programming experience. It assumes that you know your while loop from your fruit loops and a debug from a lady bug! If you’re completely new to programming, you might want to check out our iOS for High School Students series.

若你对编程完成陌生,可以完成以下for 高校生系列:http://www.raywenderlich.com/5600/ios-for-high-school-students-getting-started

The goal of this tutorial is to give you confidence with some of the basics of Objective-C. Instead of taking a “let’s explain every piece of syntax” approach, you’re going to take the approach of diving right in and giving you some hands-on experience and an example to work from. It will then be a lot easier for you to consult a reference (like this one) when necessary moving forward.

这篇教程将不会一块一块的教你objectiveC语法,相反,我们将让您动手敲,通过运行一个又一个成功的栗子来给你增加在iPhone开发道路上前进的自信。

In this tutorial, you will create a simple app that randomly generate quotes from a stored list. In doing so, you’ll become acquainted with a number of aspects of Objective-C, including:

  • Variables
  • Arrays
  • Property lists
  • Strings
  • Predicates
  • Random selection
  • Simple interface objects and events

在这个教材里,你将学会创建一个从列表中随机抽取谚语的应用,通过这个过程,你将会熟悉objective C的以下方面:

  • Variables 变量
  • Arrays 数组
  • Property lists 属性列表
  • Strings 字符串
  • Predicates 谓词
  • Random selection 随机选择
  • Simple interface objects and events 简单交互对象及事件

Let me warn you though – iPhone development with Objective-C is a lot of fun and a little addictive. Be prepared to give up some sleep, and the chores might build up! :]

Before you begin, make sure you have an Apple developer account with the provisioning details set up and the latest version of Xcode installed (you can download this for free on the Mac App Store).

When you’re done, I will (Objective) C-you after the jump! :]

学习iPhone开发的过程充满着乐趣甚至可能会让你轻微的上瘾。准备好少点睡觉,来面对即将到来的难题吧。

开始之前请准备好iPhone开发者帐号、硬件、最新版本的xcode啪啦啪啦……等等。

Getting Started

上路吧

First things first: create an Xcode project. This tutorial is written for Xcode 4.5+ and iOS 6+ – if you have an older version of Xcode, you should either upgrade or check out the pre iOS 6 version of this tutorial.

创建基于xcode的项目,该教程基于xcode版本4.5以上,以及IOS sdk版本6.0以上,若你的xcode版本过低可选择升级xcode或查看较早前教程。

Start up Xcode and create a new project with the iOS\Application\Single View Application template.

Enter QuoteGen for the product name, set device family to iPhone, and make sure Use Automatic Reference Counting and Use Storyboards are checked (but leave the other checkboxes unchecked). Now click Next and select the location to save your project.

创建新项目使用单一view模板: iOS\Application\Single View Application

输入 QuoteGen 作为项目名称、device选择iPhone、确保仅勾选了Use ARC 以及 Use storyboards,下一步并选择项目存储位置。

Screen-Shot-2012-09-18-at-5.45.40-PM-475x320

You will notice that your project has been created with AppDelegate.h, AppDelegate.m, ViewController.h and ViewController.m files, as well as a MainStoryboard.storyboard.

你会发现项目已自动为你创建以下文件

Screen-Shot-2012-09-18-at-5.47.08-PM

The AppDelegate contains the code that initiates the app. For this tutorial, that’s all you need to know. Here are brief explanations of the other files, with which you will be working directly:

The AppDelegate 包含了初始化应用的代码,对于该教程来说,这个是你当前仅需要记住的事情。稍后将直接打交道的文件,我们在底下做一些简短说明,

  • MainStoryboard.storyboard is the interface layout file. You visually create/design the screens that are displayed on the iPhone device using this file.
  • ViewController.m is the interface controller class. The interface layout file is linked to this class. This happens automatically, so at this stage you don’t need to think about it other than to know that any objects or events you set up in your interface class can be linked to your interface layout very easily. This is the file that will contain the Objective-C code you’re about to create.
  • ViewController.h is the interface controller class header file, where you’ll declare the instance variables, as well as the objects and events that you need to access from the interface screen.
  • MainStoryboard.storyboard 交互界面布局文件,ios设备上的界面元素均可该文件上进行可视化的创建及设计.

     

 

  • ViewController.m 交互界面控制文件,楼上的storyboard文件即链接到此文件.这个地方会包含你将要创建的的Objective C代码.
  • ViewController.h 头文件,声明实例变量、或交互界面访问的对象、事件、方法的地方.
  • Note: There are two ways to create interfaces in Xcode – with Storyboards and with Xcode Interface Builder files (XIBs). Either way works fine, in this tutorial we’ll be using Storyboards since it’s the most common way these days. But the two methods are quite similar – if you understand one you’ll have an easy time understanding the other.

    注:实际上Xcode有两种方法创建交互界面,一种是使用storyboard,另外一种是使用XIBs。由于前者逐渐成为主流,在本教材中我们将会使用stroyboard方法,实际上两种方法相当类似,读者可以触类旁通。

    For more information on Storyboards, check out this tutorial when you’re done.

    若想了解更多Storyboard的相关信息,可以浏览这里: http://www.raywenderlich.com/5138/beginning-storyboards-in-ios-5-part-1

    Heading in the Right Direction

    开往正确的方向

    QuoteGen_car-e1334922858347

    The first thing you need to do is create some variables for the quotes you want to display in this app – normal quotes and movie-related quotes.

    To do this, you will create two Objective-C properties. There’s some subtle aspects to properties, but for now just think of them as a way to create variables on your class.

    It’s very easy to create a property – let’s try it out by adding a property for an array of quotes. Add this line to ViewController.h, between the @interface and @end lines:

    首先需要创建APP应用中用以展示的谚语,这里假设包含两类,一般谚语和电影中的谚语。

    因此,将会创建两个properties,properties中有一些微妙的属性设置,但我们暂时只认为这是创建变量的一种方法;

    ViewController.h, @interface 和 @end之间,输入以下代码   

    @property(nonatomic, strong)NSArray*myQuotes;

    Let’s break this down bit-by-bit:

    • First you need to add the @property keyword.
    • Then you list the property attributes. Without going too deeply into this topic – the nonatomic attribute increases performance at the cost of thread-safety, and the strong attribute indicates that a pointer to the specified variable will stay in memory as long as the object that holds the pointer exists.
    • Then you list the type of the property. Here you choose NSArray *, which means “pointer to an NSArray class.” NSArray is a handy class provided by Apple that stores lists of data – we’ll talk more about this soon.
    • Finally, you add the property name.

    我们一点一点来看:

    • 添加 @property  关键字.
    • 这里我们将看到 @property 列出的属性,在不太深入该话题的情况下稍作讲解 – nonatomic 属性增加性能表现的同时保障了线程的安全, –  strong 属性意味者指向特定变量的指针将一直保留在内存直到保存该指针的变量消失.
    • 接下来选择 @property 的数据类型NSArray *. 含义是创建指向NSArray 类的指针,NSArray 是一由苹果提供的便于存储数组数据的类,我们将会在以后更多的讨论她。
    • 最后,我们加上 @property 的名称.

    By adding this single line, you now have a variable you can set and get on this class!

    Note: In the old days, you also had to @synthesize your properties after creating them, and in the really old days you had to manually declare your instance variables as well. This is no longer the case – now all you need to do to add a property is add this single line!

    Also in the old days, you used to have to do all the memory management yourself, but now with a new feature called Automatic Reference Counting (ARC) it’s automatic. To read more about ARC, check out this tutorial.

    Am I showing my age by knowing all this? :]

    注:很久以前,在创建property后依然需要@synthesize 才能使用,很久很久以前,还需要手工去声明实例变量,现在这些操作均简化了。

    This app is also going to store some famous quotes from movies. For this, you need a second array:

    App还将存储一些电影里常见的谚语,因此,我们需要建立第二个数组去存放:

  • 1 @property(nonatomic, strong)NSMutableArray*movieQuotes;

     

    Here you’re using an NSMutableArray simply to illustrate the different types of arrays. The difference is you cannot add or remove items to an NSArray after you create it, but you can add or remove items from NSMutableArray whenever you want.

    这里我们使用了NSMutableArray,与NSArray的区别在于在创建NSArray后将不能对数组进行新增或删除,但NSArray却不受该限制;

    Manual Labor

    体力劳动

    QuoteGen_manual-e1334922702406

    Now you can store your favorite quotes in the myQuotes array. You’ll do this in viewDidLoad, which is the method that executes when the view (screen) is first created.

    现在你可以存储你喜欢的谚语到 myQuotes 数组当中了,需要在view(视图)第一次创建时,加载的方法viewDidLoad中完成。

    In viewDidLoad, add the following code after [super viewDidLoad];. Include your own favorite quotes if you like. This is the “manual labor” approach and is quite okay for a small number of array entries.

    在 [super viewDidLoad]; 后增加以下代码,你也可以在数组中包含你自己喜欢的谚语,若数量不大,这个体力活也算比较轻松的。

    // 1 - Add array of personal quotes self.myQuotes = @[
     @"Live and let live",  
          @"Don't cry over spilt milk",  
          @"Always look on the bright side of life",  
          @"Nobody's perfect",  
          @"Can't see the woods for the trees",  
          @"Better to have loved and lost then not loved at all",  
          @"The early bird catches the worm",  
          @"As slow as a wet week"
    ];

    Here you are setting the myQuotes property to a list of quotes. There’s some funky syntax you might not be used to here, so let’s break it down.

    • self is a special keyword that means “this current class” – kind of like this in other programming languages.
    • You can access properties on the class by using a dot, and then typing the name of the property – i.e. self.myQuotes lets you access the myQuotes property you created earlier.
    • To create an array, there’s a handy new shortcut in Objective-C – @[ item1, item 2, item 3 ].
    • Each item in the array is a string. To create strings in Objective-C, you need to prefix them with the @ symbol. If you’re used to other languages, this can be easy to forget, which will probably cause your app to crash :] So if your app crashes when it uses a string, double check you remembered to use the @ symbol!

    这样我们便完成了myQuotes数组的设置,这里包含了一些有趣的语法,我们可以一起来看看:

    • self  代表当前的类,为系统关键词 –  像在别的语法中的  this  .
    • 可以通过Dot表达式来获取属性, – i.e. self.myQuotes 让你可以访问较早时候创建的对象.
    • 现在创建数组有了更简便的方法 – @[ item1, item 2, item 3 ].
    • 数组中的每一项均为字符串,在ObjectiveC中创建字符串,必须加前缀 @ .如果你同时还有使用其他编程语言,这将使得这个地方非常容易遗忘,要是您的程序崩溃的同时又使用到了string类型的变量,检查一遍看看是否遗漏了@前缀!

    Great – now you have an array of quotes ready to go. It’s time to add some code that will allow you to display a random quote on the screen!

    很好,现在谚语数组已经待命完毕了,是时候加上代码让随机谚语出线在屏幕上!

     

    Going to the Outlets

    朝输出口奔去

    You haven’t created the user interface yet, but when you do you’ll be adding a text view to show the quote, and a button to tap to get a random quote.

    To display a random quote to the screen, you’ll need two things – a reference to the text view so you can set the text appropriately, and notification when the button is tapped.

    But how do you connect what goes on in the interface with your code? Through some special keywords – IBOutlet and IBAction!

    到现在为止我们还未创建用户界面,但可预测的是,一旦创建我们必须新建一文本视图,以及一个按钮用于点击获取随机谚语。

    展示一个随机的谚语到屏幕,还将需要以下两个条件,1.一个指向文本视图的引用(指针)用来对内容进行设置;2.程序需要接受到按钮被按下这一事件;

    但我们是如何把用户界面及代码关联起来呢?答案是:IBOutlet 和 IBAction!

    Let’s see how this works, starting with an IBOutlet. Add the following to ViewController.h under the arrays:

    一起来看看是如何工作的把,从IBOutlet开始,把以下代码加入到 ViewController.h ,在arrays的下方:

    @property(nonatomic, strong) IBOutlet UITextView *quoteText;

    Here you declare a property just like before (for a UITextView class), but you mark it with a special keyword – IBOutlet.

    IBOutlet means that quote_text is an object that can be linked to an interface element on the XIB file so that the view controller can access (or change) properties of the interface element. In this case, we’ll be setting the displayed text for the UITextView control but you could just as easily change the color, font, size, etc.

    这里我们声明了一个property,UITextView类型,但标注了一个特别的关键词:IBOutlet。

    IBOutlet 意味着quoteText是一个可链接至XIB文件的交互界面元素,因此,视图控制器(view controller)将能访问并改变该界面元素。在当前的栗子下,我们可以对文本视图进行包括颜色、字体、大小的设置等。

    Next, add the following line of code after the list of properties:

    接下来,在properties底下添加以下代码:

    -(IBAction)quoteButtonTapped:(id)sender;

    This defines a method that you will implement in this class. This is the first time you’ve seen a method defined in Objective-C, so let’s go over it bit-by-bit:

    1. First you put a dash -, which indicates you are defining an instance method.
    2. Then you put the return value of the method. This particular method returns an IBAction, which is actually defined to void – i.e. the method returns nothing. But IBAction has another special property – it marks the method as something to you can connect to an action on a UI element. In this case, you’ll be hooking things up so when the button gets tapped, this method gets called.
    3. Next you put the name of the method – quoteButtonTapped in this case.
    4. Then you put a colon, and in parenthesis put the type of the fist parameter. id is a special type that means “any object that derives from NSObject”. Usually when you set up callbacks that buttons and other controls will call, they pass whatever button/control is sending the callback as the first parameter. Since you don’t necessarily know what type it is, you put id here.
    5. Then you put the name of the parameter – sender in this case.

    这将在类里头定义一个方法,稍后我们会实现她,这是我们第一次在Objective C里进行方法定义,我们一点一点来看:

    1. 首先输入了“-”,这表明我们将定义一个实例方法(肥牛:对应类方法的话,为“+”);
    2. 然后输入方法的返回类型,这里返回的是IBAction,实际上这里将什么都不返回(void),但IBAction这里有另外一层的含义,她标记了该方法将与UI界面元素上触发的动作绑定起来.在这个栗子中,我们将该方法与“按钮按下”绑定起来,当按钮按下时,将调用该方法。
    3. 第三步输入方法的名称 – quoteButtonTapped .
    4. 输入第一个参数,在括号内填写参数类型,id 意味着这个可能是任意的继承自NSObject的对象,由于IBAction方法一般均为界面的元素如按钮或其他交互触发,开发者亦无法知道具体是什么调用了该方法,因此这里放置id类型即可.
    5. 输入参数的名称– sender .

    If you had more than one parameter, you would just repeat steps 3-5 multiple times. The syntax of naming methods is a little strange in Objective-C, but you’ll like it when you get used to it.

    若有多于一个参数,只需要重复步骤3-5即可,刚开始学习时你或许会觉得Objective C的方法命名语法有点奇怪,只需要使用一段时间你将会很快习惯她。

    Next, switch to ViewController.m to add the implementation of quoteButtonTapped:. Add this to the end of the file (but above @end):

    下一步,转到文件ViewController.m来加入实现代码,把以下代码加到 @end的前面:

    -(IBAction)quoteButtonTapped:(id)sender {
    // 1 - Get number of rows in array
    int array_tot =[self.myQuotes count];  
    // 2 - Get random index
    int index =(arc4random()% array_tot);  
    // 3 - Get the quote string for the index
    NSString*my_quote = self.myQuotes[index];  
    // 4 - Display the quote in the text view  
    self.quoteText.text =[NSString stringWithFormat:@"Quote:\n\n%@",  my_quote];
    }

    Let’s go over this line by line:

    1. First you get the count of items in an array. This is the first example you’ve seen of calling a method in Objective-C. The syntax is a little strange – you put a bracket ([), then the name of the object you're calling the method on (self.myQuotes), then the name of the method you're calling (count). Finally, you end the method call with a close bracket (]). Note this method doesn’t take any parameters – you’ll see an example that does in step 4.
    2. Next you use the arc4random function to generate a random number. arc4random() is a regular C-style function (not a method), so you use the regular parenthesis syntax you know and love. In this case, since you want to randomly select one of the quotes, the highest possible value is the number of rows in the array, and the lowest possible value is 0. In Objective-C (like many other languages), the first row in an array is row 0, not 1.
    3. Next you look up an item in myQuotes. Objective-C’s new literal syntax allows you to access elements in an NSArray by simple subscripting like you can see here.
    4. Finally, you use stringWithFormat method to format the final output string so that you can display a label and add a new line before displaying the quote. It uses variable substitution, like printf in C/C++. %f is float, %d is integer, and %@ is Objective-C object.

    一行一行来看:

    1. 首先获取数组内的谚语数量.这里展示了方法的调用,使用“[ ]”,第一部分是调用方法的主体(类),第二部分是方法名称,注意到该方法并未包含参数,在第4步中,我们将看到包含参数的调用方法。
    2. 然后用到 arc4random 功能,为C语言的常规功能(非方法),生成随机数字 .该表达式生成数值范围在: 0~(总数-1),正如你猜想的一样,Objective C中的数组跟其他大多数语言一样,起于0,而非1。
    3. 接下来,将随机的谚语赋值至my_quote中。
    4. 最后,使用 stringWithFormat 方法格式化最好的输出结果,占位符%@ 代表的是Objective C 对象.

    Now in order to actually see the quote on the screen, you need to link the text field outlet in the class with a text field control in your XIB file.

    为了能在屏幕上真真切切的看到效果,我们还需要在XIB文件的界面交互和代码输出口进行链接。

     

    Hooking Up a Control

    链接控件至(输出口)

    To see it all in action, open up MainStoryboard.storyboard. Next, look for the right sidebar in your Xcode window. If you don’t see one, you might need to use the rightmost button under the Views section, on the toolbar at the top, to make the right hand sidebar visible.

    The lower part of the righthand sidebar has four tabs, which you can switch between using the icons at the top of that section. The section you want is the Object Library.

    打开MainStoryboard.storyboard,能看到所有的交互界面,接下来,找到xcode的右侧栏下半部的四个tab标签,当前用到的是交互对象库(Object Library)。

    From the Object Library, drag a Text View control and a Round Rect Button onto the view. Position them to your liking. Add a title to the button, such as “Quote”. Change the color and font for the controls as you see fit. You can change most properties for the controls via the upper part of the right hand sidebar which too has several tabs that you can switch between – the one you’ll use the most to customise the appearance of the controls is the Attributes Inspector tab.

    从交互对象库(Object Library)找到文本及圆角按钮交互控件,拖动并按你喜欢的样子摆放到视图上,给按钮加上标题“Quote”,在上方的属性检查栏中,你可以对控件的大多数属性进行自定义,如颜色、字体或大小等等;

    Screen-Shot-2012-09-18-at-6.54.50-PM-700x457

    As the text field is for display only, untick Behavior – Editable.

    由于这里的文本只是为了展示,因此没有勾选Behavior属性 Editable.

    QuoteGen_text_prop-245x320

    Now you need to link the button and the text view to the outlet and action you already set up in your class.

    Link your text view by control-clicking the View Controller in the left sidebar, and dragging to the text view. Release, and select quoteText from the popup that appears.

    是时候把按钮和文本链接到我们早已写好的代码上去了,按住左侧的View Controller并拖动到界面上的文本视图,松开,选择quoteText。

    Screen-Shot-2012-09-18-at-6.57.49-PM

    Alternatively, you can simply select the view controller in the left sidebar and then switch the top portion of the right hand sidebar to the Connections Inspector tab. You should see all the connections available for your View Controller. You can now simply drag from the available connection to the control visible on screen.

    除了以上这种方式外,也可以选择视图控制器后,转到右侧的链接检查标签,能看到所有的可用链接,亦可以在右侧栏中进行链接操作。

    Screen-Shot-2012-09-18-at-7.00.09-PM-700x149

    Remember the reason why the Storyboard knows about your quoteText property is because you added the IBOutlet keyword earlier!

    记住,Storyboard知道quoteText该对象的原因是你在之前申明了IBOutlet这个关键字!

    Hooking Up an Action

    链接交互动作(至方法)

    Hooking up an action on a control (such as a button tap) to a method is quite similar to the process of hooking up a control to a property.

    链接交互动作(如按下按钮)至方法与上一篇是类似的。

    This time, control-drag from the button up to the View Controller, release, and choose quoteButtonTapped: from the popup:

    这一次,从按钮处按下并拖动至左侧的视图控制,松开,选择quoteButtonTapped方法。【肥牛不推荐】

    Screen-Shot-2012-09-18-at-7.03.27-PM

    Alternatively, you can simply select the button, and if you have the Connections Inspector selected in the right hand sidebar, you’ll notice that you get a list of events for the button. You can drag from Touch Up Inside event to the View Controller there as well.

    除了以上方法,也可以在链接检查器中,对链接触发方式进行选择,并连接至触发方法。【由于更全面的链接方式选择,肥牛更推荐】

    Screen-Shot-2012-09-18-at-7.05.09-PM

     

    Let Her Rip!

    运行!

    Guess what? You’re ready to rock ‘n’ roll. Simply click on the Xcode Run button (the first button at the top of the screen) to compile and run your app in the simulator.

    马上到最让人热血沸腾的时候了!按下Run来进行编译及在模拟器中运行吧。

    QuoteGen_run

    If there are errors, don’t panic. At this stage, they should be self-explanatory. Often just typos when declaring your variables. Remember, Xcode is case-sensitive.

    If your app does compile and run, then click on the Quote button to get a random quote:

    要是出现错误,不要着急,在这个阶段通常是变量的名字打错字了,记住,Xcode是大小写敏感的。

    若APP正常编译并运行,试着点击Quote按钮获取随机谚语。

    QuoteScreen

    Allright – you have a functional app, and you’ve learned a ton about Objective-C already – you’ve created properties, your own method, made use of classes, and tons more!

    But wait – there’s more! Right now your list of quotes are hard-coded into the app. Wouldn’t it be a lot better if you could load them from an external file?

    Ah, the joys of property lists are about to be revealed!

    好了,您现在拥有了一个功能完善的APP应用,关于ObjectiveC也已经学习了大量的知识,包括创建properties,method、class以及其他,

    但等等,现在的谚语可是写死在程序里面,是不是从外部文件读取谚语会更合适呢?

    接下来,享受property list带来的乐趣吧!

    Property Lists Rule!

    配置文件列表规则

    QuoteGen_property-e1334923922912

    A property list is a special XML format defined by Apple that are designed to store basic data types like strings, numbers, arrays, and dictionaries. They are very easy to create, and to read and write from code, so they are a great way to get in small bits of data into your app.

    配置文件实际上是苹果为存储各种数据类型(如字符串、数组、数字等)而特别设计的XML格式列表。通过代码来创建、修改和读写配置文件列表均非常容易,因此这是一个非常好的方式来处理应用内的小量数据。

    Let’s try this out! Create a new file by right-clicking on your project root on the left sidebar (the Project Navigator) and selecting New File. Then select the iOS\Resource\Property List template and click Next. Select the location to save your new file (usually somewhere within the project folder for the tutorial project) and name the file quotes.plist.

    让我们来试试,右键左侧栏>New File>选择 iOS\Resource\Property List template >Next,   然后选择保存位置并命名为:quotes.plist

    You can either edit the property list file from within Xcode in a grid-view (as a list of properties) or as a text file. If you want to edit as a text file, right-click on the quotes file on the Project Navigator and select Open As\Source Code.

    你可以选择在两种模式下编辑,一种是默认的列表方式,另一种是文本形式,可以在导航栏右键quote 文件并选择以源代码形式打开。

    Since you want to quickly add all the quotes by copying and pasting, opening as source code probably would be the faster route. If you want though, you can try the grid view approach and try to figure out how to add the same values as below using that method.

    由于之前我们已经对谚语做了文本形式的录入,这里以源代码形式拷贝/粘帖 是一个更快的方式,当然你也可以尝试用第一种方法来达到相同的效果。

    Now, add your movie quotes by copying and pasting the following into quotes (in source code mode):

    将以下代码粘帖复制到quotes文件内(源代码形式):

    
    

    【xml代码块】

    These are just a few quotes to serve as examples. Have some fun and add your own favorites. If you’re feeling lazy, the sample project has a property list of many quotes.

    以上只是示例的一部分谚语,你也可以增加乐趣,尝试加入自己的谚语,如果你是个懒人,示例中的property list有大量的谚语。

    The quotes are categorized as either classic or modern to illustrate a really neat feature that we’ll get to a bit later.

    谚语被分类为经典以及现代来描绘它的显著特点,我们将在稍后讨论。

    You can also switch over to the Property List view (right-click on the quotes file on the Project Navigator and select Open As\Property List) to see how the values you added look in the grid view and how it is organised. Now that you know how the different editing modes work, you can always switch back and forth as you like.

    你也可以通过转换配置列表的查看方式,来区分两种方式是如何工作的。

    QuoteGen_warning

    Property lists are cool, but can be very uncool when you get an error. Common mistakes for newbies are forgetting the end tag or accidentally deleting a < or >. If your property list doesn’t load, then you’ll need to trawl through and work out why. Earlier versions of Xcode gave line numbers for errors. I think it was from version 4 onwards that this helpful feature was excluded.

    If you really get stuck, you need to methodically go through your file. I do this (a bit too often to be frank) to make it easier: copy my plist file, then remove chunks a bit at a time to identify the approximate location of the error.

    配置列表是非常酷的,除了它出错的时候,一般错误会发生在忘记结束标签了,或者是误删了“<”或“>”。

    若配置列表没有被正确的读取,则需要你重头检查看哪里出问题了。以往版本的Xcode会告知你错误的行数,但自从4以后,该有用的特性被移除了。

    Having created your lovely property list, you are now ready to load it into an array for use. So let’s switch back to ViewController.m and add the following to the end of viewDidLoad:

    已经把如此可爱的配置列表创建好后需要,现在需要把它读取到数组中使用,切换到 ViewController.m 文件,在viewDidLoad:后加入以下代码

    // 2 - Load movie quotesNSString*plistCatPath =[[NSBundle mainBundle] pathForResource:@"quotes" ofType:@"plist"];
    self.movieQuotes=[NSMutableArray arrayWithContentsOfFile:plistCatPath];

    It’s as easy as that – now you have an array with all of the movie quote data you entered in the property list!

    是如此的简单,现在你拥有以配置文件形式保存的一数组电影谚语!

    To try out your new array, you might think that all you really need to do is change getting the random quote from your personal quotes array to the movie quotes array. So, in quoteButtonTapped: you simply replace all references to myQuotes with movieQuotes, right?

    或许你认为我们只是改变了抽取谚语的数据源(从个人的谚语到电影谚语),而只需要修改方法quoteButtonTapped: 的变量,从 myQuotes 到 movieQuotes即可完成数据源的变更,对么?

    But that alone will not work, as you will find if you try it. This is because myQuotes was an array of quote strings. But movieQuotes is not an array of strings. Instead, it’s an array of dictionaries where a dictionary is a list of values where you can access each value based on a unique key.

    但只要试试就知道仅仅那改动是不够的,这是因为myQuotes是保存字符串的谚语数组,但movieQuotes 不是,她是存储一些些dictionaries的数组。

    Why? Because that’s how you set up the property list (go look at it again to see!)

    为什么会这样?可以看看我们是如何建立配置列表的。

    Note: Dictionaries are key/value stores, similar to hashtables in other languages. You can look up entries in a dictionary with the valueForKey method.

    注:dictionaries类似其他语言的hashtable。

    So replace quoteButtonTapped with the following code which switches over to using the movieQuotes array but also gets the quote by using the right key for each quote dictionary:

    因此我们用以下代码来将movieQuotes 数组替换掉原来的:

    -(IBAction)quoteButtonTapped:(id)sender {
    // 1 - Get number of rows in arrayint array_tot =[self.movieQuotes count]; 
    // 2 - Get random indexint index =(arc4random()% array_tot); 
    // 3 - Get the quote string for the index
    //NSString *my_quote = [self.myQuotes objectAtIndex:index];
    NSString*my_quote = self.movieQuotes[index][@"quote"]; 
    // 4 - Display the quote in the text view self.quoteText.text =[NSString stringWithFormat:@"Quote:\n\n%@",  my_quote];}

    Keep the commented out line in section #3 as it will come in handy later. Build and run and enjoy your new movie quotes!

    我们将在不久后对#3进行评论,运行程序看看我们的新谚语把!

    QuoteScreen2

    Awesome, now you have a file that can read quotes from an external file! This can be especially handy if you want someone else to fill in some quotes for you as you continue to work on your app.

    非常棒,现在你有了一个从外部文件读取谚语的应用了,这将对日后要维护内容时提供了极大的便利。

    Next you’re going to get a bit fancy and allow the user to select between viewing myQuotes or movieQuotes, and whether to view classic or modern movie quotes.

    接下来将创建允许用户从movieQuotes、经典或现代的谚语中去做选择性抽取。

    Options, Options, Options

    选项、选项和选项

    First you need to go back to your class header file, ViewController.h, and add a new property.

    首先需要回到头文件ViewController.h,,增加新的property

    @property(nonatomic, strong) IBOutlet UISegmentedControl *quoteOpt;

    Here you’ve added a property that you’ll hook up to a segmented control which will allow you to select one item from a list of options – perfect for selecting a quote type!

    这里我们增加了UISegmentedControl作为选项的控件-完美的选择! 

    Now go to MainStoryboard.storyboard and drag a Segmented Control onto your view.

    MainStoryboard.storyboard找到Segmented Control,并摆放至视图上。

    Screen-Shot-2012-09-18-at-7.19.51-PM

    Change the properties of the control to the following:

    • Style: Bar (my personal preference)
    • 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

    改变以下控件的属性:

    • Style: Bar (my personal preference)
    • Segments: 3
    • Select Segment: 0  并把标题改为 : Classic
    • Select Segment: 1  并把标题改为 : Modern
    • Select Segment: 2  并把标题改为 : Mine

    This achieves the effect of having three different quote types – or rather, the ability to select between one of the three.

    Having created your Segmented Control, you need to link it to the outlet in your class. You can use the same method as before to hook up the control to the quoteOpt property on the View Controller.

    可以用之前链接至输出口的方式,链接Segment至视图控制器。

    You will not need an action event for this control.

    该控件不需要触发交互事件。

    Why don’t you build and run to see your new control on screen? It won’t do anything at the moment, but it’s nice to know it’s there!

    运行看看?虽然按下按钮将不会发送任何事情,但可以看到控件已经生效。

    Screen-Shot-2012-09-18-at-7.19.51-PM1

     

    The Joy of Predicates

    谓词带来的愉悦

    A predicate is a useful object that filters an array. It’s a bit like having a select with a simple where clause in SQL. I find them quite useful when I have a categorized property list. It saves you from having to create separate property lists.

    谓词是有效的为数组进行过滤的对象,有点像SQL里的where条件,我发现当我对配置列表进行分类时,谓词有效的为我节省了时间。

    Don’t hate me, but you have to go back and change quoteButtonTapped: in ViewController.m to use myQuotes instead of movieQuotes, as you will soon do something quite different for your movie quotes. And you need to put a condition around it, so that you’ll only use this when the third option is selected in the Segmented Control.

    这里我们需要返回至ViewController.m中的quoteButtonTapped:方法,加入一些判断条件,重新使用myQuotes 来代替movieQuotes,不过这只发生在第三个选项被选中的时候。

    Or, if you prefer, simply replace quoteButtonTapped: with the following code:

    你可以重置quoteButtonTapped:方法使用以下代码:

    -(IBAction)quoteButtonTapped:(id)sender {
    // 1 - Get personal quotes when the final segment is selected
    if(self.quoteOpt.selectedSegmentIndex ==2)
    {// 1 - Get number of rows in array
    int array_tot =[self.myQuotes count];
     // 2 - Get random index
    int index =(arc4random()% array_tot);
     // 3 - Get the quote string for the index
    NSString*my_quote = self.myQuotes[index]; 
    // 4 - Display the quote in the text view 
    self.quoteText.text =[NSString stringWithFormat:@"Quote:\n\n%@",  my_quote]; 
    }}

    Now the user will see myQuotes only when they select the third option. As you’ll notice the rest of the code is the same as before, the only difference is that you display a quote (and that quote comes from the personal quote list) only when the segmented control has segment with index 2 selected. And as you might recall, since the segment control starts at index 0, index 2 means the third item.

    你是否意识到代码实际上跟上一个版本几乎一模一样,唯一区别只在于当segment 的序列为2时,展示myQuotes 的代码才生效(segment起于0,因此2代表第三个选项)。

    Build and test your code to make sure that it works as you expect and that the quotes show up only when the “Mine” tab/segment is selected.

    运行App看看是否按以上所述运行。

    For the predicate fun, first you figure out the category you need based on the selected segment control and then use the category to create a filtered array of quotes that matches the category. Stay with me!

    This is the code on the other side of the if statement in quoteButtonTapped: – so simply add this to the end of the method to complete the “if” statement begun in section #1:

    使用以下代码补全if表达语句:

    // 2 - Get movie quotes
    else{// 2.1 - determine category
    NSString*selectedCategory =@"classic"; 
    if(self.quoteOpt.selectedSegmentIndex ==1)
    { selectedCategory =@"modern"; }
    // 2.2 - filter array by category using predicate
    NSPredicate*predicate =[NSPredicate predicateWithFormat:@"category == %@", selectedCategory];
     NSArray*filteredArray =[self.movieQuotes filteredArrayUsingPredicate:predicate]; 
    // 2.3 - get total number in filtered array
    int array_tot =[filteredArray count]; 
    // 2.4 - as a safeguard only get quote when the array has rows in it
    if(array_tot < 0){
    // 2.5 - get random indexint index =(arc4random()% array_tot); 
    // 2.6 - get the quote string for the index
    NSString*quote = filteredArray[index][@"quote"]; 
           self.quoteText.text =[NSString stringWithFormat:@"Movie Quote:\n\n%@",  quote]; }
    else{ self.quoteText.text =[NSString stringWithFormat:@"No quotes to display."]; 
    }}

    Okay, build and run. Check that you see the right type of quote depending on your selection. If you are always getting the same type, my guess would be that you may not have linked the Segmented Control to your class.

    好了,运行吧,检查是否每个选项展示的谚语都正常的被展示,若均展示同一类型,我猜你可能还没有将Segmented Control链接到视图控制器。

    QuoteScreen3

    The String Symphony

    字符串乐章

    QuoteGen_harp-e1334923248867

    So far, so good! Now let’s explore some different string options and syntax in Objective-C.

    到目前为止还好!现在一起来看看Objective C中,字符串的一些其他属性和语法。

    If the quote has a source in the property list, then the app should display that as well. To check if there’s a value in a string, you can check the length of the string.

    若谚语在配置文件中有标明来源的属性,那么app应该把来源也展示出来,为了达到以上目地,可以先对字符串进行检查。

    So add the following to quoteButtonTapped: after the first line in section #2.6 (the first line not counting the comment, that is):

    在#2.6以后,增加以下代码至方法quoteButtonTapped:

    // 2.7 - Check if there is a source
     NSString*source =[[filteredArray objectAtIndex:index] valueForKey:@"source"];
    if(![source length]==0)
    { quote =[NSString stringWithFormat:@"%@\n\n(%@)",  quote, source];}
    // 2.8 - Set display string

    Also, comment out this line, you won’t need it anymore:

    //self.quoteText.text = [NSString stringWithFormat:@"Movie Quote:\n\n%@",  quote];

    You get the source from the array and check that it contains a value by making sure that its length is not zero. ! represents NOT. Use == when checking if an integer is equal to a value.

    首先检查数组中是否含有来源属性,是否为空,

    Then you build a new display string by combining the quote and the source using stringWithFormat.

    若非空,使用stringWithFormat 把 source至原quote内容中。

    To make things more interesting, why don’t you display something slightly different for quotes from classic movies that will involve checking the value of the category of the selected quote?

    为了让效果更有趣,不如试着将属于经典电影类型的谚语更突出展示?

    Replace section #2.8 in quoteButtonTapped: with the following:

    // 2.8 - Customize quote based on category
    if([selectedCategory isEqualToString:@"classic"])
    { quote =[NSString stringWithFormat:@"From Classic Movie\n\n%@",  quote];}
    else{ quote =[NSString stringWithFormat:@"Movie Quote:\n\n%@",  quote];}
    // 2.9 - Display quoteself.quoteText.text = quote;

    This checks if the string is equal to a specific value, in this case “classic”, and customizes the label for the quote based on the category.

    这将会检查特定的属性,这个栗子中,只要是classic分类的谚语将进一步自定义化。

    If you want to check for a particular movie title (or for that matter any other string attribute) starts with a particular value, you can do that too. Say you want to display some extra text if the quote is from a Harry Potter movie – add the following right above section #2.9:

    若你希望过滤特定的一部电影名称,如哈利波特,可加入以下代码:

    if([source hasPrefix:@"Harry"]){ quote =[NSString stringWithFormat:@"HARRY ROCKS!!\n\n%@",  quote];}

    As you can guess, hasPrefix is used to check if the start of the string has a particular text value.

    如你能看到的,能用来过滤字符串的起始文本字段。

    Build and run your app to make sure that it works as you expect it to. Pay attention to the different categories and to Harry Potter movie quotes to make sure that it all works correctly.

    看看APP是否如你所愿的运行,注意观察特别的电影如哈利波特谚语出现时,程序是否正常运行。

    QuoteScreen4

    It’s ARRAYning Quotes

    数组组成的谚语

    QuoteGen_umbrella-e1334923319666

    Just for fun, you’re going to concatenate all your quotes together, as there aren’t many. This will illustrate how to loop through an array, which you might need to do if you want to iterate over each item in an array to process each item.

    接下来,你将会专注于数组内所有的quotes,虽然他们总数并不多。下面将会讲述如何遍历数组内的每一个元素,以面对可能需要逐一处理元素的情况。

    In quoteButtonTapped: replace section #1 with the following:

    if(self.quoteOpt.selectedSegmentIndex ==2){
    // 1.1 - Get array count
    int array_tot =[self.myQuotes count]; 
    // 1.2 - Initialize string for concatenated quotes
    NSString*all_my_quotes =@""; NSString*my_quote =nil; 
    // 1.3 - Iterate through array
    for(int x=0; x < array tot xspan 
    style='font-size:12px;font-style:normal;font-weight:normal;font-family:monospace;color:rgb(0, 34, 0);'  >++)
    { my_quote = self.myQuotes[x];  
     all_my_quotes =[NSString stringWithFormat:@"%@\n%@\n",  all_my_quotes,my_quote]; } 
    self.quoteText.text =[NSString stringWithFormat:@"%@", all_my_quotes];}
    
    

    A for loop is used to loop through the array from row 0 to the last row. x is the counter that is used to keep track of the rows.

    Now run and check the results.

    for循环一般用于遍历数组对象,x是计算器,我们来看看运行结果:

    QuoteScreen5

    One last thing. I mentioned earlier that there are different types of arrays: NSArray and NSMutableArray. So far, each has done the same job in this project.

    之前我提到过,存在两种类型的数组,NSArrayNSMutableArray,到此,这两者在项目里都干着一样的活。

    Use an NSMutableArray if you want to modify/update it. As the name implies, a mutable array can be changed whereas a normal NSArray is static and you cannot add new items to the array or delete items from the array easily.

    For example, if you wanted to update the array after a row had been selected in order to show that that quote had already been displayed, you would need an NSMutableArray.

    从字面上的暗示可以猜到,NSMutableArray 可以用于需要修改/更新数组时、而NSArray 是静态且不能轻易加入/删除新元素到数组。

    In this project, movieQuotes is your NSMutableArray. You’re using a predicate, so you first need to find the row in movieQuotes and then update it. Add the following code after section #2.9 in quoteButtonTapped::

    在该项目中,movieQuotes 是NSMutableArray,因为我们需要找到对应的元素并更新,加入以下代码至#2.9 quoteButtonTapped:

    // 2.10 - Update row to indicate that it has been displayed
    int movie_array_tot =[self.movieQuotes count];
    NSString*quote1 = filteredArray[index][@"quote"];
    for(int x=0; x < movie_array_tot
     xspan style='font-size:12px;font-style:normal;font-weight:normal;font-family:monospace;color:rgb(0, 34, 0);'  >++)
    {NSString*quote2 = self.movieQuotes[x][@"quote"];
     if([quote1 isEqualToString:quote2])
    {NSMutableDictionary*itemAtIndex =(NSMutableDictionary*)self.movieQuotes[x];
            itemAtIndex[@"source"]=@"DONE"; 
    }}

    QuoteGen_loop

    You loop through the array and check each row to see if it’s the row you’re looking for. Again you use isEqualToString; this time, however, you’re comparing two string variables.

    To update the row in the array, you retrieve the object for the row in question and update the object. This is starting to get a bit advanced for this tutorial, but it’s useful to know.

    你遍历了数组来查找某一个元素,这里又一次用到了isEqualToString方法,来对比两个字符串中的内容。

    Since you’re updating the source string and since the source string is what is used to select quotes for each category, the row will not be included next time you use NSPredicate to filter the array. And that’s quite neat.

     

    Where to Go From Here?

    接下来去哪儿?

    Here is a sample project with all of the code from the above tutorial.

    这里有一份示例项目,其中包含所有以上的教程提到的代码。

    Well, you’ve reached the end of this little project. You’ve learned how to use arrays in different ways, initiate actions from interface events, access objects via Interface Builder using a XIB file and do various string comparisons and concatenations. That is not a bad effort if this is your first iPhone app!

    你已经完成这个小项目,已经学会了通过不同的方式来使用数组,初始化交互事件,通过storyboard访问界面元素,对不同的字符串做了对比及融合,若你是第一次创建APP,这将是不小的成就。

    Now that you know the basics, you might want to try out our How To Create a Simple iPhone App tutorial series, or sign up for our monthly newsletter for an epic-length iOS tutorial for beginners.

    现在你已经掌握基础知识了,或许你可以尝试以下 How To Create a Simple iPhone App这个教程,或注册为我们为初学者准备的史诗般的每月IOS教程。

    The forums are available if you have any questions about what you’ve done. Also, if you liked this tutorial and would like to see more in the series, please let me know in the forums!

    若遇上任何问题可到论坛上进行反馈,喜欢教程或希望能看到其他系列,请在论坛上告诉我即可!

    In the meantime, good luck and keep ‘appy! :]

    祝你好运和保持创建应用!

    LindaBurke.jpg

    This is a post by iOS Tutorial Team Member Linda Burke, an indie iOS developer and the founder of canApps.

    原作者为Linda burke,一个独立IOS开发者,以及canApps公司的创始人。

 

posted @ 2013-03-02 11:33  肥牛fatcow  阅读(393)  评论(0编辑  收藏  举报