iphone - gcd - multithreading swift 4
iPhone: cómo usar performSelector: onThread: withObject: waitUntilDone: method? (4)
Estoy tratando de usar un hilo separado para trabajar con algunas API.
El problema es que no puedo usar el performSelector:onThread:withObject:waitUntilDone:
con un subproceso que he instanciado para esto.
Mi código:
@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"
nunca se imprime.
¿Qué me estoy perdiendo?
Intenté crear una instancia del subproceso con destino y selector, intenté esperar a que se completara el método ( waitUntilDone:YES
).
Nada ayuda.
ACTUALIZAR:
No necesito este multihilo para separar operaciones costosas a otro hilo.
En este caso, podría usar el performSelectorInBackground
como se menciona en algunas respuestas.
La razón principal de este subproceso separado es la necesidad de realizar todas las acciones en la API (TTS por Loquendo) desde un solo subproceso.
Lo que significa que tengo que crear una instancia del objeto TTS y llamar a los métodos en ese objeto desde el mismo hilo todo el tiempo.
¡Encontré una respuesta!
Con el fin de mantener el hilo, hay una necesidad de pieza adicional de código:
- (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];
}
Y la siguiente línea:
NSThread *myThreadTemp = [[NSThread alloc] init];
Debe ser reemplazado por éste:
NSThread *myThreadTemp = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain:) object:nil];
EDITAR : Como lo sugirieron algunas personas aquí, he agregado algunas líneas de código (NSAutoreleasePool, método addPort y booleano ''isAlive'').
Bueno, supongo que tengo una mejor solución.
- (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];
}
¿Qué estoy haciendo aquí?
1) La adición de un puerto simulado aquí como una Fuente evitará que el runMode:beforeDate:
salga de manera inmediata.
2) Método runMode:beforeDate:
bloquea el hilo hasta que hay algo en runLoop.
Esto es lo que funciona para mí. Bucle principal tomado de la documentación de 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];
}
Espero eso ayude
Usted ha creado el hilo, pero no se está ejecutando. Debe ejecutarse para ejecutar algo.
También puedes usar "performSelectorInBackground" en su lugar. Se pondrá en cola la invocación hasta que se realice la inicialización.