IPhone: как использовать performSelector: onThread: withObject: waitUntilDone: метод?
Я пытаюсь использовать отдельный поток для работы с некоторым 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
"MyObject - privateInit start"
никогда не печатается.
Что мне не хватает?
Я попытался создать экземпляр потока с целью и селектором, попытался дождаться завершения выполнения метода (waitUntilDone:YES
).
Ничего не помогает.
UPDATE:
Мне не нужна эта многопоточная обработка для разделения дорогостоящих операций на другой поток.
В этом случае я мог бы использовать performSelectorInBackground
, как упоминалось в нескольких ответах.
Основной причиной этого отдельного потока является необходимость выполнения всех действий в API (TTS by Loquendo) из одного потока.
Это означает, что я должен постоянно создавать экземпляр объекта TTS и вызывать методы для этого объекта из одного и того же потока.
Ответы
Ответ 1
Я нашел ответ!
Чтобы сохранить поток вверх, существует потребность в дополнительном фрагменте кода:
- (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];
}
И следующая строка:
NSThread *myThreadTemp = [[NSThread alloc] init];
Должен быть заменен следующим:
NSThread *myThreadTemp = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain:) object:nil];
EDIT: Как было предложено несколькими людьми здесь, я добавил несколько строк кода (NSAutoreleasePool, метод addPort и "isAlive" логический).
Ответ 2
Это то, что работает для меня. Основной цикл, взятый из документации 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];
}
Надеюсь, что это поможет
Ответ 3
Ну, я полагаю, у меня есть лучшее решение
- (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];
}
Что я здесь делаю?
1) Добавление mock-порта здесь как источника предотвратит выход из него метода runMode:beforeDate:
.
2) Метод runMode:beforeDate:
блокирует поток, пока не появится что-то в runLoop.
Ответ 4
Вы создали поток, но он не работает. Он должен работать, чтобы что-то выполнить.
Вместо этого вы можете использовать "performSelectorInBackground". Он будет вызывать очередь для вызова до тех пор, пока не будет выполнена инициализация.