2012-04-22 6 views
5

Ich arbeite an einigen CoreAnimation Sachen. Ein Navigationscontroller mit einigen View-Controllern. Und die View-Controller haben UISCrollViews für verschiedene "Seiten" einer "Broschüre". Auf jeder Seite gibt es möglicherweise eine Animation, die ausgelöst wird, wenn der Benutzer auf diese Seite umschaltet.statische Variablen innerhalb von Objective-C-Blöcken?

Ich war so etwas wie dies versuchen (für One-Shot-Animationen).

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]; 

„Animation Name“ und „einige Seitenzahl“ Platzhalter für Zwecke der Erläuterung sind (sie sind willkürlich NSString Literale).

Und der Code, der diese Animationen auslöst, ist:

- (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]; 
} 

So weit so gut, dass nur, wenn ich die Broschüre aus dem Navigationscontroller Pop (aka dealloc auf der Broschüre nennt) und dann wieder einschieben Der statische Bool ist immer noch gesetzt.

Meine Gedanken:

- am Halte ich den Block? Ich weiß nicht .. Ich bin Release Aufruf nach dem Hinzufügen (mit Kopie) in das Wörterbuch und auch die dealloc Methode Broschüre nennt Release auf dem Wörterbuch.

- bin ich halten eine weitere Kopie der statischen Bool irgendwo? Mein erster Bool zugewiesen, wenn ich den Block als statisch im Rahmen eines Verfahrens zu erklären .. hängt gut auf Objective-C der Aktivierung Rekordschema, das ich in nicht aussehen. Aber vorausgesetzt, dass diese Kopie beim Freigeben des Objekts auf popViewcOntroller verschwunden ist. Und eine weitere Kopie des Aufrufs der Kopie auf dem Block beim Hinzufügen zum Wörterbuch sollte freigegeben werden, wenn das Wörterbuch beendet wird?

am Halte ich die ganze Broschüre Objekt selbst? Ich habe es nicht komplett aus den Apple Docs bekommen, aber sie sagen, wenn ich auf eine Instanzvariable per Referenz zugreife, behalte ich mich selbst. Ich habe versucht, mich selbst aus dem Block freizugeben und alles läuft gut ...?

+0

Ich glaube nicht, sollten Sie 'mischen copy' mit' Block_release() '[Bausteinen Programmieren Themen] (http: // developer. apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/bxUsing.html#//apple_ref/doc/uid/TP40007502-CH5-SW1) –

+0

eh? Das ist der Weg, um einen Block vom Stapel auf den Haufen zu verschieben – SaldaVonSchwartz

+0

Das Dokument schlägt vor, dass Sie eine Block_copy() mit Block_Release() 'und' Balance Kopie oder behalten mit Release (oder Autorelease) ' –

Antwort

1

Machen Sie den Block einen Wert zurückgeben und dann entscheiden, ob der Block aus dem Wörterbuch zu entfernen.

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

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

ist die statische Variable

@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]; 
} 

Diese gibt

#=> 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 

Lassen Sie testen Wie lösen wir das Problem? Ich würde wahrscheinlich das Objekt aus dem Wörterbuch entfernen, sobald es wie dieser

- (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

Recht habe ich darüber nachgedacht, aber das Problem ist nicht alle Animationsblöcke sind "One Shot". Einige sollten jedes Mal neu ausgeführt werden und nicht aus dem Wörterbuch entfernt werden. Also brauche ich einen Weg, um den Block auf einen Schuss zu setzen oder nicht. – SaldaVonSchwartz

+0

Zwei verschiedene Wörterbücher? –

+0

ehhh ... ich meine sicher ... aber es ist nicht elegant genug (für meinen Geschmack im Rahmen dieses Projektes zumindest, nichts für ungut). Mein Gedanke war, dass der Block sich wie ein Thread verhält und seinen eigenen Stapel von Arten haben muss. Also muss es einen Weg geben, den internen Status während der gesamten Aufrufe zu behalten. – SaldaVonSchwartz

0

Ihres Kommentar

ausgeführt worden war

So weit so gut, nur dass, wenn ich Pop die Broschüre von dem Navigations Controller (auch bekannt als ruft dealloc auf der Broschüre auf) und drückt es dann erneut in , der statische Bool ist noch gesetzt.

scheint Ihnen eine auf den geschoben View-Controller BOOL Membervariable wollen bedeuten ... Wenn das stimmt können Sie diese objc_setAssociatedObject() mit erreichen.

Ich könnte eine Kategorie UIViewController hinzufügen, dies zu erreichen:

@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 .. aber Brochure ist Ihre Push-Ansicht-Controller, und es wird dealloc'd ... so wird dies nicht helfen – nielsbot

+0

Richtig ... wie ich Paul sagte, ist der Bool nicht für den View-Controller. Der Bool war gedacht als eine Möglichkeit für die vielen Blöcke, die im Wörterbuch der Controller gehalten wurden, um zu wissen, ob sie wiederholen sollten oder nicht. Es soll Teil des "internen Zustands" eines Blocks sein, unabhängig vom View-Controller, in dem sie deklariert werden. Also ein Bool pro Block – SaldaVonSchwartz

+0

klingt wie Ihr Block braucht eine Member-Variable. Sie können immer noch "objc_setAssociatedObject" – nielsbot