【问题标题】:Threads and autoreleasepool questions线程和自动释放池问题
【发布时间】:2011-11-19 03:45:25
【问题描述】:

据我了解,有几种方法可以发送要在线程中执行的任务。我最常用的是:

1) performSelector:withObject:afterDelay:

2) performSelectorOnMainThread:withObject:waitUntilDone:

3) performSelectorInBackground:withObject:

4) [NSThread detachNewThreadSelector:toTarget:withObject:]

我的第一个问题是,除了明显的参数差异之外,1) 和 2) 之间有什么区别?它们实际上是否都在主线程中工作(其自动释放池是在 main.m 中自动创建的)?我刚刚从某人在 Stackoverflow 上的帖子中读到方法 1) 实际上是在一个新线程中工作,因此应该为其选择器方法创建一个自动释放池。它是否正确?我一直在使用 1) 很多,主要是为了利用延迟参数,但我从未为它们创建自动释放池。没有发生任何灾难性的事情。

接下来,3) 和 4) 都在单独的线程中执行任务。我听说 UI 的东西不应该在这些线程中完成,但我对什么是严格的 UI 感到困惑。 我正在尝试编写代码以在表格视图从导航控制器模态启动时基本上播放重复加载动画。然后动画在 tableview 控制器的 viewDidLoad 方法中停止。最初,我只是将启动动画的代码粘贴在启动模态视图的代码行之上。发生的事情是动画从未播放过。

[[self loadingView] playAnimation];

SettingsViewController *menus = [[SettingsViewController alloc] initWithNibName:@"SettingsViewController" bundle:nil];

MyNavigationController *navController = [[MyNavigationController alloc] initWithRootViewController:menus];

[menus setParent:navController];
[navController setDelegate:self];
menus.mainViewController = self;

[self presentModalViewController:navController animated:YES];
[navController release];
[menus release];

然后我尝试了以下方法,并且成功了...

[NSThread detachNewThreadSelector:@selector(settingsOpeningThread) toTarget:self withObject:nil];
[[self loadingView] playAnimation];



- (void) settingsOpeningThread {

NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];

SettingsViewController *menus = [[SettingsViewController alloc]   initWithNibName:@"SettingsViewController" bundle:nil];

MyNavigationController *navController = [[MyNavigationController alloc] initWithRootViewController:menus];

[menus setParent:navController];
[navController setDelegate:self];
menus.mainViewController = self;

[self presentModalViewController:navController animated:YES];
[navController release];
[menus release];

[apool release];

}

动画会一直播放,直到 SettingsViewController 视图完全启动。但是启动像这样的模态视图是否算作“UI”并且应该避免?此外,每次启动模态视图时,我都会在 Instruments 中遇到一些奇怪的内存泄漏错误。但它来自那些“系统库”之一,我被告知很难调试。这里可能出了什么问题?

很抱歉这篇令人尴尬的长帖子。任何帮助将不胜感激!

【问题讨论】:

    标签: iphone objective-c nsthread nsautoreleasepool performselector


    【解决方案1】:

    (1) 为当前运行循环 安排一个任务。在非常高的层次上,一个 UIKit 应用程序看起来像

    while(true) {
      update UI
      run all tasks that were scheduled last time through the loop
    }
    

    这就是您在第一次尝试时没有看到您的 UI 更新的原因;对playAnimation 的调用将UI 安排在runloop 的下一次迭代中更新,但它永远不会到达那里,直到它后面的代码完成。

    注意performSelector:withObject:afterDelay 确实在单独的线程中运行指定的代码。

    (2) 做了一些非常相似的事情,但它不是为当前的 runloop 安排一些东西,而是为主线程上的 runloop 安排一些东西。这仅在从单独的线程调用时才有用,通常是因为您想从辅助线程更新 UI。

    是的,您的代码略显粗体。我建议这样做:

    [[self loadingView] playAnimation];
    [self performSelector:@selector(loadTable) withObject:nil afterDelay:0]
    

    加载表格的实际代码在loadTable 中。这意味着当 runloop 出现时,您的 UI 将被更新,动画开始播放,然后loadTable 方法被调用并完成其工作。

    如果动画需要主线程干预才能执行,这仍然不起作用。也就是说,如果加载表格的代码使主线程停止,您的动画也可能停止。除了在单独的线程中执行长期任务(可能使用也可能不使用performSelector:onMainThread:waitUntilDone 来安排主线程上的 UI 更新)之外,确实没有其他办法。

    如果您不太关心动画本身,您可能会发现https://github.com/samvermette/SVProgressHUD 之类的内容很有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-02
      • 1970-01-01
      • 2020-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-16
      • 1970-01-01
      相关资源
      最近更新 更多