我有一个名为AllThingsViewController的视图控制器,它可以动态创建其他名为ThingViewController的视图控制器,并将其顶层视图添加到UIScrollView中。 (我正在编写专有代码,因此我更改了类的名称,但是代码的结构完全相同。)

这是其loadView方法包含的内容:

NSArray *things = [[ThingDataController shared] getThings];

if ([things count] == 0) {
    // code in this block is not relevant as it's not being executed...
} else {

    for(unsigned int i = 0; i < [things count]; ++i) {
        ThingViewController *thingViewController = [[ThingViewController alloc] init];
        [thingViewController loadView];

        [scrollView addSubview:thingViewController.topView];
        thingViewController.topView.frame = CGRectNewOrigin(thingViewController.topView.frame,
                0, thingViewController.topView.frame.size.height*i);

        [thingViewController displayThing:thing[i]];
    }
}

ThingViewController的loadView方法如下所示:
- (void)loadView
{
    NSArray *topLevelObjs = nil;
    topLevelObjs = [[NSBundle mainBundle] loadNibNamed:@"ThingView" owner:self options:nil];
    if (topLevelObjs == nil)
    {
        NSLog(@"Error: Could not load ThingView xib\n");
        return;
    }
}

当我的应用程序启动时,所有内容都会正确显示,直到我尝试点击ThingViewController加载的xib中存在的按钮之一为止,此时它由于以下异常而崩溃:“无法识别的选择器已发送至实例”。似乎ARC太早释放了ThingViewController实例。

查看我的代码,我发现这是因为它们没有被保留在任何东西上,所以我在AllThingsViewController类中创建了一个NSMutableArray作为实例变量,并因此开始向其中添加ThingViewControllers:
NSArray *things = [[ThingDataController shared] getThings];

if ([things count] == 0) {
    // not being executed...
} else {

    for(unsigned int i = 0; i < [things count]; ++i) {
        ThingViewController *thingViewController = [[ThingViewController alloc] init];
        [thingViewController loadView];

        [scrollView addSubview:thingViewController.topView];
        thingViewController.topView.frame = CGRectNewOrigin(thingViewController.topView.frame,
                0, thingViewController.topView.frame.size.height*i);

        [thingViewController displayThing:thing[i]];

        [allThingsViewControllers addObject:thingViewController];
    }
}

但是,即使将这些对象添加到数组中,它也没有任何改变。最后,只是为了确认这是ARC较早发布,我将“thingViewController”更改为AllThingsViewController中的实例变量,并进行了更改:
ThingViewController *thingViewController = [[ThingViewController alloc] init];

成为:
thingViewController = [[ThingViewController alloc] init];

果然,当我点击其按钮时,可滚动列表中的最后一个项目不会崩溃,而其他项目则不会崩溃,因为它的ThingViewController未被释放。

我对ARC还是比较陌生,但是经过一堆谷歌搜索后,我不知道如何解决此问题。我该怎么办?

最佳答案

几件事。

问题1:

这看起来像是您的错误的原因:

[allBillViewControllers addObject:billViewController];

它应该是:
[allBillViewControllers addObject:thingViewController];

对?

问题2

您没有正确地将视图控制器添加到视图层次结构中。应该是这样的:
[self addChildViewController:childViewController];
[childViewController.view setFrame:targetFrame];
[scrollView addSubview:childViewController.view];
[childViewController didMoveToParentViewController:self];

同样,在删除子视图控制器时:
[childViewController willMoveToParentViewController:nil];
[childViewController.view removeFromSuperview];
[childViewController removeFromParentViewController];

问题3

切勿在视图控制器上显式调用loadView。每当您访问视图控制器的view属性时,UIKit就会调用它。

问题4

您必须将子视图控制器的view添加到滚动视图,而不是其视图层次结构中的任意子视图topView。重构ThingViewController类,以使其自己更简单。 :-)

07-28 06:28