2012-05-08 13 views
9

Staram się rozszerzyć funkcjonalność SimpleAudioEngine z cocos2d z możliwością odtwarzania kilku efektów dźwiękowych jeden po drugim jako pewnego rodzaju łańcucha. Próbowałem to zrobić z rozszerzeniem. Jednak teraz zdałem sobie sprawę, że prawdopodobnie potrzebuję również iVar, aby zapamiętać nazwy wszystkich plików dźwiękowych i jeden do zapamiętania, który dźwięk jest obecnie odtwarzany.Objective-C Kategoria i nowy iVar

Wygląda jednak na to, że nie mogę dodać iVars do kategorii. Zamiast tego próbowałem użyć rozszerzenia, ale wygląda na to, że muszą znajdować się w oryginalnym pliku .m klasy, więc to też nie zadziała. Czy istnieje jeszcze inny sposób, który pozwala mi to zrobić?

Nagłówek z kategorii

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

a .m-pliku z rozszerzeniem:

#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 

Alternatywnie próbowałem zdefiniować Ivars jako właściwości, które będzie skompilować. Jednak nie mogę ich ani syntezować, ani nie mam żadnej innej możliwości związania ich z żadną metodą.

Próbuję wdrożyć funkcjonalność jako kategorię SimpleAudioEngine, tak że potrzebuję tylko pamiętać jedną klasę, która zajmuje się wszystkimi moimi problemami z dźwiękiem. i tak, że mogę stworzyć łańcuch tak proste, jak to:

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

Jeśli istnieje inny sposób, który daje taki sam/podobny wynik byłbym bardzo wdzięczny.

+1

Dlaczego nie ma podklasy SimpleAudioEngine? – lawicko

+0

możliwy duplikat [Objective-C: Property in Category] (http: // stackoverflow.com/questions/8733104/target-c-property-in-category) – hfossli

Odpowiedz

22

Masz rację, że nie można dodawać zmiennych instancji (lub zsyntetyzowanych @ właściwości) do kategorii. Można obejść to ograniczenie korzystania wsparcie Objective-C Runtime dla Associative References

coś takiego:

W swojej .h:

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

W swojej .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 

(Obowiązuje standardowe zastrzeżenie, wpisałem to w przeglądarce i nie przetestowałem, ale użyłem tej techniki wcześniej.)

Dokumentacja, z którą się łączyłem, zawiera dużo więcej informacji na temat działania odwołań asocjacyjnych.

+0

Zapomniałem powiedzieć, że pracuję na iOS. Dodałem tę informację do tagów. W systemie iOS takie podejście jest zabronione. Czy wiesz, czy nadal istnieją sposoby osiągnięcia tego celu, czy też muszę utworzyć nową klasę, która oferuje pożądaną funkcjonalność? –

+0

@gebirgsbaerbel: Zakaz w systemie iOS? Gdzie to usłyszałeś? – Chuck

+0

@Chuck w dokumentacji mówi, że funkcja jest dostępna na MacOS10.6 i nowszych. Również wypróbowałem to i zasadniczo dostaję błąd, że dwie metody nie są znane. Plik nagłówkowy, który je zawiera, wydaje się nie istnieć w systemie iOS. Może coś przeoczyłem? –

-1

Nie można dodawać obiektów iVars, ale można dodawać zmienne właściwości. Coś jak poniżej:

W swojej .h:

#import <objc/runtime.h> 

@interface Chair (Liking) 

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

W swojej .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 

Potem gdzieś w innej klasie powiedzieć myViewController.m

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