【问题标题】:viewWillAppear is not firedviewWillAppear 没有被触发
【发布时间】:2012-06-03 20:03:37
【问题描述】:

我已经设置了一个基本的测试应用程序,它显示一个包含标签的视图,没有使用 IB。我想使用自定义 UIView 子类和自定义 UIViewController 子类。

这将按预期运行,但 MyViewController 的 viewWillAppear 和其他类似的委托不会触发。

我缺少什么来制造这些火?在以前的项目中(使用 IB),这些都可以触发。

完整代码如下:

AppDelegate - 加载一个“MainVC”视图控制器并将其设置为根控制器

#import "AppDelegate.h"
#import "MainVC.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize mainVC = _mainVC;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.mainVC = [[MainVC alloc] init];
    self.window.rootViewController = self.mainVC;
    [self.window makeKeyAndVisible];
    return YES;
}

MainVC - 创建一个分配“MyView”的“MyViewController”(它还向下传递应该用于视图的帧大小)

#import "MainVC.h"
#import "MyViewController.h"

@implementation MainVC

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        MyViewController *controller = [[MyViewController alloc] init];
        CGRect frame;
        frame.origin.x = 5;
        frame.origin.y = 5;
        frame.size.width = self.view.frame.size.width - (2 * 5);
        frame.size.height = self.view.frame.size.height - (2 * 5);
        controller.startingFrame = frame;
        [self.view addSubview:controller.view];
    }
    return self;
}

MyViewController - 创建 MyView

#import "MyViewController.h"
#import "MyView.h"

@implementation MyViewController

@synthesize startingFrame;

- (void)loadView{
    self.view = [[MyView alloc] initWithFrame:startingFrame];
}

- (void)viewWillAppear:(BOOL)animated{
    NSLog(@"appearing"); //doesn't do anything
}

- (void)viewDidAppear:(BOOL)animated{
    NSLog(@"appeared"); //doesn't do anything
}

我的视图

#import "MyView.h"

@implementation MyView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor whiteColor];
        label = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 150, 40)];
        [label setText:@"Label"];
        [self addSubview:label];
    }
    return self;
}

【问题讨论】:

标签: ios cocoa-touch ios5 uiview uiviewcontroller


【解决方案1】:

您的错误:您正在设置一个根视图控制器,然后在其上添加另一个视图控制器视图。当第二个视图被添加到视图层次结构中时,它的视图控制器以这种方式保持“未连线”。事实上,如果你检查 MainViewController 的 parentViewController,你会发现它是 nil

原因: viewWillAppear 方法将仅发送到根视图控制器或根视图控制器层次结构中的视图控制器(使用presentModalViewController:animated:presentViewController:animated:completion: 呈现的视图控制器) .

解决方案:要解决它,您有几个选择:

  1. 使用您的视图控制器作为根视图控制器
  2. 通过上述方法之一展示您的视图控制器
  3. 保持您的代码不变,并手动将这些事件连接到子视图控制器(不过请注意这种方法,因为我相信您提到的事件会在 iOS 5 下自动转发 - 您可以轻松地检查一下)。
  4. 如果我没记错的话,将这些事件转发到您的视图控制器的另一种方法是将您的视图控制器的视图添加到窗口,而不是添加到父视图。

【讨论】:

  • 谢谢 - 所以我的视图被添加了,但控制器本质上是漂浮在未连接的地方?我的目标是使用 MainVC 加载分页滚动视图,然后添加多个 MyView 实例 - 基本上是相同的 UI 导航天气应用程序。所以这排除了我认为的选项1和2? 3和4我需要玩一个小时。也许我已经结束了,是否有一些更简单的方法来设置分页滚动视图(具有可重复的内容)?
  • 根据您的问题:是的,可以这么说,它有点飘忽不定。至于你能做什么:我建议你尝试使用一个视图控制器来配置和设置多个视图,并充当滚动视图的委托。它将负责查询您的模型以了解要显示的内容,并设置不同的视图以显示正确的数据。需要将操作传回视图控制器的每个视图都可以使用块、委托或回调来执行此操作。
  • 为了扩展这一点,我组织 iOS 应用程序的首选方法是让我的自定义视图提供一个 setupWithSomeDataObject: 方法,该方法接收设置其外观所需的内容。我还使用blocks,这是(恕我直言)每当我的自定义视图需要让视图控制器知道触发了某些重要事件时执行操作的一种非常优雅的方式。
  • 让我感到困惑的一件事 - 对于我构建的其他应用程序,我的常见做法是 1:1 视图:控制器比例。如果我推送一种新型视图,它有自己的控制器。区别仅仅是因为我没有转换到新视图,而是添加了新视图。如果是这样,我想我正在做的相当于为视图上的每个标签制作一个 LabelController,为每个 UITextField 制作一个 FieldController,等等。这显然是疯狂的。
  • 在 iOS 中,视图控制器与“屏幕”视图的控制器有关。拥有更多的视图控制器并没有错,但我建议您尽可能避免 1:1 的配给 - 这会让您的生活更轻松。
【解决方案2】:

有许多非常基本的事情出错了:

  • 您正在为您的 MainViewController 在initWithNibNamed: 中进行整个设置,但您正在创建它只是调用init。所以你的设置永远不会发生
  • 您正在实施第二个 VC (MyViewController),显然只是为了创建 myView,然后将其添加到您的 rootVC 层次结构中。不好!只有一个 VC(在您的情况下为 MainViewController)应负责创建和管理其层次结构中的视图
  • 不要像在 MyViewController 中那样在 loadView 中设置 VC 控制器。在您的情况下,这是使事情正常进行的唯一方法,因为 MyVC 从未真正完全启动并运行,但方法是错误的 - 您基本上是在强制 View Controller 设置视图,尽管控制器本身从未在控制一切

还有一些其他内容,但这些是最重要的内容 - 再次阅读 Model - View - Controller concept 的整个基本概念似乎对您来说是个好主意。接下来,您应该深入研究UIViewControllerUIView 的类引用。

即使您最终会使用当前的方法获得您想要的结果,但从长远来看它对您没有帮助,因为您不会学会正确使用所涉及的元素。

【讨论】:

  • 我的目标是从模型逻辑中分离出视图逻辑。我可以轻松使用单个视图控制器,并将所有视图设置添加到 loadView,但我的感觉是这不是非常 MVC - 至少不依赖数据对象的视图设置在 UIView 子类中会更好?然后我将只向控制器公开依赖数据对象的部分。也许我已经走远了。然后对我来说第二个棘手的部分是可重用性。这就是我尝试使用 2 个视图/控制器的原因。我将重新阅读苹果 MVC 文档。
  • 模型部分通常根本不包含任何逻辑——模型类在大多数情况下或多或少地充当数据容器。然而它仍然是一个类,一个事实,尤其是与一个充满逻辑的视图控制器相比,可能会令人困惑。关于可重用性,根据经验:尝试将逻辑封装到一定程度,您可以将 UIView 子类(例如)从项目中取出并在另一个项目中使用,而无需进行任何更改。如果不是绝对必要,不要跨类传播逻辑。最重要的是:别担心,这可能很棘手,但你会掌握的!
【解决方案3】:

方法不会在另一个视图控制器内的视图控制器上调用。如果仅针对 iOS 5 进行开发,请查看可用于解决此问题的 UIViewController Containment。如果您希望您的应用程序与以前的 iOS 版本兼容,您可以将方法调用转发到您的子视图控制器。我个人更喜欢继承 SFContainerViewController 来自动处理这个问题:https://github.com/krzysztofzablocki/SFContainerViewController

【讨论】:

    猜你喜欢
    • 2011-04-03
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 2017-11-22
    • 2019-11-07
    • 2018-09-01
    • 2018-12-03
    相关资源
    最近更新 更多