iphone——Three20库代码初探

本文介绍如何使用Three20框架创建一个包含单一section的TTTableViewController页面,详细讲解了配置步骤与关键代码。

本文使用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];
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值