2012-03-30 21 views
7

Uso los métodos de Grand Central Dispatch para realizar algunas ejecuciones de mi aplicación en una cola. Decido los marcos para botones en un cálculo en esa cola. Quiero que mi aplicación vuelva a dibujar su scren y calcule nuevos cuadros después de la rotación. Aquí hay un código de pseudo explicación de lo que hago:¿Cómo se nombra un bloque de código y se lo llama de otra manera?

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

aquí lo que quiero es, ¿Cómo puedo dar a este bloque un nombre y volver a utilizarlo en el método delegado

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

? Por ejemplo, si la rotación es horizontal, quiero usar a=234 en lugar de 123 ... Cualquier ayuda por favor. Gracias de antemano ..

Respuesta

6

declarar una variable de instancia de tipo de bloque y el uso Block_copy para mantener el bloque:

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

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

// later call it 
myBlock(); 

// don't forget to release it in dealloc 

Es importante copia del bloque antes de guardarla fuera del alcance de su literal (^{...}), porque el bloque original se almacena en la pila y morirá cuando el alcance se cierre.

+0

Es importante tener en cuenta que hacer referencia a 'self' o cualquier ivar dentro de un bloque que se mantiene en un ivar creará un ciclo de retención y, por lo tanto, una fuga. Puede romper el ciclo al referirse a ivars a través de un identificador '__block id BlockSelf = self;' o arreglando para liberar el bloque _before_ 'dealloc'. –

1

Simplemente haga una @property que es un bloque, almacenarlo y usarlo de nuevo más tarde:

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

En primer lugar, nunca cambian interfaz de usuario fuera del hilo principal. Así que su debe modificar el código en algo así como:

dispatch_async(drawingQue, ^{ 
    // ... 

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

En segundo lugar, nunca cambie la interfaz de usuario dentro del método shouldAutorotateToInterfaceOrientation. Todo lo que tiene que hacer dentro de ese método es devolver si la vista debe rotar o no. Por ejemplo, en algunos casos en los que tiene una jerarquía de controlador de vista, la vista puede no girar incluso si devuelve YES en shouldAutorotateToInterfaceOrientation.

Por lo tanto, debe llamar a su código dentro del método:

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

Esto se puede lograr de muchas maneras. El más simple (y la que yo recomiendo) es utilizar un método estándar de Objective-C:

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

Usted realmente no necesita llamar el propio bloque desde múltiples lugares. Pero si todavía quiere hacer eso, hay muchas respuestas aquí que le muestran cómo hacerlo.

+0

Su respuesta parece razonable, pero ¿cómo puedo manejar esta situación? Si decido los marcos estáticamente, cuando gira parece horrible – ilhnctn

+0

Gracias de antemano. Muy buena explicación de respuesta. – ilhnctn

Cuestiones relacionadas