在手动构建视图时,如何处理UIViewController中的视图初始化顺序?

rcw*_*cw3 4 iphone cocoa-touch objective-c uiviewcontroller ios

我有一个UIViewController,它在loadView中实现了它的视图(即没有nib).根据文档(并通过代码中的确认),loadView以及因此,在第一次访问UIViewController的视图之前,不会调用viewDidLoad.

我有另一个类实例化UIViewController并在引用视图本身之前调用它上面的许多方法.其中许多方法都修改了UIViewController中的视图/子视图.不幸的是,此时未对视图/子视图进行实例化.(我可以很容易地在其他方法调用之前添加对视图的引用,但这需要努力并理解我的UIViewController用户的不可见契约).

如何处理修改视图/子视图的UIViewController上的方法?在我的每个UIViewController方法中,我可以检查视图是否已加载,但您不应该直接调用loadView.我可以把"自我观点"; 在方法中可能确保视图被加载,但这看起来非常h​​ackish(当然导致clang警告).

此外,这不仅仅是一次性的事情,因为显然可以在内存事件期间卸载视图,从而允许这种状态经常发生.

我觉得我错过了一些相当简单的东西,但我找不到它.处理此状态/初始化问题的适当方法是什么?

Jas*_*oco 5

基本上,这种事情的答案是不通过视图控制器公开视图的组件,因为其他对象可能不应该访问它们.因此,如果您的视图控制器管理一个呈现某人姓名的视图,例如,而不是执行以下操作:

PersonNameController* pnc = [[PersonNameController alloc] initWithNibName:nil bundle:nil];
[[pnc nameLabel] setText:@"Jason"];
[[self navigationController] pushViewController:pnc animated:YES];
Run Code Online (Sandbox Code Playgroud)

您可以将数据/模型位与视图位分开,并在视图控制器上显示"名称"属性.然后你就可以拥有这个总是正常工作的简单示例代码(它需要更多的代码,但它可以让你免于这样的烦恼,而且说实话,就是MVC的意思):

PersonNameController* pnc = [[PersonNameController alloc] initWithNibName:nil bundle:nil];
[pnc setName:@"Jason"];
[[self navigationController] pushViewController:pnc animated:YES];
Run Code Online (Sandbox Code Playgroud)

并执行这样的控制器:

@interface PersonNameController : UIViewController {
 @private
  NSString* name_;
}

// other people use this to pass model data to the controller
@property(nonatomic,copy) NSString* name;   

@end

@interface PersonNameController()

// for us only
@property(nonatomic,assign) UILabel* nameLabel;

@end

@implementation PersonNameController

// properties
@synthesize nameLabel;
@synthesize name = name_;

- (void)setName:(NSString*)value
{
  if( [value isEqualToString:name_] ) return;
  [name_ autorelease];
  name_ = [value copy];
  [[self nameLabel] setText:name_?:@""];
}

// view lifecycle
- (void)loadView
{
  // ob fake frame for now
  UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
  UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake( 10, 10, 300, 37)];
  [view addSubview:label];
  [self setView:view];
  [self setNameLabel:label];

  // Set the name on the label if one's set already
  [label setText:name_?:@""];

  // clean up
  [view release];
  [label release];
}

// take care of unloads
- (void)viewDidUnload
{
  // no need to release, but set nil so it's not used while the view
  // is unloaded
  nameLabel = nil;
  [super viewDidUnload];
}

- (void)dealloc
{
  // nameLabel is assign (owned by our view) so we don't release here
  // but set to nil just to be good citizens
  nameLabel = nil;
  [name_ release];
  [super dealloc];
}

@end
Run Code Online (Sandbox Code Playgroud)

快速注意:这只是在这个小盒子里输入的,我真的很累,所以没有检查语法的正确性等等.这是一个快速的例子,不是剪切和粘贴的东西.

此外,如果每次都需要更新许多属性,您可以创建一个单独的实用程序方法,如-udpateLabels或更新所有这些方法.然后从每个setter和viewDidLoad或loadView调用它.这样你就可以在一个地方拥有一切(以牺牲一些表现为代价).如果在分析后,您在该方法上花费了太多时间,则可以根据需要将其分解.