UIRefreshControl内部的UITableView导致应用程序在旋转时冻结 - iOS 6+

时间:2014-01-02 18:19:03

标签: ios uiviewcontroller uirefreshcontrol

好的StackOverflow人......我有一个非常有趣的问题,我一直试图解决好几天而无法弄清楚所以我需要一些重要的帮助。这很可能是一个非常冗长的描述,但请耐心等待我,并提前感谢您阅读所有这些,因为我拥有的词越多,我就能更清楚地向您描述全貌。我会竭尽全力尽可能地保持简洁和连贯。无论我在哪里,请告诉我。


以下是我的问题的背景:我正在为我的iOS应用程序使用Storyboard,并且在我的应用程序中使用特定的导航选项卡,我必须为纵向和横向方向创建两个单独的场景。这样做的原因(而不是说,使用Autolayout),是因为在这个标签中,有视觉元素(表格视图,网页视图等)根据方向不同的布局,它更容易创建一个单独的方向场景来处理UI中的这种变化而不是以编程方式进行 - (它也更容易理解和更清晰的代码)。因此,要记住所有这些,请注意这两个独立的纵向和横向场景代表我的应用程序中的相同选项卡。 (旁注:这些场景当然是在IB中制作的)

现在我在UI中提到的视觉元素 - 更深入,它们都是不同UIViewControllers的容器。我在应用程序中沙盒化了所有内容,并且几乎与所有内容都有一对一的关系,因此这些容器将映射到我为其特定目的创建的子类UIViewControllers - 但它是第一个我的问题的警告出现了。这是一个更清晰图片的实际示例,我有一个UIViewController包含一个UITableView,名为MXSAnnouncementsViewController,这个相同的视图控制器同时存在于Landscape和Portrait场景中。我没有创建该视图控制器的显式纵向或横向VERSION,而是让控制器跟踪指向特定方向的两个IBOutlet属性(tableViewLandscapetableViewPortraitUITableViews - 这种方法非常合适。此外,在我的MXSAnnouncementsViewController中,我有一个名为tableView的本地属性,它抽象了特定于方向的表视图。它设置在viewDidLoad范围内,您可以在下面看到:

- (void)viewDidLoad
{
    [super viewDidLoad];

    if (self.tableViewPortrait) {
        self.tableView = self.tableViewPortrait;
    } else {
        self.tableView = self.tableViewLandscape;
    }

    [self.tableView setDelegate:self];
    [self.tableView setDataSource:self];

    if (![MXSAnnouncementManager sharedAnnouncementManager].latestAnnouncements) {
        [MXSAnnouncementManager loadModel:@"MXSAnnouncementGroupAllAnnouncements" withBlock:^(id model, NSError *error) {
            if (!error) {
                self.arrayLatestAnnouncements = [MXSAnnouncementManager sharedAnnouncementManager].latestAnnouncements;
                [self.tableView reloadData];
            } else {
                // show some error msg
            }
        }];
    } else {
        self.arrayLatestAnnouncements = [MXSAnnouncementManager sharedAnnouncementManager].latestAnnouncements;
    }

    [self setupPullToRefresh];
}

每当我进入标签页时,两个方向特定的IBOutlets中的一个始终处于活动状态,并且在内存中有一个地址,而另一个是nil。每当我旋转时,角色都会反向 - 先前在内存中有地址的任何内容现在都是nil而另一个已经被初始化和分配了,这就是我在片段中对tableView属性所做的事情的原因以上。这里有一个警告#2进入图片并且它是一个doozy - 它与视图生命周期有关。为清晰起见,这是一个实际的例子:假设我以横向方向加载应用程序。当我这样做时,我的tableViewLandscape商店内存中有一个地址,我tableViewPortrait商店的地址为nil。这是预期和期望的行为。现在,当我旋转应用程序时,疯狂的东西开始了。这里有一个地方,我需要清楚你们所有人关于UIViewControllers的实例以及什么是正常而不是什么不是这样非常慢慢地仔细阅读。

立即旋转应用会导致相反的方向场景(另一个MXSAnnouncementsViewController的实例???)调用其viewDidLoad方法(在此示例中,我们处于Landscape中,因此Portrait场景调用了方法)。在该方法中,我的本地tableView属性设置为该方向的当前活动表视图(请参阅上面的代码段)。当该方法完成时,先前的MXSAnnouncementsViewController LANDSCAPE实例调用其viewWillDisappear方法,然后是PORTRAIT实例调用其viewWillAppear方法,该方法最后以LANDSCAPE实例调用其结束willRotateToInterfaceOrientation回调 - 这是我从断点看到的操作顺序。我真的希望你能得到所有这一切,因为我的思绪只是从这一切中迸发出来。

如果你现在还和我在一起,谢谢你,因为我们终于在家了。正如这篇文章的标题所暗示的那样,我试图解决的问题是我的应用程序冻结轮换。如果您没有注意到viewDidLoad代码段,则执行的最后一条指令是setupPullToRefresh方法,该方法如下:

- (void)setupPullToRefresh
{
    UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
    [refreshControl addTarget:self action:@selector(refreshTableView:) forControlEvents:UIControlEventValueChanged];
    [self.tableView addSubview:refreshControl];
}

由于我已经在早期解释了旋转操作的整个视图生命周期顺序,所以如果我在setupPullToRefresh末尾为{viewDidLoad注释掉最后MXSAnnouncementsViewController条指1}},我的应用程序运行正常。如果我包含该指令,我的应用程序在第一次轮换时变得完全没有响应,我不能为我的生活找出原因。我不确定我是在处理边缘情况还是其他问题。欢迎任何和所有的见解,非常感谢您阅读所有这些!

2 个答案:

答案 0 :(得分:1)

您最好的方法可能是放弃目前设计的两个独立的纵向和横向控制器。在iOS上,您应该始终重新布置您想要的方向的视图,而不是销毁和重新创建所有内容。通过重新创建所有内容来尝试处理它,我认为你只会让自己陷入困境。

如果你知道的话,你可以使用自动布局在旋转时对视图进行复杂的重新排序,但最好的办法是废弃当前的代码以进行横向渲染,并编写代码以便在旋转时自行重新排列视图。您将面临更少的问题,并且您的代码也将更容易让其他人理解和维护。

当你删除那一段代码时,你的应用程序可能看起来工作得很好,但是幕后可能会发生一些不太正确的事情,可能会在将来再次引发你的想法。这可能就是为什么添加代码行会打破它。

答案 1 :(得分:0)

  • 尝试在轮换后添加

    -(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
        [self setupPullToRefresh];
    }
    
  • 如果这没有帮助,只需创建一次UIRefreshControl并在旋转时将其设置为右表。

  • 如果这也没有帮助,请按照第一个给出的答案(@ Gavin的答案),在viewDidLoad上只创建一个表,并在-(void)viewWillLayoutSubviews

  • 中重新发布内容