Threads and autoreleasepool questions

感情迁移 提交于 2019-12-24 16:18:15

问题


As I understand there are several ways to send tasks to be performed in threads. The most common ones that I use are:

1) performSelector:withObject:afterDelay:

2) performSelectorOnMainThread:withObject:waitUntilDone:

3) performSelectorInBackground:withObject:

4) [NSThread detachNewThreadSelector:toTarget:withObject:]

My first question is, what is the difference between 1) and 2), besides the obvious parameter differences? Are they actually both working in the Main thread (whose autorelease pool was automatically created in main.m)? I just read from someone's post on Stackoverflow that method 1) is actually working in a new thread, and so an autorelease pool should be created for its selector method. Is this correct? I've been using 1) a lot, mostly to take advantage of the delay parameter, but I've never created an autorelease pool for them. Nothing catastrophic has happened.

Next, 3) and 4) both perform tasks in a separate thread. I hear that UI stuff should never be done in these threads, but I'm confused as to what is strictly UI. I was trying to write code to basically play a repeating loading animation while a tableview is launching modally from a navigationcontroller. The animation is then stopped in the viewDidLoad method of the tableview controller. Initially, I just stuck the code to start the animation above the lines of code that start the modal view. What happened was the animation was never played.

[[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];

I then tried the following, and it worked...

[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];

}

Animation keeps playing until the SettingsViewController view is fully launched. But does launching modal views like this count as "UI" and should be avoided? Also I am getting some weird memory leak errors in Instruments every time the modal view is launched. But it's from one of those "System Libraries", which I've been told is very difficult to debug. What might be going wrong here?

Sorry for the embarrassingly long post. Any help will be appreciated!


回答1:


(1) schedules a task for the current runloop. At a very high level, an UIKit application looks like

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

This is why you didn't see your UI updated in your first attempt; the call to playAnimation schedules the UI to be updated in the next iteration of the runloop, but it never gets there until the code that followed it is completed.

Note that performSelector:withObject:afterDelay does not run the specified code in a seperate thread.

(2) does something very similar, but rather than scheduling something for the current runloop it schedules something for the runloop on the main thread. This is only useful if invoked from a separate thread, typically because you want to update the UI from a secondary thread.

And yes, your code is slightly bold. I would suggest to do something like:

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

where the actual code to load the table is in loadTable. This means that when the runloop comes around, your UI will be updated, the animation starts playing, then the loadTable method gets called and do its job.

This still will not work however if the animation requires intervention from the main thread to execute. That is, if the code to load the table stalls the main thread, your animation might stall too. There really is no way around that except doing the long run task in a separate thread (which may or may not use performSelector:onMainThread:waitUntilDone to schedule UI updates on the main thread).

If you don't care too much about the animation itself, you might find something like https://github.com/samvermette/SVProgressHUD useful.



来源:https://stackoverflow.com/questions/7452925/threads-and-autoreleasepool-questions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!