【问题标题】:iPhone SDK: what is the difference between loadView and viewDidLoad?iPhone SDK:loadView 和 viewDidLoad 有什么区别?
【发布时间】:2010-10-09 02:33:14
【问题描述】:

在 iPhone 应用程序中使用视图和视图控制器时,谁能解释 loadView 和 viewDidLoad 之间的区别?

我个人的情况是,我从代码中构建所有视图,我不会也不会使用 Interface Builder,如果这有什么不同的话。

我发现,当我将初始化代码添加到 loadView 时,我经常会得到一个无限的堆栈跟踪,所以我通常在 viewDidLoad 中构建我所有的子视图......但我真的不清楚每个得到执行,以及放置 init 代码的更合适的位置是什么。最完美的是初始化调用的简单图表。

谢谢!

【问题讨论】:

    标签: ios objective-c iphone uiview


    【解决方案1】:

    我可以猜到这里可能是什么问题,因为我已经做到了:

    我发现当我向 loadView 添加初始化代码时,我经常会得到一个无限的堆栈跟踪

    不要在-loadView中读取self.view。设置它,不要get它。

    如果当前未加载视图,则 self.view 属性访问器调用 -loadView。这就是你的无限递归。

    在 -loadView 中以编程方式构建视图的常用方法,如 Apple 的 pre-Interface-Builder 示例所示,更像是这样:

    UIView *view = [[UIView alloc] init...];
    ...
    [view addSubview:whatever];
    [view addSubview:whatever2];
    ...
    self.view = view;
    [view release];
    

    我不怪你没有使用 IB。我在所有 Instapaper 中都坚持使用这种方法,发现自己比处理 IB 的复杂性、界面怪癖和意想不到的幕后行为更舒服。

    【讨论】:

    • 啊啊啊,终于谢谢你的解释了!我已经避开了分配一个临时变量,然后设置为 self.view,然后释放的习惯用法……这似乎有点尴尬,没有必要。我现在可以理解为什么这个决定会让我走上我现在找到自己的道路。
    • 我有这样的代码,没有递归。为什么? -(void) loadView { // Frame for Hypnosis view CGRect frame = [[UIScreen mainScreen] bounds]; // Create a Hipnosis view v = [[HypnosisView alloc] initWithFrame:frame]; self.view = v;
    【解决方案2】:

    loadViewUIViewController 中的方法,它将实际加载视图并将其分配给view 属性。如果您想以编程方式设置 view 属性,这也是 UIViewController 的子类将覆盖的位置。

    viewDidLoad 是加载视图后调用的方法。这是在调用 loadView 之后调用的。在这里,您可以覆盖和插入代码,以便在视图加载后对视图进行进一步的初始设置。

    【讨论】:

      【解决方案3】:
      viewDidLoad()
      

      在您从 NIB 加载视图并希望在启动后执行任何自定义时使用

      LoadView()
      

      当您想以编程方式创建视图时使用(不使用 Interface Builder)

      【讨论】:

      • 这可能有问题,我测试了当我的视图控制器没有与NIB文件关联时,仍然调用viewDidLoad
      【解决方案4】:

      只是添加一些代码示例来演示 NilObject 所说的:

      - (void)loadView
      {
          // create and configure the table view
          myTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStyleGrouped];   
          myTableView.delegate = self;
          myTableView.dataSource = self;
          myTableView.scrollEnabled = NO;
          self.view = myTableView;
      
          self.view.autoresizesSubviews = YES;
      }
      
      - (void)viewDidLoad 
      {
        self.title = @"Create group";
      
        // Right menu bar button is to Save
        UIBarButtonItem *saveButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStyleDone target:self action:@selector(save)];
        self.navigationItem.rightBarButtonItem = saveButtonItem;
        [saveButtonItem release];
      }
      

      【讨论】:

      • 所以,在你们两个之间,是否可以准确地说 loadView 是我应该在我的控制器的 self.view 中执行 alloc/init 的地方,而子视图应该在 viewDidLoad 中处理(或更高版本) )?
      【解决方案5】:

      为防止在读取 self.view 时发生无限循环,请在加载视图时调用该类的超级实现。超级实现会为你分配一个新的 UIView。

      - (void) loadView {
      [super loadview];
      
      // init code here...
      
      [self.view addSubView:mySubview1]; //etc..
      
      }
      

      【讨论】:

      • 我可以发誓 Apple 的文档说你不应该打电话给 [super loadView];。这在示例中是矛盾的,但我认为文档说得对(随着时间的推移,我在示例中发现了许多错误)。不过,UITableViewController 等需要[super loadView]。然而!任何加载后设置(例如添加额外的子视图)都应在 viewDidLoad 中完成。
      • 我已经调用了[super loadView],到目前为止没有任何副作用。如果你打算将 self.view 设置为你自己制作的东西,这可能是真的。
      • 如果您在 loadView 中调用 [super loadView],那么它将尝试从 nib 加载视图(如果可用的默认名称)。所以你需要小心。
      • 如果你调用[super loadView],你在super loadView方法中初始化self.view
      【解决方案6】:

      使用 loadView 最简单的方法是制作某种类型的基本视图控制器,例如 MyBaseViewController,它是 UIViewController 的子类。在它的 loadView 方法中以这种方式创建视图:

      -(void) loadView {
          if ([self viewFromNib]) {
              self.view = [self viewFromNib];
          } else {
              self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
          }
          self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
          self.view.backgroundColor = [UIColor whiteColor];
      }
      

      当你需要制作一些视图控制器时,你只需使用 MyBaseViewController 的子类,在它的 loadView 控制器中,你只需像这样调用 [super loadView]

      //sucblass loadView
      -(void) loadView {
          [super loadView];
      
          //rest of code like this..
          UILabel *myLabel = [[UILabel alloc] initWithFrame:myFrame];
          [self.view addSubview:myLabel];
          [myLabel release];
      }
      

      【讨论】:

        【解决方案7】:

        loadView() 在您的控制器被要求创建其self.view 时被调用。你可以自己做,就像

        self.view = [UIView alloc] init...];
        

        或者你的控制器的父 UIController 类已经有一个方法名-loadView(),它将你的 self.view 初始化为空白视图。然后就可以调用了

        [super loadView];
        

        我真的推荐第二种方法,因为它鼓励继承。仅当您的视图控制器不是直接从 UIViewController 继承时。

        【讨论】:

          【解决方案8】:

          Apple 在 vi​​ewDidLoad 上给出的定义中提到,它是在控制器的视图加载到内存后调用的。简单来说,就是第一个加载的方法。

          您可能在想,这种方法在什么条件下才能得到充分利用?答案是,基本上你希望应用程序首先加载的任何内容。例如,您可能想要不同的背景颜色,而不是白色,您可以选择蓝色。

          【讨论】:

            猜你喜欢
            • 2011-03-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-12-29
            相关资源
            最近更新 更多