iPhone:如何使用performSelector:onThread:withObject:waitUntilDone:方法?

Mic*_*ler 18 iphone multithreading

我正在尝试使用单独的线程来处理某些API.

问题是我无法使用performSelector:onThread:withObject:waitUntilDone:我为此实例化的线程的方法.

我的代码:

@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
Run Code Online (Sandbox Code Playgroud)

"MyObject - privateInit start"永远不会打印.
我错过了什么?

我试图用目标和选择器实例化线程,试图等待方法执行完成(waitUntilDone:YES).
什么都没有帮助.

更新:
我不需要这种多线程来将昂贵的操作分离到另一个线程.
在这种情况下,我可以使用performSelectorInBackground几个答案中提到的.
这个单独线程的主要原因是需要从一个单独的线程执行API中的所有操作(TTS by Loquendo).
这意味着我必须创建一个TTS对象的实例,并始终从同一个线程调用该对象的方法.

Mic*_*ler 14

我找到了答案!

为了保持线程,需要额外的代码:

- (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];
}
Run Code Online (Sandbox Code Playgroud)


而下一行:

NSThread *myThreadTemp = [[NSThread alloc] init];
Run Code Online (Sandbox Code Playgroud)

应该被这个替换:

NSThread *myThreadTemp = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain:) object:nil];
Run Code Online (Sandbox Code Playgroud)

编辑:正如这里的人们所建议的那样,我添加了几行代码(NSAutoreleasePool,addPort方法和'isAlive'布尔值).

  • 请注意,根据KermiDT的回答,线程还应该设置自己的自动释放池.为了使这个答案可以接受,1.添加,2.添加一个keepalive系统,以消除对未记录行为的依赖(根据KermiDT:添加一个选择器/ kotenok-gav:添加一个端口),3.更改while循环检查退出条件 - `do {...} while(!shouldExit)` - 和4.在循环后添加清理代码(释放autoreleasepool和任何其他变量). (2认同)

Prz*_*ych 13

这对我有用.主循环取自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];
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你