2012-03-30 7 views
7

Ich verwende Grand Central Dispatch-Methoden, um einige Ausführungen meiner App in einer Warteschlange auszuführen. Ich entscheide die Rahmen für Schaltflächen in einer Berechnung in dieser Warteschlange. Ich möchte, dass meine App ihren Scren neu zeichnet und nach der Rotation neue Frames berechnet. Hier einige Pseudo-Code Erklärung von dem, was ich tue:Wie man einen Block des Codes nennt und ihn in einer anderen Methode nennt?

CGFloat a=123, b=24; 
    dispatch_async(drawingQue, ^{ 
     //needed loops to get the total button count-how many ones will be drawn et.. 
     for(int x=0;x<someCount<x++){ 
      for(int y=0;y<anotherCount;y++){ 

     //needed frame&name ect assingments 

     button.frame= CGRectMake(x+y, x-y, a, b); 
     [button setTitle:@"abc"];}} 
     }; 

Hier ist, was ich will, ist, wie kann ich diesen Block einen Namen geben und wieder verwenden es in der

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
} 

Delegatmethode? Zum Beispiel, wenn die Rotation ist Landschaft, ich möchte a=234 anstelle von 123 verwenden .. Jede Hilfe bitte. Vielen Dank im Voraus ..

Antwort

6

eine Instanzvariable von Blocktyp deklarieren und Block_copy den Block zu halten verwenden:

@interface My { 
    void (^myBlock)(void); 
} 
@end 

myBlock = Block_copy(^{ 
    ...block code... 
}); 

// later call it 
myBlock(); 

// don't forget to release it in dealloc 

Es ist wichtig zu Kopie der Block, bevor er außerhalb des Anwendungsbereichs der wörtlichen Speicherung (^{...}), weil der ursprüngliche Block im Stack gespeichert ist und beim Beenden des Scope sterben wird.

+0

Es ist wichtig zu beachten, dass die Bezugnahme auf "self" oder irgendeinen ivar innerhalb eines Blocks, der selbst in einem ivar gehalten wird, einen Retain-Zyklus und somit ein leak erzeugt. Sie können den Zyklus unterbrechen, indem Sie entweder durch einen '__block id blockSelf = self;' -Zeiger auf Ivars verweisen oder indem Sie den Block _before_ 'dealloc' freigeben. –

1

Nur @property machen, dass ein Block ist, speichern Sie es, und es später wieder verwenden:

typedef void (^MyBlock)(CGFloat, CGFloat); 
... 
@property(readwrite, copy) MyBlock buttonFramesBlock; 
... 
@synthesize buttonFramesBlock; 
... 
self.buttonFramesBlock = ^(CGFloat a, CGFloat b){ 
    //needed loops to get the total button count-how many ones will be drawn et.. 
    for(int x=0;x<someCount<x++){ 
     for(int y=0;y<anotherCount;y++){ 

    //needed frame&name ect assingments 

    button.frame= CGRectMake(x+y, x-y, a, b); 
    [button setTitle:@"abc"];}} 
}; 
... 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    dispatch_async(drawingQue, ^{ 
     self.buttonFramesBlock(234,someOtherInt); 
    }); 
} 
1

Zuerst UI nie außerhalb des Haupt-Threads ändern. So sollte Ihr Code in so etwas wie ändern:

dispatch_async(drawingQue, ^{ 
    // ... 

    dispatch_async(dispatch_get_main_queue(), ^{ 
     button.frame= CGRectMake(x+y, x-y, a, b); 
     [button setTitle:@"abc"]; 
    }); 
}); 

Zweitens nie UI innerhalb des shouldAutorotateToInterfaceOrientation Methode ändern. Innerhalb dieser Methode müssen Sie nur zurückgeben, ob die Ansicht gedreht werden soll oder nicht. In einigen Fällen, in denen Sie zum Beispiel eine View-Controller-Hierarchie haben, wird die Ansicht möglicherweise nicht gedreht, selbst wenn Sie YES in zurückgeben.

Also, sollten Sie Ihren Code innerhalb der Methode aufrufen:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 

Dies kann auf vielfältige Weise erreicht werden. Die einfachste (und die, die ich empfehlen kann) ist eine Standard-Objective-C-Methode zu verwenden:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) { // landscape 
     [self rotateButtonWithA:234 b:24]; 
    } else { // portrait 
     [self rotateButtonWithA:123 b:24]; 
    } 

} 

- (void)rotateButtonWithA:(CGFloat)a b:(CGFloat)b 
{ 
    dispatch_async(drawingQue, ^{ 
     // ... 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      button.frame= CGRectMake(x+y, x-y, a, b); 
      [button setTitle:@"abc"]; 
     }); 
    }); 
} 

Sie nicht wirklich braucht, den Block selbst von mehreren Stellen zu nennen. Aber wenn Sie das noch tun wollen, gibt es hier viele Antworten, die Ihnen zeigen, wie Sie das tun.

+0

Ihre Antwort sieht vernünftig aus, aber wie kann ich mit dieser Situation umgehen? Wenn ich die Rahmen statisch entscheide, wenn es sich dreht, sieht es schrecklich aus – ilhnctn

+0

Danke im Voraus. Wirklich gute Antwort-Erklärung. – ilhnctn

Verwandte Themen