2012-02-23 11 views
10

La siguiente es mi categoría Objective-C en NSTimer para hacer disparos basados ​​en bloques de NSTimers. No puedo ver nada malo con eso, pero lo que obtengo es que el bloque que paso al método schedule... está siendo desasignado a pesar de que llamé al copy.NSTimer con bloque - ¿Lo estoy haciendo bien?

¿Qué me estoy perdiendo?

typedef void(^NSTimerFiredBlock)(NSTimer *timer); 

@implementation NSTimer (MyExtension) 

+ (void)timerFired:(NSTimer *)timer 
{ 
    NSTimerFiredBlock blk = timer.userInfo; 
    if (blk != nil) { 
     blk(timer); 
    } 
} 

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds 
            repeats:(BOOL)repeats 
            callback:(NSTimerFiredBlock)blk 
{ 
    return [NSTimer scheduledTimerWithTimeInterval:seconds 
              target:self 
              selector:@selector(timerFired:) 
              userInfo:[blk copy] 
              repeats:repeats]; 
} 

@end 
+1

Creo '(nulo) timerFired: (NSTimer *) timer' debe ser un método de instancia' -', no un método de clase '+'. Lo mismo probablemente se aplica a 'scheduledTimerWithTimeInterval', pero estoy menos seguro de eso. – dasblinkenlight

+6

Ese no sería el caso. Los métodos programados de NSTimer son métodos de clase. – user1175914

+1

Pasando 'self' ya que el objetivo sugiere fuertemente un método de instancia. Todos los ejemplos de código de 'NSTimer' que he visto también usan métodos de instancia para selectores. – dasblinkenlight

Respuesta

0

probar esto

typedef void(^NSTimerFiredBlock)(NSTimer *timer); 

@interface NSObject (BlocksAdditions) 

- (void)my_callBlock:(NSTimer *)timer; 

@end 

@implementation NSObject (BlocksAdditions) 

- (void)my_callBlock:(NSTimer *)timer { 
    NSTimerFiredBlock block = (id)self; 
    block(timer); 
} 

@implementation NSTimer (MyExtension) 

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds 
            repeats:(BOOL)repeats 
            callback:(NSTimerFiredBlock)blk 
{ 
    blk = [[blk copy] autorelease]; 
    return [NSTimer scheduledTimerWithTimeInterval:seconds 
              target:blk 
              selector:@selector(my_callBlock:) 
              userInfo:nil 
              repeats:repeats]; 
} 

@end 
+1

En realidad, probé esta solución y sigo teniendo el mismo problema. No creo que los selectores no sean compatibles con los métodos de clase. Los objetos de clase también son objetos de primera clase en Objective-C. Los selectores – user1175914

+1

definitivamente son compatibles con los métodos de clase. Tu problema es bloquear el desasignamiento antes de que se active el temporizador, pero no puedo ver por qué sucede esto. ¿Cuál es el mensaje de error? –

2

lo que se pierde es que si el bloque que está pasando en está en la pila a continuación copy hará exactamente lo que su nombre dice - que va a crear una copia del bloque en el montón. Por lo tanto, no esperarías ningún cambio en el comportamiento del que pasaste; nadie nuevo lo está reteniendo. La copia permanecerá activa mientras se desasigna el original.

(aparte: si no está utilizando ARC También querrá a AutoRelease la copia; que está destinado a pasar una referencia no propietario como userInfo: de otra manera nunca se cancela la asignación de la copia.)

+0

exactamente lo que quería ... ¡salud! –

8

¡Tienes un proyecto en github que hace el trabajo!

Cocoapod BlocksKit, le permiten Blockify un montón de clases ...

#import "NSTimer+BlocksKit.h" 
[NSTimer bk_scheduledTimerWithTimeInterval:1.0 block:^(NSTimer *time) { 
     // your code 
    } repeats:YES]; 
29

me encontré con este código en más de http://orion98mc.blogspot.ca/2012/08/objective-c-blocks-for-fun.html

Gran trabajo

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.7 
     target:[NSBlockOperation blockOperationWithBlock:^{ /* do this! */ }] 
     selector:@selector(main) 
     userInfo:nil 
     repeats:NO 
]; 
+0

Guau, esto es genial.De la experimentación, si no tengo una referencia al NSTimer, parece que vive hasta que se dispara y luego se limpia. – davew

+0

¡es genial! –

2

Aquí está la versión de Swift Mc.Stever's answer:

NSTimer.scheduledTimerWithTimeInterval(0.7, target: NSBlockOperation(block: { 
    /* do work */ 
}), selector: "main", userInfo: nil, repeats: false) 
+0

Swift 2.2: NSTimer.scheduledTimerWithTimeInterval (0.7, destino: NSBlockOperation (bloque: { /* do work */ }), selector: #selector (NSOperation.main), userInfo: nil, repeats: false) – Fraser

Cuestiones relacionadas