Objective-C分类和新iVar

9
我想扩展cocos2d的SimpleAudioEngine功能,使其能够按照某种链式方式播放多个音效。我试图使用扩展来实现此功能。然而,我现在意识到我可能还需要一个iVar来记住所有声音文件的名称,并且需要一个iVar来记住当前正在播放的声音。
但是,似乎我不能在类别中添加iVars。我尝试使用扩展,但是它们似乎需要在类的原始.m文件中,因此这也行不通。是否有另一种方法可以让我做到这一点?
带类别的头文件
#import <Foundation/Foundation.h>
@interface SimpleAudioEngine(SoundChainHelper)<CDLongAudioSourceDelegate>
-(void)playSoundChainWithFileNames:(NSString*) filename, ...;
@end

文件扩展名为 .m:

#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

另一种方法是将iVars定义为属性,这样可以编译。但是我既不能合成它们,也没有其他绑定它们到任何方法的可能性。

我尝试将功能实现为SimpleAudioEngine的类别,这样我只需要记住一个处理所有声音问题的类,以便我可以创建如下简单的链:

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

如果有其他能够产生相同/类似结果的方法,我也会非常感激。

1
为什么不继承自SimpleAudioEngine类? - lawicko
可能是Objective-C:类别中的属性的重复问题。 - hfossli
2个回答

24
您说得对,您无法在类别中添加实例变量(或合成的@property)。但是,您可以使用Objective-C运行时对关联引用的支持来解决此限制。
例如:
在您的.h文件中:
@interface SimpleAudioEngine (SoundChainHelper)
    @property (nonatomic, retain) NSMutableArray *soundsInChain;
@end

在你的 .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

(标准免责声明适用。我在浏览器中输入了这个,没有测试过,但我以前使用过这种技术。)
我链接的文档中有关于关联引用如何工作的更多信息。

我忘了说明我正在iOS上工作。我现在已经将这些信息添加到标签中了。在iOS上,这种方法是被禁止的。你知道是否仍然有办法实现这个功能,还是我需要创建一个新的类来提供我想要的功能? - gebirgsbärbel
@gebirgsbaerbel:在iOS上被禁止了?你从哪里听说的? - Chuck
@Chuck,在文档中指出该功能可在MacOS10.6及更高版本上使用。而且我已经尝试过,但基本上遇到了两种未知方法的错误。包含它们的头文件似乎在iOS上不存在。也许我错过了什么? - gebirgsbärbel
1
在使用Objective-C运行时函数(包括关联引用函数)的文件中,需要#import <objc/runtime.h>。它们可用于iOS。如果查看runtime.h,您会发现它们适用于OS X 10.6及更高版本和iOS 3.1及更高版本。 - Andrew Madsen
啊,谢谢你。虽然它在你的代码顶部,但我还是找不到正确的导入...有时候我有点瞎。 - gebirgsbärbel
我在最近的评论后添加了这个,所以你没有错过任何东西 :). 很高兴能帮到你! - Andrew Madsen

-1
你不能添加iVars,但可以添加属性变量。 类似下面这样:
在你的.h文件中:
#import <objc/runtime.h>

@interface Chair (Liking)

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

在你的 .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

然后在其他类中的myViewController.m文件中的某个地方

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接