iphone - 手动构建 View 时如何处理 UIViewController 中的 View 初始化顺序?

标签 iphone objective-c cocoa-touch ios uiviewcontroller

我有一个 UIViewController,它在 loadView 中具体化了它的 View (即没有 nib)。根据文档(并通过代码确认),loadView 和 viewDidLoad 在第一次访问 UIViewController 的 View 之前不会被调用。

我有另一个类实例化 UIViewController 并在引用 View 本身之前调用它的许多方法。其中许多方法修改 UIViewController 中的 View / subview 。不幸的是,此时 View / subview 没有被实例化。 (我可以轻松地在其他方法调用之前添加对 View 的引用,但这需要付出努力并理解我的 UIViewController 用户的不可见契约)。

如何处理 UIViewController 上修改 View / subview 的方法?在我的每个 UIViewController 方法中,我可以检查 View 是否已加载,但您不应该直接调用 loadView。我可以放一个“self.view;”在大概确保 View 已加载的方法中,但这看起来很老套(当然会导致 clang 警告)。

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

我觉得我遗漏了一些相当简单的东西,但我一直没能找到它。处理此状态/初始化问题的适当方法是什么?

最佳答案

基本上,解决此类问题的方法是不要通过 View Controller 公开 View 的组件,因为其他对象可能不应该访问它们。所以,如果你的 View Controller 管理一个呈现人名的 View ,例如,而不是做这样的事情:

PersonNameController* pnc = [[PersonNameController alloc] initWithNibName:nil bundle:nil];
[[pnc nameLabel] setText:@"Jason"];
[[self navigationController] pushViewController:pnc animated:YES];

您可以将数据/模型位与 View 位分开,并在您的 View Controller 上公开一个“名称”属性。然后你就可以得到这个简单的示例代码,它总是能正常工作(它需要更多的代码,但它可以让你免于像这样令人头疼的事情,老实说,这就是 MVC 的意义所在):

PersonNameController* pnc = [[PersonNameController alloc] initWithNibName:nil bundle:nil];
[pnc setName:@"Jason"];
[[self navigationController] pushViewController:pnc animated:YES];

以及这样一个 Controller 的实现:

@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

快速说明:这只是在这个小盒子里打出来的,我真的很累,所以它没有检查总的语法正确性等。这只是一个简单的例子,不是要删减的东西粘贴。

此外,如果您有许多属性需要每次都更新,您可以创建一个单一的实用方法,如 -udpateLabels 或更新所有属性的方法。然后从每个 setter 和 viewDidLoad 或 loadView 调用它。这样你就可以把所有东西都放在一个地方(以牺牲一些性能为代价)。如果在分析之后,您在该方法上花费了太多时间,您可以适本地将其分解。

关于iphone - 手动构建 View 时如何处理 UIViewController 中的 View 初始化顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4743784/

相关文章:

iphone - 将 UTF8 十六进制字符串转换为常规 UTF8 编码的 NSString

c++ - 将相对路径转换为完整路径的系统函数,即使对于非现有路径也能正常工作?

ios - 转换为使用 iOS 8 Popover Segues 时 UISplitViewController 崩溃

ios - 打开手机应用程序而不调用电话

iphone - 在iPad中实现像xcode的 "build success"这样的通知 View

ios - 自构建预编译头以来文件已被修改

iphone - iOS 5 中 UINavigationBar 中的截止标题标签

iphone - iOS:有条件地加载 View Controller

iphone - NSMutableArray 和 removeobjectsatindex

ios - 防止 View 被拖出屏幕