XCode4.3创建第一个ios入门项目,翻译至官方教程(四)

来源:互联网 发布:青云志网络播放量 编辑:程序博客网 时间:2024/04/27 22:45

 为用户的姓名添加一个属性

用户的姓名由一个字符串保存着,首先要为该字符串声明一个属性,这样你的代码才能引用它。请将此声明添加到视图控制器的头文件中(即 HelloWorldViewController.h)。

属性声明是一个指令,它会告诉编译器如何为变量生成存取方法(Access method),例如这里的用来保存用户姓名的变量。(完成添加属性声明之后,你会学到什么是存取方法。)

在本教程中,你无需对故事板文件进行任何改动。接下来的代码比较多,为了给自己腾出必要的工作空间,可以点按 View 按钮中的实用工具按钮关闭实用工具区域(或者点选 View > Utilities > Hide Utilities)。

如何为用户的姓名添加属性声明…

  1. 在工程导航栏中点选 HelloWorldViewController.h
  2. 在 @end 语句之前,为字符串添加一个 @property 语句。
    属性声明语句应该是这样的:

     

    @property (copy, nonatomic) NSString *userName;

    你可以将这行代码拷贝并粘贴到编辑器面板中,也可以手动输入。如果你要手动输入,就能注意到 Xcode 会针对你的输入提供补全建议。比方说你开始输入 @pro… 时 Xcode 就会猜测你可能想要输入 @property,于是就会在这行语句下面显示一个建议面板,如图:


如果该建议是正确的(如上图的例子),则可以按回车键接受之。
在你继续输入代码时,Xcode 也许会提供一系列建议让你挑选。比如在你输入 NSSt… 的时候,Xcode 可能会显示类似图中的补全建议:


当 Xcode 显示补全列表时,按回车键就可以接受当前高亮显示的那一个语句了。如果高亮显示的并非你所需的语句(比如上图中的例子),可以按方向键在列表中选择合适的项目。

要完成 userName 属性的实现,你还需要让编译器合成相应的存取方法。存取方法是用来读取或设置对象属性的值的方法(有时,存取方法也被称作“getter”和“setter”)。

Xcode 会产生一个警告,提示你必须合成相应的存取方法。在活动查看器里会显示一个黄色的警告符号,此时,你已经知道 Xcode 的警告是什么,所以不必查看警告的详细信息。若需要查看警告信息的具体内容,你可以点按活动查看器中的黄色警告图标,并在问题导航栏中查看细节。

在本篇教程里,你不会再用到问题导航栏。请点按导航选择条最左边的按钮返回工程导航栏。

接下来,你需要向视图控制器的实现文件(即 HelloWorldViewController.m)中输入代码,让编译器生成存取方法。

如何为用户的姓名属性生成存取方法…

  1. 在工程导航栏中点选 HelloWorldViewController.m
  2. 在 @implementation HelloWorldViewController 这行的下面,输入如下代码:

    @synthesize userName = _userName;

    输入这段代码之后,Xcode 就不会再警告你缺少存取方法了,于是警告图标也就从活动查看器中消失了。

当编译器遇到 @synthesize 指令时,它实际上会自动为你生成下面两个存取方法:

- (NSString *)userName
- (void)setUserName:(NSString *)newUserName

由于在 @synthesize 语句里的 userName 添加了一个下划线,编译器便知道 _userName 是 userName 属性的一个实例变量名称。而你之前没有为名为 _userName 的实例变量进行声明,这段代码就会向编译器请求为它也生成存取方法。

注意:编译器生成存取方法只会在已编译的代码中进行,而不会改动你的源代码文件。


实现 changeGreeting: 方法

在上一个章节“对视图进行调整”里,你配置了 Hello 按钮的动作,在用户轻敲按钮时它便给视图控制器发送一个 changeGreeting: 消息。为了响应此消息,你会让视图控制器在标签上显示一段文字,包含用户刚刚输入的内容。具体而言,changeGreeting: 方法应该:

  1. 从文本框取回字符串,并将视图控制器的 userName 属性值设置为这个字符串。
  2. 根据 userName 属性创建一个新字符串,并将其显示在标签上。

如何实现 changeGreeting: 方法…

  1. 在工程导航栏中点选 HelloWorldViewController.m

    你可能要移动到文件末尾才会看到 Xcode 为你添加的 changeGreeting: 存根实现。

  2. 将 changeGreeting: 方法的存根实现补全,请输入如下代码:

    - (IBAction)changeGreeting:(id)sender {

        self.userName = self.textField.text;

        NSString *nameString = self.userName;
        if ([nameString length] == 0) {
            nameString = @”World”;
        }
        NSString *greeting = [[NSString alloc] initWithFormat:@”Hello, %@!”, nameString];
        self.label.text = greeting;
    }

在 changeGreeting: 方法中有好几个有趣的地方:

  • self.userName = self.textField.text; 从文本框取回文字,并将视图控制器的 userName 属性值设置为该文字。
    在本篇教程中,你可能不会在其他地方用到存有用户姓名的这个字符串,但仍然需要明白它的作用:它是非常简单的一个模型对象,由视图控制器管理。通常情况下控制器会在自己的模型对象中保存关于应用数据的信息,该数据信息不应该被保存在用户界面元素中,例如 HelloWorld 的文本框。
  • NSString *nameString = self.userName; 会创建一个新的变量(类型为 NSString)并将它的值设为视图控制器 userName 属性的值。
  • @”World” 是一个字符串常量,由一个 NSString 类的实例来表示。如果用户运行应用时没有输入任何文字(即满足 [nameString length] == 0 这个条件),nameString 就会包含字符串“World”。
  • initWithFormat: 方法是由 Foundation 框架提供给你的。它根据你提供的格式化字符串的格式创建一个新的字符串(这一点和 C 语言中的 printf函数很相近,你也许对它比较熟悉)。
    在格式化字符串中,%@ 代表字符串对象的占位符。双引号中的其他字符则会原封不动地显示在屏幕上。

将视图控制器配置为文本框的委托

如果你构建并运行应用,你应该会发现点按按钮时标签显示“Hello World!”字样。可是当你点选了文本框并输入一些文字时,则会发现仍然无法通过点按 Done 来收起键盘。

在一个 iOS 应用中,一旦能够接受文字输入的 UI 元素成为 first responder 就会自动调出键盘。反过来,该元素失去 first responder 状态时键盘就会自动收起。(请回忆一下 first responder 是什么:它是在若干事件中第一个接收通知的对象,例如轻敲文本框就会呼出键盘。)虽然不能直接从你的应用给键盘发送消息,但你可以通过改变文字输入 UI 元素的 first responder 状态来呼出和收起键盘。

而 UITextFieldDelegate 协议是由 UIKit 框架定义的,其中包含了一个 textFieldShouldReturn: 方法,它在用户轻敲回车键(无论回车键的标题被改成什么)是被文本框调用。因为我们已经将视图控制器设为了文本框的委托(在上一章节“对视图进行调整”),你可以通过实现这个方法来强制文本框失去 first responder 状态,给它发送一个 resignFirstResponder 消息即可,通过这个方式就能收起键盘。

注意:协议从根本上讲就是一系列方法的集合。如果某个类遵守(或采用了)某个协议,它也就承诺一定会实现协议中规定的所有方法。(协议也可以包含可选方法。)委托协议指定了对象可能发送给委托的所有消息。

如何配置文本框的委托 HelloWorldViewController …

  1. 在工程导航栏中点选 HelloWorldViewController.m
  2. 实现 textFieldShouldReturn: 方法。
    这个方法会让文本框失去 first responder 状态。实现的代码如下:

     

    - (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
        if (theTextField == self.textField) {
            [theTextField resignFirstResponder];
        }
        return YES;
    }

    在本应用中,并非一定要包含 theTextField == self.textField 这个检查语句,因为只有一个文本框。不过这个模式非常值得反复使用,因为在某些情况下某个对象可能会成为类型相同的多个对象的委托,你就需要严格区分它们了。

  3. 在工程导航栏中点选 HelloWorldViewController.h
  4. 在 @interface 行的结尾添加 <UITextFieldDelegate>
    你的接口声明应该是这样的:

     

    @interface HelloWorldViewController : UIViewController <UITextFieldDelegate>

    这段声明指定了你的 HelloWorldViewController 类要采用 UITextFieldDelegate 协议。

最终测试应用

构建并运行应用吧。这一次,所有功能应该都已达到我们的预期效果。在 iOS 模拟器中,输入完你的姓名后点按 Done 按钮来收起键盘,然后点按 Hello 按钮在标签里显示“Hello, 你的姓名!”。

如果应用还是没能按照预期效果工作,你就需要排查一下问题了。下一章节“故障排除以及代码检查”里将介绍可能出错的几个地方。

本节回顾

那么,你终于把视图控制器的实现也做好了,你做出了你的第一个 iOS 应用,祝贺你!


 

如果你的应用仍然无法正常工作,请根据本章节来尝试进行故障排查。如果仍然无法找到错误,请按照本章节最后的代码清单和你的代码进行逐一比对。

代码和编译器警告

你的代码应该能够无警告并通过编译。如果发现有警告出现,建议你将它们当成错误来看待。因为 Objective-C 是个非常灵活的语言,有时候编译器顶多把一些地方判定成警告而不是错误。

检查故事板文件

作为一名开发者,如果发现有东西运行不正常,出于自然的直觉你大概会去检查源代码中的漏洞。但是在 Cocoa Touch 开发中,需要注意另一件事:你的应用中许多配置可能被“编码”到了故事板文件中。打个比方,如果你的连接不正确,应用也不会如预期那样正常工作。

  • 如果点按按钮后文字没有更新,则可能是按钮的动作没有和视图控制器正确连接,或者是视图控制器的插座变量没有和文本框或者标签正确连接。
  • 如果你点按 Done 按钮后键盘并未收回,则有可能是文本框的委托或者视图控制器的 textField 插座变量没有跟文本框正确连接。请务必检查故事板中文本框的连接情况:按住 Control 键并点按文本框,调出半透明的连接面板。你应该看到 delegate 插座变量以及 textField 引用旁边是带有填充的圆形。

    如果你确实连接了委托,那么可能存在某些更加微妙的问题(参看下边的“委托方法名称”)。

委托方法名称

委托中常见的一个错误就是拼错委托方法的名称。就算正确设定了委托对象,但是如果委托没有使用方法实现中的正确名称,则正确的方法就永远也不会被调用。最好的建议是从开发者文档中拷贝和粘贴委托方法的声明,比如 textFieldShouldReturn:

代码清单

在这个部分,HelloWorldViewController 类的接口和实现文件都被完全罗列出来。需要注意的是本代码清单不包含由 Xcode 模板提供的其他方法实现以及代码注释。

接口文件:HelloWorldViewController.h

#import <UIKit/UIKit.h>

@interface HelloWorldViewController : UIViewController <UITextFieldDelegate>

@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (nonatomic, copy) NSString *userName;

- (IBAction)changeGreeting:(id)sender;

@end

实现文件:HelloWorldViewController.m

#import “HelloWorldViewController.h”

@implementation HelloWorldViewController

@synthesize textField=_textField;
@synthesize label=_label;
@synthesize userName=_userName;

 
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
    if (theTextField == self.textField) {
        [theTextField resignFirstResponder];
    }
    return YES;
}

- (IBAction)changeGreeting:(id)sender {
    self.userName = self.textField.text;

    NSString *nameString = self.userName;
    if ([nameString length] == 0) {
        nameString = @”World”;
    }
    NSString *greeting = [[NSString alloc] initWithFormat:@”Hello, %@!”, nameString];
    self.label.text = greeting;
}
@end


XCode4.3创建第一个ios入门项目,翻译至官方教程(一)
XCode4.3创建第一个ios入门项目,翻译至官方教程(二)
 

XCode4.3创建第一个ios入门项目,翻译至官方教程(三)