首页 » iOS编程(第4版) » iOS编程(第4版)全文在线阅读

《iOS编程(第4版)》8.2 UITableViewController

关灯直达底部

UITableView是视图。第1章中介绍过模型-视图-控制器(Model-View-Controller),它是iOS开发者必须遵守的一种设计模式。其含义是,应用创建的任何一个对象,其类型必定是以下三种类型中的一种。

•模型:负责存储数据,与用户界面无关。

•视图:负责显示界面,与模型对象无关。

•控制器:负责确保视图对象和模型对象的数据保持一致。

一般来说,控制器用来控制应用的流程,例如,在删除数据之前必须提示用户:“Really delete this item?(确定要删除该条数据吗?)”

因此,作为视图对象的UITableView不应该负责处理应用的逻辑或数据。当在应用中使用UITableView对象时,必须考虑如何搭配其他的对象,与UITableView对象一起工作:

•通常情况下,要通过某个视图控制对象来创建和释放UITableView对象,并负责显示或隐藏视图。

•UITableView对象要有数据源才能正常工作。UITableView对象会向数据源查询要显示的行数、显示表格行所需的数据和其他所需的数据。没有数据源的UITableView对象只是空壳。凡是遵守UITableViewDataSource协议的Objective-C对象,都可以成为UITableView对象的数据源(即dataSource属性所指向的对象)。

•通常情况下,要为UITableView对象设置委托对象,以便能在该对象发生特定事件时做出相应的处理。凡是遵守UITableViewDelegate协议的对象,都可以成为UITableView对象的委托对象。

UITableViewController对象可以扮演以上全部角色,包括视图控制对象、数据源和委托对象。

UITableViewController是UIViewController的子类,所以也有view属性。UITableViewController对象的view属性指向一个UITableView对象,并且这个UITableView对象由UITableViewController对象负责设置和显示。UITableViewController对象会在创建UITableView对象后,为这个UITableView对象的dataSource和delegate赋值,并指向自己(见图8-4)。

图8-4 UITableViewController和UITableView之间的关系

创建UITableViewController子类

下面要为Homepwner编写一个UITableViewController子类。这次要使用NSObject模板。选择File菜单中的New菜单项,然后选择File…选中窗口左侧iOS部分的Cocoa Touch,然后选中窗口右侧的Objective-C class,最后单击Next按钮。在新出现的面板中,在Class文本框中输入BNRItemsViewController,在Subclass of下拉菜单中选择NSObject,单击Next按钮。Xcode会提示创建文件,单击Create按钮。

打开BNRItemsViewController.h,修改BNRItemsViewController的父类,代码如下:

#import <Foundation/Foundation.h>

@interface BNRItemsViewController : NSObject

#import <UIKit/UIKit.h>

@interface BNRItemsViewController : UITableViewController

UITableViewController的指定初始化方法是initWithStyle:。调用initWithStyle:时要传入一个类型为UITableViewStyle的常数,该常数决定了UITableView对象的风格。目前可以使用的UITableViewStyle常量有两个,即UITableViewStylePlain和UITableViewStyleGrouped。两种风格的外观在iOS 6中差异很大,但是在iOS 7中非常相似。

现在将UITableViewController的指定初始化方法改为init:,为此需要遵守以下两条规则:

•在新的指定初始化方法中调用父类的指定初始化方法。

•覆盖父类的指定初始化方法,调用新的指定初始化方法。

在BNRItemsViewController.m中实现以下两个初始化方法。

#import /"BNRItemsViewController.h/"

@implementation BNRItemsViewController

- (instancetype)init

{

// 调用父类的指定初始化方法

self = [super initWithStyle:UITableViewStylePlain];

return self;

}

- (instancetype)initWithStyle:(UITableViewStyle)style

{

return [self init];

}

实现以上两个初始化方法后,可以确保无论向新创建的BNRItemsViewController对象发送哪一个初始化方法,初始化后的对象都会使用UITableViewStylePlain风格。

打开BNRAppDelegate.m,在application:didFinishLaunchingWithOptions:中创建一个BNRItemsViewController对象,并将其设置为UIWindow的rootViewController。此外,还要在BNRAppDelegate.m顶部导入BNRItemsViewController的头文件,代码如下:

#import /"BNRItemsViewController.h/"

@implementation BNRAppDelegate

- (BOOL)application:(UIApplication *)application

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

self.window = [[UIWindow alloc] initWithFrame:

 [[UIScreen mainScreen] bounds]];

// 在这里添加应用启动后的初始代码

// 创建BNRItemsViewController对象

BNRItemsViewController *itemsViewController =

[[BNRItemsViewController alloc] init];

// 将BNRItemsViewController的表视图加入窗口层次结构

self.window.rootViewController = itemsViewController;

self.window.backgroundColor = [UIColor whiteColor];

[self.window makeKeyAndVisible];

return YES;

}

构建并运行应用,虽然只能看到一个空白屏幕,但是屏幕上确实存在一个空的UITableView对象(见图8-5)。BNRItemsViewController作为UITableViewController的子类,继承了view方法。view方法会调用loadView方法,如果视图不存在,则loadView方法会创建并载入一个空的视图。因为UITableViewController对象的视图类型是UITableView,所以向UITableViewController对象发送view消息会得到一个空的UITableView对象。

图8-5 空的UITableView对象

下面要为UITableView对象设置内容。这里借用第2章编写的BNRItem类,并将表格行和BNRItem对象对应起来,一行对应一个BNRItem对象。在Finder中找到BNRItem类的头文件和实现文件(BNRItem.h和BNRItem.m),并将这两个文件拖曳至Homepwner的项目导航面板。

在Xcode弹出的下拉窗口,选中Copy items into destination group/'s folder(拷贝文件或目录至目标组的目录),单击Finish按钮。Xcode会先将BNRItem.h和BNRItem.m拷贝至Homepwner的项目目录,然后将拷贝后的新文件加入Homepwner项目。

本章中不需要使用BNRItem的containedItem和container属性(它们只是用来演示强引用循环),因此,在BNRItem.h文件中删除以下代码:

@property (nonatomic, strong) BNRItem *containedItem;

@property (nonatomic, weak) BNRItem *container;

同时,在BNRItem.m中删除setContainedItem:方法:

- (void)setContainedItem:(BNRItem *)i

{

_containedItem = i;

// 将item加入容纳它的BNRItem对象时,

// 会将它的container实例变量指向容纳它的对象

self.containedItem.container = self;

}