【发布时间】:2014-01-02 18:19:02
【问题描述】:
Ok StackOverflow 人...我有一个非常有趣的问题,我已经尝试解决了好几天但无法弄清楚,所以我需要一些重要的帮助。这很可能是一个非常冗长的描述,但请耐心等待,并提前深深感谢您阅读所有这些,因为我拥有的单词越多,我就越能清楚地向大家描述全貌。我将尽我所能做到尽可能简洁和连贯。请让我知道我的不足之处。
这是我的问题的背景:我正在为我的 iOS 应用程序使用 Storyboard,而对于我的应用程序中的特定导航选项卡,我必须为纵向和横向方向创建两个单独的场景。这样做的原因(而不是说,使用自动布局)是因为在这个选项卡中,有一些视觉元素(表格视图、Web 视图等),它们的布局根据方向而不同,而且更容易创建一个单独的方向场景来处理 UI 中的这种变化,而不是以编程方式进行 - (它也更容易理解和更清晰的代码)。因此,从所有这些中要记住的一点是,这两个独立的纵向和横向场景代表了我的应用程序中的 SAME TAB。 (旁注:这些场景当然是在 IB 中制作的)
现在是我之前在 UI 中提到的视觉元素——再深入一点,它们都是不同 UIViewControllers 的容器。我对应用程序中的所有内容进行了沙盒处理,并且几乎所有内容都具有一对一的关系,因此这些容器将映射到我为它们的特定目的创建的子类 UIViewControllers - 但这是第一个警告我的问题出现了。这是一个更清晰图片的实际示例,我有一个UIViewController,其中包含一个名为MXSAnnouncementsViewController 的UITableView,并且在横向和纵向场景中都存在相同的视图控制器。我没有创建该视图控制器的显式纵向或横向版本,而是让控制器跟踪两个指向特定方向的IBOutlet 属性(tableViewLandscape 和tableViewPortrait)@ 987654329@ - 和这种方法非常有效。此外,在我的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,而另一个已经初始化和分配,这就是为什么我使用上面sn-p 中的tableView 属性所做的事情。这就是警告 #2 出现的地方,它是一个笨拙的 - 它与视图生命周期有关。为了清楚起见,这是一个实际示例:假设我以横向加载应用程序。当我这样做时,我的tableViewLandscape 插座在内存中有一个地址,我的tableViewPortrait 插座是nil。这是预期和期望的行为。现在,当我旋转应用程序时,疯狂的事情就开始了。这里有一个地方我需要你们所有人澄清UIViewControllers 的实例以及正常与不正常的情况,请非常缓慢而仔细地阅读以下内容。
旋转应用程序会立即导致相反方向的场景(MXSAnnouncementsViewController???的另一个实例)调用其 viewDidLoad 方法(在此示例中,我们处于横向,因此纵向场景调用该方法)。在该方法中,我的本地 tableView 属性被设置为该方向的当前活动表视图(参见上面的 sn-p)。当该方法完成时,MXSAnnouncementsViewController 的前一个 LANDSCAPE 实例调用其viewWillDisappear 方法,然后是 PORTRAIT 实例调用其viewWillAppear 方法,最后以 LANDSCAPE 实例调用其willRotateToInterfaceOrientation 回调结束——这就是我从断点看到的操作顺序。我真的希望你能得到这一切,因为我的思绪被这一切炸飞了。
如果此时你还在我身边,谢谢你,因为我们终于到了最后阶段。正如这篇文章的标题所暗示的,我要解决的问题是我的应用程序在轮换时冻结。如果你没有注意到viewDidLoad sn-p,最后一条要执行的指令是setupPullToRefresh 方法,如下所示:
- (void)setupPullToRefresh
{
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(refreshTableView:) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:refreshControl];
}
由于我之前已经解释了轮换操作的整个视图生命周期顺序,长话短说,如果我在 viewDidLoad 末尾为 MXSAnnouncementsViewController 注释掉最后一条 setupPullToRefresh 指令,我的应用程序工作正常。如果我包含该指令,我的应用程序在第一次旋转时完全没有响应,我终生无法弄清楚原因。不确定我是否在这里处理边缘情况或其他情况。欢迎任何和所有见解,非常感谢您阅读所有这些!
【问题讨论】:
-
应用挂起时在做什么,主线程?
-
我还不是 iOS 开发和调试领域的专业人士,但我只是尝试使用 Instruments,它看起来不像主线程在做任何事情。我确实看到了 但我不确定这意味着什么。我当然可以通过一点方向更深入地挖掘,但是,我就像地面上的一块石头一样有用。
-
有时使用 || 暂停应用时会有线索并查看主线程的堆栈。 Unpauzing-pauzing-again 几次当然可能会给出不同的堆栈结果。
标签: ios uiviewcontroller uirefreshcontrol