本文使用Three20库,生成只有一个section的TTTableViewController页面。
操作步骤:
1.修改main.m中UIApplicationMain(argc, argv, nil, nil)调用的第四个参数为应用程序的代理类名。例如:你应用程序的代理类为AppUsingThree20AppDelegate,则将第四个参数修改为@"AppUsingThree20AppDelegate"。
2.新建一个UIViewController,命名为“AppUsingThree20ViewController”使其继承自TTTableViewController。
3.加入相关的头文件并在应用程序代理类的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中加入如下代码:
//获得TTNavigator的单实例
TTNavigator *navigator = [TTNavigator navigator];
//设置该navigator中view的保存模式
navigator.persistenceMode = TTNavigatorPersistenceModeAll;
//设置该navigator中URL与Object的映射关系
TTURLMap* map = navigator.URLMap;
//对于全局URL“*”,设置与其映射的对象为TTWebController的实例
//该设置的作用在于当打开一个未建立映射关系时,不会报错而是将TTWebController加入到当前的页面关系中
[map from:@"*" toViewController:[TTWebController class]];
//设置URL“tt://catalog”所映射的对象为AppUsingThree20ViewController的实例
[map from: @"tt://catalog" toSharedViewController:[AppUsingThree20ViewController class]];
if (![navigator restoreViewControllers]) {
//打开相应的URL的对象并执行操作
[navigator openURLAction:[TTURLAction actionWithURLPath:@"tt://catalog"]];
}4.在AppUsingThree20ViewController.m文件中添加“- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil”方法,加入如下代码:
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
self.title = @"Three20 Table";
self.navigationItem.backBarButtonItem =
[[[UIBarButtonItem alloc] initWithTitle:@"Table" style:UIBarButtonItemStyleBordered target:nil action:nil] autorelease];
self.tableViewStyle = UITableViewStyleGrouped;
}
return self;5.在AppUsingThree20ViewController.m文件中添加“- (void)createModel”方法,加入如下代码:
self.dataSource = [TTSectionedDataSource dataSourceWithObjects:@"Photos", [TTTableTextItem itemWithText:@"Photo Browser" URL:@"tt://photoTest"], nil];URL与Action映射关键类图

流程解析及关键代码初探
解析URL,建立与对象的关系
TTNavigator *navigator = [TTNavigator navigator];
+ (TTNavigator*)navigator {
//获得TTBaseNavigator全局navigator
//globalNavigator作为TTBaseNavigator的单实例
TTBaseNavigator* navigator = [TTBaseNavigator globalNavigator];
//如果还不存在全局navigator,则新建一个TTNavigator对象实例并将其设置为全局navigator
if (nil == navigator) {
navigator = [[[TTNavigator alloc] init] autorelease];
// setNavigator: retains.
[super setGlobalNavigator:navigator];
}
...
return (TTNavigator*)navigator;
}TTNavigator作为TTBaseNavigator的子类,其中包括TTURLMap类的实例对象_URLMap,用于对URL与object的映射进行管理。
TTURLMap* map = navigator.URLMap; //获得navigator对应URLMap,该URLMap在TTBaseNavigator的init方法中初始化
[map from:@"tt://catalog" toSharedViewController:[AppUsingThree20ViewController class]];
- (void)from:(NSString*)URL toSharedViewController:(id)target {
TTURLNavigatorPattern* pattern = [[TTURLNavigatorPattern alloc] initWithTarget:target mode:TTNavigationModeShare];
[self addObjectPattern:pattern forURL:URL];
[pattern release];
}TTURLNavigatorPattern作为TTURLPattern的子类,保存了解析后的URL信息,包括scheme,path,query和fragment以及该URL所对应的对象。
- (void)addObjectPattern: (TTURLNavigatorPattern*)pattern
forURL: (NSString*)URL {
pattern.URL = URL;
//对模式进行编译,主要是对模式中的URL进行分析
[pattern compile];
[self registerScheme:pattern.scheme];
//判断pattern是否等于全局URL“*”
if (pattern.isUniversal) {
[_defaultObjectPattern release];
_defaultObjectPattern = [pattern retain];
} else if (pattern.isFragment) {
if (!_fragmentPatterns) {
_fragmentPatterns = [[NSMutableArray alloc] init];
}
[_fragmentPatterns addObject:pattern];
} else {
_invalidPatterns = YES;
if (!_objectPatterns) {
_objectPatterns = [[NSMutableArray alloc] init];
}
//TTURLMap中的_objectPatterns增加TTURLNavigatorPattern实例
[_objectPatterns addObject:pattern];
}
}生成URL对应对象并显示
[navigator openURLAction:[TTURLAction actionWithURLPath:@"tt://catalog"]];
//TTURLAction的实例变量_URLPath中保存了要打开的URL“tt://catalog”
- (UIViewController*)openURLAction:(TTURLAction*)action {
...
TTURLNavigatorPattern* pattern = nil;
//生成要显示的view controller,该例中为AppUsingThree20ViewController
UIViewController* controller = [self viewControllerForURL: urlPath query: action.query pattern: &pattern];
if (nil != controller) {
...
action.transition = action.transition ? action.transition : pattern.transition;
//如果该URL对应的对象不为空,则将该对象展示出来
BOOL wasNew = [self presentController: controller parentURLPath: action.parentURLPath withPattern: pattern action: action];
if (action.withDelay && !wasNew) {
[self cancelDelay];
}
} else if (_opensExternalURLs) {
...
}
return controller;
}//获得该URL对应要显示的ViewController
- (UIViewController*)viewControllerForURL: (NSString*)URL query: (NSDictionary*)query pattern: (TTURLNavigatorPattern**)pattern {
...
id object = [_URLMap objectForURL:URL query:query pattern:pattern];
if (object) {
UIViewController* controller = object;
controller.originalNavigatorURL = URL;
if (_delayCount) {
if (!_delayedControllers) {
_delayedControllers = [[NSMutableArray alloc] initWithObjects:controller,nil];
}
else {
[_delayedControllers addObject:controller];
}
}
return controller;
} else {
return nil;
}
}//取得该URL所对应的object
- (id)objectForURL: (NSString*)URL query: (NSDictionary*)query pattern: (TTURLNavigatorPattern**)outPattern {
id object = nil;
//"tt://catalog"URL只设置了_objectPattern
if (_objectMappings) {
object = [_objectMappings objectForKey:URL];
if (object && !outPattern) {
return object;
}
}
NSURL* theURL = [NSURL URLWithString:URL];
TTURLNavigatorPattern* pattern = [self matchObjectPattern:theURL];
if (pattern) {
if (!object) {
object = [pattern createObjectFromURL:theURL query:query];
}
if (pattern.navigationMode == TTNavigationModeShare && object) {
[self setObject:object forURL:URL];
}
if (outPattern) {
*outPattern = pattern;
}
return object;
} else {
return nil;
}
}//创建AppUsingThree20ViewController的实例
- (id)createObjectFromURL: (NSURL*)URL query: (NSDictionary*)query {
id returnValue = nil;
if (self.instantiatesClass) {
//suppress static analyzer warning for this part
// - invoke:withURL:query actually calls an - init method
// which returns either a new object with retain count of +1
// or returnValue (which already has +1 retain count)
#ifndef __clang_analyzer__
returnValue = [_targetClass alloc];
//如果有相应的初始化方法,在alloc后会调用相应的初始化方法,否则就调用init
if (_selector) {
returnValue = [self invoke:returnValue withURL:URL query:query];
} else {
returnValue = [returnValue init];
}
[returnValue autorelease];
#endif
} else {
...
}
return returnValue;
}//只有在打开对象时才会生成该对象的实例并加入到_objectMappings字典中
- (void)setObject:(id)object forURL:(NSString*)URL {
if (nil == _objectMappings) {
_objectMappings = TTCreateNonRetainingDictionary();
}
// XXXjoe Normalize the URL first
[_objectMappings setObject:object forKey:URL];
if ([object isKindOfClass:[UIViewController class]]) {
[UIViewController ttAddNavigatorController:object];
}
}//展示view controller,如果没有设置topViewController且当前展示的viewController不能包含其它的viewController,
//则将当前展示的viewController包含在NavigationController中进行展示
- (BOOL)presentController: (UIViewController*)controller parentURLPath: (NSString*)parentURLPath withPattern: (TTURLNavigatorPattern*)pattern action: (TTURLAction*)action {
BOOL didPresentNewController = NO;
if (nil != controller) {
UIViewController* topViewController = self.topViewController;
//此时还没有设置topViewController,所有topViewController为nil
if (controller != topViewController) {
UIViewController* parentController = [self parentForController: controller isContainer: [controller canContainControllers] parentURLPath: parentURLPath ? parentURLPath : pattern.parentURL];
if (nil != parentController && parentController != topViewController) {
[self presentController: parentController parentController: nil mode: TTNavigationModeNone action: [TTURLAction actionWithURLPath:nil]];
}
didPresentNewController = [self presentController: controller parentController: parentController mode: pattern.navigationMode action: action];
}
}
return didPresentNewController;
}- (UIViewController*)parentForController: (UIViewController*)controller isContainer: (BOOL)isContainer parentURLPath: (NSString*)parentURLPath {
if (controller == _rootViewController) {
return nil;
} else {
// If this is the first controller, and it is not a "container", forcibly put
// a navigation controller at the root of the controller hierarchy.
if (nil == _rootViewController && !isContainer) {
[self setRootViewController:[[[[self navigationControllerClass] alloc] init] autorelease]];
}
if (nil != parentURLPath) {
return [self openURLAction:[TTURLAction actionWithURLPath:parentURLPath]];
} else {
UIViewController* parent = self.topViewController;
if (parent != controller) {
return parent;
} else {
return nil;
}
}
}
}- (void)setRootViewController:(UIViewController*)controller {
if (controller != _rootViewController) {
[_rootViewController release];
_rootViewController = [controller retain];
if (nil != _rootContainer) {
[_rootContainer navigator:self setRootViewController:_rootViewController];
} else {
[self.window addSubview:_rootViewController.view];
}
}
}[navigator openURLAction:[TTURLAction actionWithURLPath:@"tt://catalog"]]调用中会对“tt://catalog”对应的AppUsingThree20ViewController对象调用其init方法进行初始化(- (id)createObjectFromURL: (NSURL*)URL query: (NSDictionary*)query方法),而在init内部又会调用- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil方法,在该方法中我们设置了该页面的title,navigationItem的返回按钮以及表格的格式。
AppUsingThree20ViewController在显示之前会调用- (void)viewWillAppear:(BOOL)animated方法,因为AppUsingThree20ViewController没有重写这个方法,则会调用从其基类继承来的这个方法。
TTModelViewController
|
|
TTTableViewController
|
|
AppUsingThree20ViewController
TTModelViewController中的- (void)viewWillAppear:(BOOL)animated方法,代码如下:
- (void)viewWillAppear:(BOOL)animated {
_isViewAppearing = YES;
_hasViewAppeared = YES;
[self updateView];
[super viewWillAppear:animated];
}- (void)updateView {
if (_flags.isViewInvalid && !_flags.isViewSuspended && !_flags.isUpdatingView) {
_flags.isUpdatingView = YES;
// Ensure the model is created
self.model;
// Ensure the view is created
self.view;
[self updateViewStates];
if (_frozenState && _flags.isShowingModel) {
[self restoreView:_frozenState];
TT_RELEASE_SAFELY(_frozenState);
}
_flags.isViewInvalid = NO;
_flags.isUpdatingView = NO;
[self reloadIfNeeded];
}
}//该方法中调用了createModel方法,createModel是该类中定义的虚方法且在AppUsingThree20ViewController类中重写,
//即会调用AppUsingThree20ViewController中的createModel方法
- (id<TTModel>)model {
if (!_model) {
if (![TTNavigator navigator].isDelayed) {
[self createModel];
}
if (!_model) {
[self createInterstitialModel];
}
}
return _model;
}//创建TTTableViewController展示所需的数据源
- (void)createModel {
self.dataSource = [TTSectionedDataSource dataSourceWithObjects:@"Photos", [TTTableTextItem itemWithText:@"Photo Browser" URL:@"tt://photoTest"], nil];
}
本文介绍如何使用Three20框架创建一个包含单一section的TTTableViewController页面,详细讲解了配置步骤与关键代码。
420

被折叠的 条评论
为什么被折叠?



