2012-02-23 23 views
10

Quanto segue è la mia categoria Objective-C su NSTimer per eseguire l'attivazione basata su blocchi di NSTimers. Non riesco a vedere nulla di sbagliato in questo, ma quello che sto ottenendo è che il blocco che passo al metodo schedule... è stato deallocato nonostante io abbia chiamato copy su di esso.NSTimer con blocco - lo sto facendo bene?

Cosa mi manca?

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

Penso che '(void) timerFired: (NSTimer *) timer' dovrebbe essere un metodo di istanza' -', non un metodo di classe '+'. Lo stesso vale probabilmente per 'scheduledTimerWithTimeInterval', ma ne sono meno sicuro. – dasblinkenlight

+6

Non sarebbe il caso. I metodi pianificati di NSTimer sono metodi di classe. – user1175914

+1

Passare 'self' come target suggerisce fortemente un metodo di istanza. Tutti gli esempi di codice di 'NSTimer' che ho visto usano anche i metodi di istanza per i selettori. – dasblinkenlight

risposta

0

provare questo

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

In realtà, ho provato questa soluzione e sto ancora ricevendo lo stesso problema. Non penso che i selettori non siano supportati sui metodi di classe. Gli oggetti di classe sono anche oggetti di prima classe in Objective-C. I selettori – user1175914

+1

supportano sicuramente i metodi di classe. il tuo problema è che il blocco viene deallocato prima del timer, ma non riesco a capire perché questo sta accadendo. qual è il messaggio di errore? –

2

cosa che ti manca è che se il blocco si sta passando è in pila allora copy farà esattamente ciò che dice il nome - si creerà un copia del blocco sull'heap. Non ti aspetteresti quindi alcun cambiamento nel comportamento di quello che hai passato; nessuno di nuovo lo sta conservando. La copia rimarrà in vita mentre l'originale viene deallocato.

(a parte: se non si sta usando ARC si potrà anche autorelease la copia, sei destinato a passare un riferimento non possedere come userInfo: In caso contrario, la copia non sarà mai deallocato.)

+0

esattamente quello che volevo ... evviva! –

8

Hai un progetto su github che fa il lavoro!

Cocoapod BlocksKit, consentono di Blockify un gruppo di classi ...

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

Ho trovato questo codice sopra a http://orion98mc.blogspot.ca/2012/08/objective-c-blocks-for-fun.html

Grande lavoro

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

Wow, è grandioso.Dalla sperimentazione, se non ho un riferimento al NSTimer, sembra che sopravviva finché non scocca e poi viene ripulito. – davew

+0

è geniale !!! –

2

ecco la versione di 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, destinazione: NSBlockOperation (blocco: { /* do work */ }), selettore: #selector (NSOperation.main), userInfo: nil, ripetizioni: false) – Fraser

Problemi correlati