Start Developing iOS Apps Today系列(十一)

Start Developing iOS Apps Today系列之应用程序

十一、教程:添加数据

      本教程以第二个教程(“教程:串联图”)中创建的项目为基础。您将用到从使用设计模式、使用 Foundation 以及编写自定类中学到的知识,在 ToDoList 应用程序中添加对动态数据的支持。

      本教程讲述了以下操作:

  • 使用常见的 Foundation 类

  • 创建自定数据类

  • 实现委托和数据源协议

  • 在视图控制器之间传递数据

      完成本教程中的所有步骤后,您的应用程序外观大致是这样的:

Start Developing iOS Apps Today系列(十一)_第1张图片
Start Developing iOS Apps Today系列(十一)_第2张图片

创建数据类

      现在就开始吧,请在 Xcode 中打开您的现有项目。

      目前,使用串联图的 ToDoList 应用程序有一个界面和一个导航方案。现在,是时候使用模型对象来添加数据储存和行为了。

      应用程序的目标在于创建一个待办事项列表,因此首先您将创建一个自定类XYZToDoItem来表示单个待办事项。您应该记得,XYZToDoItem类已经在编写自定类中讨论过。

创建 XYZToDoItem 类

  1. 选取“File”>“New”>“File”(或按下 Command-N)。

    这时将会出现一个对话框,提示您为新文件选取模板。

  2. 从左侧的 iOS 下方选择“Cocoa Touch”。

  3. 选择“Objective-C Class”,并点按“Next”。

  4. 在“Class”栏中,在XYZ前缀后键入ToDoItem。

  5. 从“Subclass of”弹出式菜单中选取“NSObject”。

  6. 如果您完全按照本教程操作,那么在这个步骤之前,“Class”标题可能是XYZToDoItemViewController。选取 NSObject 作为“Subclass of”后,Xcode 会知道您创建了一个正常的自定类,并移除了它先前添加的ViewController文本。

  7. 点按“Next”。

  8. 存储位置默认为您的项目目录。此处无需更改。

  9. “Group”选项默认为您的应用程序名称“ToDoList”。此处无需更改。

  10. “Targets”部分默认选定您的应用程序,未选定应用程序的测试。好极了,这些都无需更改。

  11. 点按“Create”。

      XYZToDoItem类很容易实现。它具有项目名称、创建日期,以及该项目是否已完成等属性。继续将这些属性添加到XYZToDoItem类接口。

配置 XYZToDoItem 类

  1. 在项目导航器中,选择XYZToDoItem.h。

  2. 将以下属性添加到该接口,使声明如下所示:

    1. @interface XYZToDoItem : NSObject

    2. @property NSString *itemName;
    3. @property BOOL completed;
    4. @property (readonly) NSDate *creationDate;

    5. @end

      检查点:通过选取“Product”>“Build”(或按下 Command-B)来生成项目。尽管该新类尚未实现任何功能,但是生成它有助于编译器验证任何拼写错误。如果发现错误,请及时修正:通读编辑器提供的警 告或错误,然后回顾本教程中的说明,确保所有内容与此处的描述相符。

载入数据

      您现在有一个类,可以用它作为基础来为单个列表项目创建并储存数据。您还需要保留一个项目列表。在XYZToDoListViewController类中跟踪此内容较为合适,视图控制器负责协调模型和视图,所以需要对模型进行引用。

      Foundation 框架有一个NSMutableArray类,很适合跟踪项目列表。此处必须使用可变数组,这样用户就可以将项目添加到数组。因为不可变数组NSArray在其初始化后将不允许添加项目。

      要使用数组,您需要声明并创建它。可以通过分配并初始化数组来完成。

要分配并初始化数组

  1. 在项目导航器中,选择XYZToDoListViewController.m。

    由于项目数组是表格视图控制器的实现细节,所以应该在 .m 文件中进行声明,而不是 .h 文件。此操作可让项目数组成为您自定类的私有数组。

  2. 将以下属性添加到接口类别中,它是由 Xcode 在您的自定表格视图控制器类中创建的。声明应该是这样的:

    1. @interface XYZToDoListViewController ()

    2. @property NSMutableArray *toDoItems;

    3. @end
  3. 在viewDidLoad方法中分配并初始化toDoItems数组:

    1. - (void)viewDidLoad
    2. {
    3.     [super viewDidLoad];
    4.     self.toDoItems = [[NSMutableArray alloc] init];
    5. }

      viewDidLoad的实际代码中有一些附加行被注释掉了,那些行是 Xcode 创建XYZListViewController时插入的。保留与否都没有影响。

      现在,您已经拥有了一个可以添加项目的数组。添加项目将在单独的方法loadInitialData中进行,并将通过viewDidLoad调用该方法。由于此代码是一个模块化任务,所以会进入其自身的方法中。当然您也可以将方法分离出来,从而提高代码的可读性。在真正的应用程序中,此方法可 能会从某种永久储存形式载入数据,例如文件。现在,我们的目标是了解表格视图如何处理自定数据项目,那么让我们创建一些测试数据来体验一下吧。

      以创建数组的方式创建项目:分配并初始化。然后,给项目命名。该名称将显示在表格视图中。按照此方法创建一组项目。

载入初始数据

  1. 在@implementation行下方,添加一个新方法loadInitialData。

    1. - (void)loadInitialData {
    2. }
  2. 在此方法中,创建几个列表项目,并将它们添加到数组。

    1. - (void)loadInitialData {
    2.     XYZToDoItem *item1 = [[XYZToDoItem alloc] init];
    3.     item1.itemName = @"Buy milk";
    4.     [self.toDoItems addObject:item1];
    5.     XYZToDoItem *item2 = [[XYZToDoItem alloc] init];
    6.     item2.itemName = @"Buy eggs";
    7.     [self.toDoItems addObject:item2];
    8.     XYZToDoItem *item3 = [[XYZToDoItem alloc] init];
    9.     item3.itemName = @"Read a book";
    10.     [self.toDoItems addObject:item3];
    11. }
  3. 在viewDidLoad方法中调用loadInitialData。

    1. - (void)viewDidLoad
    2. {
    3.     [super viewDidLoad];
    4.     self.toDoItems = [[NSMutableArray alloc] init];
    5.     [self loadInitialData];
    6. }

      检查点:通过选取“Product”>“Build”来生成项目。您应该会在loadInitialData方法的代码行上看到大量错误。第一行是出错的关键所在,错误提示应该是“Use of undeclared identifier XYZToDoItem”。这说明编译器在编译XYZToDoListViewController时不知道XYZToDoItem。编译器比较特别,您需要明确告知它应当注意什么。

让编译器注意您的自定列表项目类

  1. 在XYZToDoListViewController.m文件的顶部附近找到#import "XYZToDoListViewController.h"行。

  2. 紧接着在其下方添加以下行:

    1. #import "XYZToDoItem.h"

      检查点:通过选取“Product”>“Build”来生成项目。项目生成时应该没有错误。

显示数据

      目前,表格视图具有一个可变数组,预填充了几个示例待办事项。现在您需要在表格视图中显示数据。

      通过让XYZToDoListViewController成为表格视图的数据源,可以实现这一点。无论要让什么成为表格视图的数据源,都需要实施UITableViewDataSource协议。需要实施的方法正是您在第二个教程中注释掉的那些。创建有效的表格视图需要三个方法。第一个方法是numberOfSectionsInTableView:,它告诉表格视图要显示几个部分。对于此应用程序,表格视图只需要显示一个部分,所以实现比较简单。

在表格中显示一个部分

  1. 在项目导航器中,选择XYZToDoListViewController.m。

  2. 如果您在第二个教程中注释掉了表格视图数据源方法,现在请移除那些注释标记。

  3. 模板实现的部分如下所示。

    1. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    2. {
    3. #warning Potentially incomplete method implementation.
    4. // Return the number of sections.
    5.     return 0;
    6. }

    您想要单个部分,所以需要移除警告行并将返回值由 0 更改为 1。

  4. 更改numberOfSectionsInTableView:数据源方法以便返回单个部分,像这样:

    1. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    2. {
    3. // Return the number of sections.
    4.     return 1;
    5. }

    下一个方法tableView:numberOfRowsInSection:告诉表格视图要在给定部分中显示几行。现在表格中有一个部分,并且每个待办事项在表格视图中都应该有它自己的行。这意味着行数应该等于toDoItems数组中的XYZToDoItem对象数。

返回表格中的行数

  1. 在项目导航器中,选择XYZToDoListViewController.m。

  2. 您可看到模板实现的部分是这样的:

    1. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    2. {
    3. #warning Incomplete method implementation.
    4. // Return the number of rows in the section.
    5.     return 0;
    6. }

    您想要返回所拥有的列表项目的数量。幸运的是,NSArray有一个很方便的方法,称为count,它会返回数组中的项目数,因此行数是[self.toDoItems count]。

  3. 更改tableView:numberOfRowsInSection:数据源方法,使其返回正确的行数。

    1. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    2. {
    3. // Return the number of rows in the section.
    4.     return [self.toDoItems count];
    5. }

      最后一个方法,tableView:cellForRowAtIndexPath:请求一个单元格来显示给定行。到现在为止,您只是处理了代码,但是界面的绝大部分是针对行显示的单元格。幸运的是,Xcode 可让您轻松地在 Interface Builder 中设计自定单元格。首个任务是设计您的单元格,并告诉表格视图不要使用静态内容,而要使用具有动态内容的原型单元格。

配置表格视图

  1. 打开串联图。

  2. 在大纲中选择表格视图。

  3. 选定表格视图后,在实用工具区域中打开“Attributes”检查器 image: ../Art/inspector_attributes_2x.png

  4. 在“Attributes”检查器中,将表格视图的“Content”属性从“Static Cells”更改为“Dynamic Prototypes”。

      Interface Builder 会采用您配置的静态单元格,并将它们全部转换为原型。原型单元格,顾名思义,是使用您要显示的文本样式、颜色、图像或其他属性进行配置,并在运行时从数据 源获取其数据的单元格。数据源会为每一行载入一个原型单元格,然后配置该单元格来显示该行的数据。

      要载入正确的单元格,数据源需要知道单元格的名称,并且该名称也必须在串联图中进行配置。

      设定原型单元格名称时,也将配置另一个属性—单元格选择样式,该样式用于确定用户轻按单元格时单元格的外观。将单元格选择样式设定为“None”,使用户 轻按单元格时单元格不会高亮显示。这是当用户轻按待办事项列表中的项目,将其标记为已完成或未完成时,您想要单元格呈现的行为。稍后会在本教程中实现该功 能。

配置原型单元格

  1. 在表格中选择第一个表格视图单元格。

  2. 在“Attributes”检查器中,找到“Identifier”栏并键入ListPrototypeCell。

  3. 在“Attributes”检查器中,找到“Selection”栏并选取“None”。

      您也可以更改原型单元格的字体或其他属性。基本配置很容易完成,您可以轻松记下。

      下一步是实现tableView:cellForRowAtIndexPath:方法,让数据源为给定行配置单元格。表格视图在想要显示给定行时会调用此数据源方法。对于行数较少的表格视图,所有行可能会同时出现在屏幕上,所以表格中 的每一行都会调用此方法。但是,行数很多的表格视图在给定时间内只会显示全部项目中的一小部分。最有效的方式是让表格视图仅请求要显示行的单元格,而这一 点可通过tableView:cellForRowAtIndexPath:让表格视图实现。

      对于表格中的任何给定行,取回toDoItems数组中的相应条目,然后将单元格的文本标签设定为项目的名称。

在表格中显示单元格

  1. 在项目导航器中,选择XYZToDoListViewController.m。

  2. 找到tableView:cellForRowAtIndexPath:数据源方法。模板实现是这样的:

    1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    2. {
    3.     static NSString *CellIdentifier = @"Cell";
    4.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier     forIndexPath:indexPath];

    5. // Configure the cell...

    6. return cell;
    7. }

    该模板执行多个任务。它会创建一个变量来保存单元格的标识符,向表格视图请求具有该标识符的单元格,添加一个注释注明配置该单元格的代码应该写在哪里,然后返回该单元格。

    要让此代码为您的应用程序所用,需要将标识符更改为您在串联图中设定的标识符,然后添加代码来配置该单元格。

  3. 将单元格标识符更改为您在串联图中设定的标识符。为了避免拼写错误,请将串联图中的标识符拷贝并粘贴到实现文件中。该单元格标识符行现在应该是这样的:

    1. static NSString *CellIdentifier = @"ListPrototypeCell";
  4. 在 return 语句前,添加以下代码行:

    1. XYZToDoItem *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
    2. cell.textLabel.text = toDoItem.itemName;

      您的tableView:cellForRowAtIndexPath:方法应如下图所示:

  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  2. {
  3.     static NSString *CellIdentifier = @"ListPrototypeCell";
  4.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
  5.     XYZToDoItem *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
  6.     cell.textLabel.text = toDoItem.itemName;
  7.     return cell;
  8. }

      检查点:运行您的应用程序。您在loadInitialData中添加的项目列表应该在表格视图中显示为单元格。

将项目标记为已完成

      如果无法将待办事项列表中的项目标记为已完成,那么这个待办事项列表还不够好。现在,让我们来添加这样的支持。一个简单的界面应该可以在用户轻按单元格时 切换完成状态,并在已完成的项目旁边显示勾号。幸运的是,表格视图附带了一些内建行为,您可以利用这些行为来实现这样的简单界面。需要注意的是,在用户轻 按单元格时,表格视图要通知它们的委托。所以我们的任务是写一段代码,对用户轻按表格中的待办事项这个操作作出响应。

      您在串联图中配置XYZToDoListViewController时,Xcode 就已经让它成为表格视图的委托了。您要做的只是实现tableView:didSelectRowAtIndexPath:委托方法,使其响应用户轻按,并在适当时候更新您的待办事项列表。

      选定单元格后,表格视图会调用tableView:didSelectRowAtIndexPath:委托方法,来查看它应如何处理选择操作。在此方法中,您需要编写代码来更新待办项目的完成状态。

将项目标记为已完成或未完成

  1. 在项目导航器中,选择XYZToDoListViewController.m。

  2. 将以下代码行添加到文件末尾,在@end行正上方:

    1. #pragma mark - Table view delegate

    2. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    3. {

    4. }

    请试着键入第二行,而不是拷贝和粘贴。您将发现代码补全是 Xcode 最节省时间的功能之一。当 Xcode 显示出可能的补全建议列表时,请滚动浏览列表,找到想要的建议,然后按下 Return 键。Xcode 会为您插入整行。

  3. 您想要响应轻按,但并不想让单元格保持选定状态。添加以下代码,让单元格在选定后立即取消选定:

    1. [tableView deselectRowAtIndexPath:indexPath animated:NO];
  4. 在toDoItems数组中搜索相应的XYZToDoItem。

    1. XYZToDoItem *tappedItem = [self.toDoItems objectAtIndex:indexPath.row];
  5. 切换被轻按项目的完成状态。

    1. tappedItem.completed = !tappedItem.completed;
  6. 告诉表格视图重新载入您刚更新过数据的行。

    1. [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

      您的tableView:didSelectRowAtIndexPath:方法应如下图所示:

  1. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  2. {
  3.     [tableView deselectRowAtIndexPath:indexPath animated:NO];
  4.     XYZToDoItem *tappedItem = [self.toDoItems objectAtIndex:indexPath.row];
  5.     tappedItem.completed = !tappedItem.completed;
  6.     [tableView reloadRowsAtIndexPaths:@[indexPath]     withRowAnimation:UITableViewRowAnimationNone];
  7. }

      检查点:运行您的应用程序。您在loadInitialData中添加的项目列表在表格视图中显示为单元格。但当您轻按项目时,并没有任何反应。为什么呢?

      原因是您尚未配置显示项目完成状态的表格视图单元格。要实现此功能,您需要回到tableView:cellForRowAtIndexPath:方法,并配置单元格以在项目完成时显示指示。

      指示项目已完成的一种方式是在其旁边放置一个勾号。幸运的是,表格视图右边可以有一个单元格附属物。默认情况下,单元格中没有任何附属物;不过您可以进行更改,使其显示不同的附属物。其中的一个附属物就是勾号。您要做的是根据待办事项的完成状态,设定单元格的附属物。

显示项目的完成状态

  1. 前往tableView:cellForRowAtIndexPath:方法。

  2. 在设定单元格的文本标签的代码行下方添加以下代码:

    1. if (toDoItem.completed) {
    2. cell.accessoryType = UITableViewCellAccessoryCheckmark;
    3. } else {
    4. cell.accessoryType = UITableViewCellAccessoryNone;
    5. }

      您的tableView:cellForRowAtIndexPath:方法现在应如下图所示:

  1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
  2. {
  3.     static NSString *CellIdentifier = @"ListPrototypeCell";
  4.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
  5.     XYZToDoItem *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
  6.     cell.textLabel.text = toDoItem.itemName;
  7.     if (toDoItem.completed) {
  8.         cell.accessoryType = UITableViewCellAccessoryCheckmark;
  9.     } else {
  10.         cell.accessoryType = UITableViewCellAccessoryNone;
  11.     }
  12.     return cell;
  13. }

      检查点:运行应用程序。您在loadInitialData中添加的项目列表在表格视图中显示为单元格。轻按项目时,其旁边应该出现一个勾号。如果您再次轻按同一项目,勾号会消失。

添加新项目

      构建待办事项列表应用程序功能的最后一步是实现添加项目的能力。当用户在XYZAddToDoItemViewController场景的文本栏中输入项目名称,并轻按“Done”按钮时,您想要视图控制器创建一个新的列表项目并将其传递回XYZToDoListViewController,以显示在待办事项列表中。

      首先,您需要拥有一个列表项目来进行配置。就像表格视图那样,视图控制器是将界面连接到模型的逻辑位置。为XYZAddToDoItemViewController添加一个属性来保存新的待办事项。

将 XYZToDoItem 添加到 XYZAddToDoItemViewController 类

  1. 在项目导航器中,选择XYZAddToDoItemViewController.h。

    由于稍后需要从表格视图控制器访问列表项目,所以务必将其设为公共属性。这就是为什么要在接口文件XYZAddToDoItemViewController.h中声明它,而不在实现文件XYZAddToDoItemViewController.m中声明的原因所在。

  2. 将 import 声明添加到@interface行上方的XYZToDoItem类中。

    1. #import "XYZToDoItem.h"
  3. 将toDoItem属性添加到该接口。

    1. @interface XYZAddToDoItemViewController : UIViewController

    2. @property XYZToDoItem *toDoItem;

    3. @end

      要获得新项目的名称,视图控制器需要访问用户输入名称的文本栏。要实现此功能,请创建从XYZAddToDoItemViewController类到串联图中的文本栏的连接。

将文本栏连接到视图控制器

  1. 在大纲视图中,选择XYZAddToDoItemViewController对象。

  2. 点按窗口工具栏右上角的“Assistant”按钮,打开辅助编辑器。

    Start Developing iOS Apps Today系列(十一)_第3张图片

    右边的编辑器出现时,应该显示有XYZAddToDoItemViewController.m。如果未显示,请点按右边的编辑器中的文件名,并选取XYZAddToDoItemViewController.m。

    辅助编辑器可让您一次打开两个文件,以便能够在它们之间执行操作。例如,在源文件中键入一个属性,而源文件的对象又在接口文件中。

  3. 在串联图中选择文本栏。

  4. 按住 Control 键从画布上的文本栏拖到右边编辑器中的代码显示窗口,到达XYZAddToDoItemViewController.m中的@interface行正下方时停止拖移。

    Start Developing iOS Apps Today系列(十一)_第4张图片
  5. 在出现的对话框中,为“Name”栏键入“textField”。

    让选项的其余部分保持不变。您的对话框应如下图所示:

    Start Developing iOS Apps Today系列(十一)_第5张图片
  6. 点按“Connect”。

    Xcode 会将必要的代码添加到XYZAddToDoItemViewController.m,用于储存指向文本栏的指针,并配置串联图来设置该连接。

      另外,您需要知道何时创建项目。如果想要仅在“Done”按钮被轻按时才创建项目,那么请将“Done”按钮添加为 Outlet。

将“Done”按钮连接到视图控制器

  1. 在串联图中,打开辅助编辑器,将最右边的窗口设定为XYZAddToDoItemViewController.m。

  2. 在串联图中选择“Done”按钮。

  3. 按住 Control 键从画布上的“Done”按钮拖到右边的编辑器中的代码显示窗口,到达XYZAddToDoItemViewController.m中的textField属性正下方的行时停止拖移。

  4. 在出现的对话框中,在“Name”栏键入“doneButton”。

    保持选项的其余部分不变。对话框应如下图所示:

    Start Developing iOS Apps Today系列(十一)_第6张图片
  5. 点按“Connect”。

      您现在有了识别“Done”按钮的方式。由于想在轻按“Done”按钮时创建一个项目,所以需要知道该按钮何时被按下。

      当用户轻按“Done”按钮时,它会启动一个 unwind segue,返回到待办事项列表,这正是您在第二个教程中配置的接口。在 segue 执行前,系统通过调用prepareForSegue:,给所包含的视图控制器一次准备机会。这便是检查用户是否轻按了“Done”按钮的时候。如果是,将会创建一个新的待办事项。您可以检查轻按了哪一个按钮,如果是“Done”按钮,将会创建项目。

轻按“Done”按钮后创建项目

  1. 在项目导航器中选择XYZAddToDoItemViewController.m。

  2. 在@implementation行下方添加prepareForSegue:方法:

    1. - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    2. {
    3. }
  3. 在此方法中,请查看“Done”按钮是否按下。

    如果未按下就不存储项目,而是让方法返回但不执行任何其他操作。

    1. if (sender != self.doneButton) return;
  4. 查看一下文本栏中是否有文本。

    1. if (self.textField.text.length > 0) {
    2. }
  5. 如果有文本,将会创建一个新项目,并用文本栏中的文本为其命名。另外,请确保完成状态被设定为“NOfalse”。

    1. self.toDoItem = [[XYZToDoItem alloc] init];
    2. self.toDoItem.itemName = self.textField.text;
    3. self.toDoItem.completed = NO;

    如果没有文本,您就不需要存储项目,也不需要执行任何其他操作。

您的prepareForSegue:方法应如下图所示:

  1. - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
  2. {
  3.     if (sender != self.doneButton) return;
  4.     if (self.textField.text.length > 0) {
  5.         self.toDoItem = [[XYZToDoItem alloc] init];
  6.         self.toDoItem.itemName = self.textField.text;
  7.         self.toDoItem.completed = NO;
  8.     }
  9. }

      既然创建了一个新项目,那么就需要将该项目传递回XYZToDoListViewController,以便它可以将项目添加到待办事项列表。要完成此功能,请重新访问您在第二个教程中编写的unwindToList:方法。当用户轻按“Cancel”或“Done”按钮,XYZAddToDoItemViewController场景会在关闭时调用该方法。

      就像作为 unwind segue 目标的所有方法一样,unwindToList:方法也采用 segue 作为参数。segue 参数是从XYZAddToDoItemViewController展开并返回到XYZToDoListViewController的过渡。由于 segue 是两个视图控制器之间的过渡,所以知道它的源视图控制器是XYZAddToDoItemViewController。通过向 segue 对象请求其源视图控制器,您可以用unwindToList:方法访问储存在源视图控制器中的任何数据。目前,您想要访问toDoItem。如果它是nil,则该项目并未创建。原因可能是文本栏没有文本,或者是用户轻按了“Cancel”按钮。如果toDoItem有值,则可以取回该项目,再添加到toDoItems数组,并通过重新载入表格视图中的数据将其显示在待办事项列表中。

储存并显示新项目

  1. 在项目导航器中,选择XYZToDoListViewController.m。

  2. 将 import 声明添加到@interface行上方的XYZAddToDoItemViewController类中。

    1. #import "XYZAddToDoItemViewController.h"
  3. 找到您在第二个教程中添加的unwindToList:方法。

  4. 在此方法中,取回源视图控制器XYZAddToDoItemViewController,即您要展开的控制器。

    1. XYZAddToDoItemViewController *source = [segue sourceViewController];
  5. 取回控制器的待办事项。

    1. XYZToDoItem *item = source.toDoItem;

    这就是轻按“Done”按钮时创建的项目。

  6. 看看这个项目是否存在。

    1. if (item != nil) {
    2. }

    如果是nil,可能是“Cancel”按钮关闭了屏幕,或者是文本栏中没有文本,因此不必存储该项目。

    如果项目存在,请添加到toDoItems数组。

    1. [self.toDoItems addObject:item];
  7. 重新载入表格中的数据。

    因为表格视图不会跟踪其数据,所以数据源(在这个程序中是表格视图控制器)有责任通知表格视图何时有新数据供其显示。

    1. [self.tableView reloadData];

      您的unwindToList:方法应如下图所示:

  1. - (IBAction)unwindToList:(UIStoryboardSegue *)segue
  2. {
  3.     XYZAddToDoItemViewController *source = [segue sourceViewController];
  4.     XYZToDoItem *item = source.toDoItem;
  5.     if (item != nil) {
  6.         [self.toDoItems addObject:item];
  7.         [self.tableView reloadData];
  8.     }
  9. }

      检查点:运行您的应用程序。现在,当您点按添加按钮 (+) 并创建一个新项目时,它应该会显示在待办事项列表中。恭喜您!您已经创建了一个应用程序,它能接收用户的输入,将其储存在对象中,并在两个视图控制器之间传递该对象。对于基于串联图的应用程序,这是在场景之间移动数据的基础。

小结

      您差不多完成了开发 iOS 应用程序的入门之旅。最后一部分更详细地讲述了如何查询文稿材料,并且为您学习创建更高级的应用程序给出了一些后续建议。

你可能感兴趣的:(Start Developing iOS Apps Today系列(十一))