2012-04-22 15 views
5

Sto lavorando su alcune cose di CoreAnimation. Un controller di navigazione con alcuni controller di visualizzazione. E i controller di visualizzazione hanno UISCrollViews per diverse "pagine" di una "brochure". In ogni pagina potrebbero esserci delle animazioni che vengono attivate quando l'utente si gira verso quella pagina.variabili statiche all'interno dei blocchi Objective-C?

Stavo provando qualcosa di simile (per le animazioni one-shot).

void (^animationBlock)() = 
    ^{ 
    static bool alreadyTriggered = NO; 
    if(alreadyTriggered) 
     return; 

    [CATransaction begin]; 
    [CATransaction setCompletionBlock: 
    ^{ 
     alreadyTriggered = YES; 
    }]; 

    // Do me some animations... 

    [CATransaction commit]; 
    }; 

    NSMutableDictionary* pageBlocks = [[NSMutableDictionary alloc] init]; 
    [pageBlocks setObject:[animationBlock copy] forKey:<animation's name>]; 
    [self.animationBlocks setObject:pageBlocks forKey:<some page number>]; 

    [pageBlocks release]; 
    [animationBlock release]; 

"il nome di animazione" e "qualche numero di pagina" sono segnaposto per il bene della spiegazione (sono letterali NSString arbitrarie).

E il codice che fa scattare queste animazioni è:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 
{ 
    int pageNumber = floor(self.scrollView.contentOffset.x/self.scrollView.frame.size.width); 
    NSMutableDictionary* pageBLocks = [self.animationBlocks objectForKey:[NSString stringWithFormat:@"page%i",pageNumber]]; 
    [CATransaction begin]; 
    for(id key in pageBLocks) 
    ((void (^)())[pageBLocks objectForKey:key])(); 
    [CATransaction commit]; 
} 

Fin qui tutto bene, solo che se ho pop la brochure dal controller di navigazione (aka chiama dealloc sul depliant) e spingerlo di nuovo , il bool statico è ancora impostato.

I miei pensieri:

- Sono mantenendo il blocco? Non so .. Sto chiamando rilascio dopo averlo aggiunto (con copia) al dizionario e anche il metodo dealloc della brochure chiama rilascio sul dizionario.

- sto mantenendo un'altra copia del bool statico da qualche parte? Il mio primo valore bool viene assegnato quando dichiaro il blocco come statico nell'ambito di un metodo .. beh dipende dallo schema di registrazione di attivazione di Objective-C che non ho esaminato. Ma supponendo di sì, quella copia è sparita quando si rilascia l'oggetto su popViewcOntroller. E un'altra copia di esso dal richiamo della copia sul blocco quando la si aggiunge al dizionario dovrebbe essere rilasciata quando il dizionario viene ucciso?

sto conservando l'intero oggetto brochure stesso? Non l'ho preso completamente dai documenti Apple, ma dicono che se accedo a una variabile di istanza per riferimento, mantengo l'io. Ho provato a liberare me stesso dall'interno del blocco e tutto continua a funzionare bene ...?

+0

non credo che si deve mescolare '' copy' con Block_release() '[Blocchi di programmazione Argomenti] (http: // developer. apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/bxUsing.html#//apple_ref/doc/uid/TP40007502-CH5-SW1) –

+0

eh? Questo è il modo di spostare un blocco dalla pila all'heap – SaldaVonSchwartz

+0

Il documento suggerisce di "bilanciare un Block_copy() con Block_release()" e "bilanciare copia o conservare con release (o autorelease)" –

risposta

1

Fare in modo che il blocco restituisca un valore e quindi decidere se rimuovere o meno il blocco dal dizionario.

// ... 
    BOOL shouldRemove = block(); 

    if (shouldRemove) { 
     [pageBlocks removeObjectForKey:key]; 
    } 
// ... 

Testiamo la variabile statica

@interface TestClass : NSObject 
@end 

@implementation TestClass 

- (void(^)(void))block; 
{ 
    return [[^{ 

     static BOOL staticBOOL = NO; 

     NSLog(@"%d", staticBOOL); 

     staticBOOL = YES; 

    } copy] autorelease]; 
} 

@end 

int main(int argc, char *argv[]) { 
    NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init]; 

    TestClass *test1 = [[TestClass alloc] init]; 
    test1.block(); 
    test1.block(); 

    TestClass *test2 = [[TestClass alloc] init]; 
    test2.block(); 
    test2.block(); 

    [p release]; 
} 

Emette

#=> 2012-04-23 00:43:38.501 Untitled[8380:707] 0 
#=> 2012-04-23 00:43:38.503 Untitled[8380:707] 1 
#=> 2012-04-23 00:43:38.503 Untitled[8380:707] 1 
#=> 2012-04-23 00:43:38.504 Untitled[8380:707] 1 

Come si risolve il problema? Io probabilmente rimuovere l'oggetto dal dizionario una volta che fosse stato eseguito in questo modo

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView; 
{ 
    NSInteger pageNumber = floor(self.scrollView.contentOffset.x/self.scrollView.frame.size.width); 
    NSMutableDictionary *pageBlocks = [self.animationBlocks objectForKey:[NSString stringWithFormat:@"page%i", pageNumber]]; 

    [CATransaction begin]; 

    for (id key in [pageBlocks copy]) { 
     void (^block)(void) = [pageBlocks objectForKey:key]; 
     if (block) { 
      block(); 
     } 
     [pageBlocks removeObjectForKey:key]; 
    } 

    [CATransaction commit]; 
} 
+0

giusto ci ho pensato, ma il problema non è che tutti i blocchi di animazione sono "uno scatto". Alcuni dovrebbero effettivamente rieseguire ogni volta e non essere rimossi dal dizionario. Quindi ho bisogno di un modo in cui il blocco si possa impostare su un solo scatto o meno. – SaldaVonSchwartz

+0

Due dizionari diversi? –

+0

ehhh ... voglio dire certo ... ma non è abbastanza elegante (per i miei gusti almeno nell'ambito di questo progetto, senza offesa). Il mio pensiero era che il blocco si comporta in modo simile a un thread e deve avere il proprio stack di sorta .. quindi deve esserci un modo per mantenere lo stato interno durante le chiamate – SaldaVonSchwartz

0

Il tuo commento

Fin qui tutto bene, solo che se ho pop la brochure dal controller di navigazione (aka chiama dealloc sull'opuscolo) e poi lo inserisce nuovamente in , il bool statico è ancora impostato.

sembra implicare che si desidera una variabile BOOL membro sui controller di vista spinto ... Se questo è corretto, è possibile raggiungere questo obiettivo usando objc_setAssociatedObject().

mi permetto di aggiungere una categoria per UIViewController per raggiungere questo obiettivo:

@interface UIViewController (OneShotAnimation) 
@property (nonatomic) BOOL animationHasBeenPlayed ; 
@end 

@implementation UIViewController (OneShotAnimation) 

-(void)setAnimationHasBeenPlayed:(BOOL)b 
{ 
    objc_setAssociatedObject(self, @"animationHasBeenPlayed", [ NSNumber numberWithBool:b ], OBJC_ASSOCIATION_RETAIN_NONATOMIC) ; 
} 

-(BOOL)animationHasBeenPlayed 
{ 
    return [ objc_getAssociatedObject(self, @"animationHasBeenPlayed") boolValue ] ; 
} 

@end 
+0

oh .. ma la brochure è il tuo controller di visualizzazione spinto, ed è stato deallocato ... quindi questo non aiuterà – nielsbot

+0

Giusto ... come ho detto a Paul, il bool non è per il controller di visualizzazione. Il bool era inteso come un modo per i molti blocchi conservati nel dizionario dei controllori a ciascuno di loro a sapere se dovessero replicare o meno. Si suppone che faccia parte dello "stato interno" di un blocco indipendentemente dal controller della vista che viene dichiarato all'interno. Quindi un bool per blocco – SaldaVonSchwartz

+0

suona come se il tuo blocco avesse bisogno di una variabile membro. Puoi ancora usare 'objc_setAssociatedObject' – nielsbot