multithreading iPhone:如何使用 performSelector:onThread:withObject:waitUntilDone: 方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2584394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iPhone: how to use performSelector:onThread:withObject:waitUntilDone: method?
提问by Michael Kessler
I am trying to use a separate thread for working with some API.
我正在尝试使用单独的线程来处理某些 API。
The problem is that I am not able to use performSelector:onThread:withObject:waitUntilDone:
method with a thread that I' instantiated for this.
问题是我无法将performSelector:onThread:withObject:waitUntilDone:
方法与我为此实例化的线程一起使用。
My code:
我的代码:
@interface MyObject : NSObject {
NSThread *_myThread;
}
@property(nonatomic, retain) NSThread *myThread;
@end
@implementation MyObject
@synthesize myThread = _myThread;
- (NSThread *)myThread {
if (_myThread == nil) {
NSThread *myThreadTemp = [[NSThread alloc] init];
[myThreadTemp start];
self. myThread = myThreadTemp;
[myThreadTemp release];
}
return _myThread;
}
- (id)init {
if (self = [super init]) {
[self performSelector:@selector(privateInit:) onThread:[self myThread] withObject:nil waitUntilDone:NO];
}
return self;
}
- (void)privateInit:(id)object {
NSLog(@"MyObject - privateInit start");
}
- (void)dealloc {
[_myThread release];
_myThread = nil;
[super dealloc];
}
@end
"MyObject - privateInit start"
is never printed.
What am I missing?
"MyObject - privateInit start"
从不打印。
我错过了什么?
I tried to instantiate the thread with target and selector, tried to wait for method execution completion (waitUntilDone:YES
).
Nothing helps.
我试图用目标和选择器实例化线程,试图等待方法执行完成(waitUntilDone:YES
)。
没有任何帮助。
UPDATE:
I don't need this multithreading for separating costly operations to another thread.
In this case I could use the performSelectorInBackground
as mentioned in few answers.
The main reason for this separate thread is the need to perform all the actions in the API (TTS by Loquendo) from one single thread.
Meaning that I have to create an instance of the TTS object and call methods on that object from the same thread all the time.
更新:
我不需要这个多线程来将昂贵的操作分离到另一个线程。
在这种情况下,我可以使用performSelectorInBackground
几个答案中提到的 。
这个单独线程的主要原因是需要从一个线程执行 API(Loquendo 的 TTS)中的所有操作。
这意味着我必须创建 TTS 对象的实例并始终从同一线程调用该对象上的方法。
采纳答案by Michael Kessler
I found an answer!
我找到了答案!
In order to keep the thread up, there is a need in additional piece of code:
为了保持线程运行,需要额外的一段代码:
- (void)threadMain:(id)data {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[runloop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (isAlive) { // 'isAlive' is a variable that is used to control the thread existence...
[runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
[pool release];
}
And the next line:
下一行:
NSThread *myThreadTemp = [[NSThread alloc] init];
Should be replaced by this one:
应该换成这个:
NSThread *myThreadTemp = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain:) object:nil];
EDIT: As was suggested by few people here I've added few lines of code (NSAutoreleasePool, addPort method and 'isAlive' boolean).
编辑:正如这里很少有人建议的那样,我添加了几行代码(NSAutoreleasePool、addPort 方法和“isAlive”布尔值)。
回答by Przemyslaw Zych
This is what works for me. Main loop taken from Apple's documentation http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW25
这对我有用。主循环取自 Apple 的文档 http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW25
- (void) start {
self.imageSaverThread = [[[NSThread alloc] initWithTarget:self selector:@selector(imageSaverThreadMain) object:nil] autorelease];
[self.imageSaverThread start];
}
- (void) imageSaverKeepAlive {
[self performSelector:@selector(imageSaverKeepAlive) withObject:nil afterDelay:60];
}
- (void)imageSaverThreadMain
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// Add selector to prevent CFRunLoopRunInMode from returning immediately
[self performSelector:@selector(imageSaverKeepAlive) withObject:nil afterDelay:60];
BOOL done = NO;
do
{
NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init];
// Start the run loop but return after each source is handled.
SInt32 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, YES);
// If a source explicitly stopped the run loop, or if there are no
// sources or timers, go ahead and exit.
if ((result == kCFRunLoopRunStopped) || (result == kCFRunLoopRunFinished))
done = YES;
[tempPool release];
}
while (!done);
[pool release];
}
Hope it helps
希望能帮助到你
回答by Andrey Lushnikov
Well, I suppose I've got a better solution
好吧,我想我有更好的解决方案
- (void)run{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
running = true;
[[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (running && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]){
//run loop spinned ones
}
[pool release];
}
What am i doing here?
1) Adding a mock port here as a Source will prevent runMode:beforeDate:
method from exiting immideately.
2) Method runMode:beforeDate:
blocks thread until there's something in runLoop.
我在这是要干嘛?
1)在此处添加一个模拟端口作为源将防止runMode:beforeDate:
方法立即退出。
2) 方法runMode:beforeDate:
阻塞线程,直到 runLoop 中有东西。
回答by Laurent Etiemble
You have created the thread, but it is not running. It must run in order to execute something.
您已经创建了线程,但它没有运行。它必须运行才能执行某些操作。
You may also use "performSelectorInBackground" instead. It will queue the invocation until the initialization is done.
您也可以改用“performSelectorInBackground”。它将对调用进行排队,直到初始化完成。