2012-05-08 8 views
9

Intento ampliar la funcionalidad de SimpleAudioEngine de cocos2d con la capacidad de reproducir varios efectos de sonido uno tras otro como un tipo de cadena. Intenté hacer esto con una extensión. Sin embargo, ahora me di cuenta de que probablemente también necesito un iVar para recordar los nombres de todos los archivos de sonido y uno para recordar qué sonido se está reproduciendo actualmente.Categoría Objective-C y nueva iVar

Sin embargo, parece que no puedo agregar iVars en una categoría. En cambio, traté de usar una extensión, pero parece que necesitan estar en el archivo .m original de la clase, por lo que tampoco funcionaría. ¿Hay alguna otra forma más que me permita hacer esto?

La cabecera con la categoría

#import <Foundation/Foundation.h> 
@interface SimpleAudioEngine(SoundChainHelper)<CDLongAudioSourceDelegate> 
-(void)playSoundChainWithFileNames:(NSString*) filename, ...; 
@end 

Y el .m-archivo con la extensión:

#import "SoundChainHelper.h" 

@interface SimpleAudioEngine() { 
    NSMutableArray* soundsInChain; 
    int currentSound; 
} 
@end 

@implementation SimpleAudioEngine(SoundChainHelper) 

// read in all filenames and start off playing process 
-(void)playSoundChainWithFileNames:(NSString*) filename, ... { 
    soundsInChain = [[NSMutableArray alloc] initWithCapacity:5]; 

    va_list params; 
    va_start(params,filename); 

    while (filename) { 
     [soundsInChain addObject:filename]; 
     filename = va_arg(params, NSString*); 
    } 
    va_end(params); 
    currentSound = 0; 
    [self cdAudioSourceDidFinishPlaying:nil]; 
} 

// play first file, this will also always automatically be called as soon as the previous sound has finished playing 
-(void)cdAudioSourceDidFinishPlaying:(CDLongAudioSource *)audioSource { 
    if ([soundsInChain count] > currentSound) { 
     CDLongAudioSource* mySound = [[CDAudioManager sharedManager] audioSourceForChannel:kASC_Right]; 
     [mySound load:[soundsInChain objectAtIndex:0]]; 
     mySound.delegate = self; 
     [mySound play]; 
     currentSound++; 
    } 
} 

@end 

alternativa que trataron de definir los Ivars como propiedades, que compilará. Sin embargo, no puedo sintetizarlos ni tengo ninguna otra posibilidad para vincularlos a ningún método.

Intento implementar la funcionalidad como una categoría de SimpleAudioEngine para que solo tenga que recordar una clase que trate todos mis problemas de sonido. y de modo que pueda crear una cadena tan simple como esto:

[[SimpleAudioEngine sharedEngine] playSoundChainWithFileNames:@"6a_loose1D.mp3", @"6a_loose2D.mp3", @"6a_loose3D.mp3", @"6a_loose4D.mp3", @"6b_won1D.mp3", nil]; 

Si hay otra manera que se obtiene el mismo resultado/similar que también estaría muy agradecido.

+1

¿Por qué no la subclase SimpleAudioEngine? – lawicko

+0

posible duplicado de [Objective-C: Propiedad en categoría] (http: // stackoverflow.com/questions/8733104/objective-c-property-in-category) – hfossli

Respuesta

22

Tiene razón en que no puede agregar variables de instancia (o @properties sintetizadas) a una categoría. Puede solucionar esta limitación mediante el apoyo del tiempo de ejecución de Objective-C para Associative References

algo así:

En su .h:

@interface SimpleAudioEngine (SoundChainHelper) 
    @property (nonatomic, retain) NSMutableArray *soundsInChain; 
@end 

En su .m:

#import <objc/runtime.h> 
static char soundsInChainKey; 

@implementation SimpleAudioEngine (SoundChainHelper) 

- (NSMutableArray *)soundsInChain 
{ 
    return objc_getAssociatedObject(self, &soundsInChainKey); 
} 

- (void)setSoundsInChain:(NSMutableArray *)array 
{ 
    objc_setAssociatedObject(self, &soundsInChainKey, array, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 

@end 

(Se aplica la cláusula de exención de responsabilidad estándar. Escribí esto en el navegador y no lo probé, pero he utilizado esta técnica antes).

La documentación a la que me he vinculado tiene mucha más información sobre cómo funcionan las referencias asociativas.

+0

Olvidé decir que estoy trabajando en iOS. Ahora agregué esta información a las etiquetas. En iOS, este enfoque está prohibido. ¿Sabes si todavía hay formas de lograr esto o necesito crear una nueva clase que ofrezca la funcionalidad que deseo? –

+0

@gebirgsbaerbel: ¿Prohibido en iOS? ¿De dónde has oído eso? – Chuck

+0

@Chuck en la documentación dice que la función está disponible en MacOS10.6 y posterior. También lo probé y básicamente recibí el error de que los dos métodos no se conocen. El archivo de encabezado que los contiene no parece existir en iOS. Tal vez me perdí algo? –

-1

No puede agregar iVars pero puede agregar variables de propiedad. Algo como a continuación:

En su .h:

#import <objc/runtime.h> 

@interface Chair (Liking) 

    @property (nonatomic, assign)BOOL liked; 
@end 

En su .m:

#import "Chair+ChairCat.h" 

@implementation Chair (Liking) 

-(BOOL)liked{ 

    return [ objc_getAssociatedObject(self, "_aliked") boolValue ] ;  
} 

-(void)setLiked:(BOOL)b{  
    objc_setAssociatedObject(self, "_aliked", [ NSNumber numberWithBool:b ],OBJC_ASSOCIATION_RETAIN_NONATOMIC) ; 

} 

@end 

Entonces en algún lugar de alguna otra clase decir myViewController.m

#import "Chair+ChairCat.h" 
- (void)viewDidLoad { 
    ///// 
    Chair *chair = [[Chair alloc] init]; 
    [chair setLiked:NO]; 
} 
Cuestiones relacionadas