Question

I've created a class that contains three properties that are Core Audio types:

@interface AudioFilePlayer : NSObject <NSCoding>

@property (assign) AudioUnit                        mAudioUnit;
@property (assign) AUNode                           mNode;
@property (assign) AudioStreamBasicDescription      mStreamFormat;

@end

My app holds an array of objects of type AudioFilePlayer and I want to archive and unarchive them using NSCoding. I've written the encodeWithCoder: and initWithCoder: methods as follows:

- (void)encodeWithCoder:(NSCoder *)aCoder
{        
    [aCoder encodeBytes:(uint8_t*)&_mAudioUnit length:sizeof(AudioUnit) forKey:@"mAudioUnit"];
    [aCoder encodeBytes:(uint8_t*)&_mNode length:sizeof(AUNode) forKey:@"mNode"];
    [aCoder encodeBytes:(uint8_t*)&_mStreamFormat length:sizeof(AudioStreamBasicDescription) forKey:@"mStreamFormat"];
}

- (id)initWithCoder:(NSCoder *)aDecoder
{        
    self = [super init];
    if (self) {
        [self setMAudioUnit:(AudioUnit)[aDecoder decodeBytesForKey:@"mAudioUnit" returnedLength:sizeof(AudioUnit)]];

        [self setMNode:(AUNode)[aDecoder decodeBytesForKey:@"mNode" returnedLength:sizeof(AUNode)]];
        [self setMStreamFormat:*(AudioStreamBasicDescription*)[aDecoder decodeBytesForKey:@"mStreamFormat" returnedLength:sizeof(AudioStreamBasicDescription)]];
    }

    return self;
}

I'm able to encode/archive successfully (that is to say a file is written and no errors are returned...I'm not sure it's actually working) but when I launch the app and try to decode/unarchive the object, the app crashes with:

Thread 1: EXC_BAD_ACCESS (code=2,address=0x4)

on this line in my initWithCoder method:

[self setMAudioUnit:(AudioUnit)[aDecoder decodeBytesForKey:@"mAudioUnit" returnedLength:sizeof(AudioUnit)]];

This is my first time using NSCoding so I'm not at all confident I'm doing this even remotely correctly.

These three Core Audio data types are structs so using the "bytes" version of the encode/init NSCoder methods seems like the right way to go.

Any ideas on where I might be going wrong?

Was it helpful?

Solution

If you have a look at decodeBytesForKey:returnedLength: you would see that returnedLength is a NSUInteger* and you're passing an integer. Besides the method returns const uint8_t*, so you need to dereference it to get back your data.

Instead of

[self setMAudioUnit:(AudioUnit)[aDecoder decodeBytesForKey:@"mAudioUnit" returnedLength:sizeof(AudioUnit)]];

it should be

NSUInteger szAudioUnit;
const uint8_t* audioUnitBytes = [aDecoder decodeBytesForKey:@"mAudioUnit" returnedLength:&szAudioUnit];
AudioUnit* pAudioUnit = (AudioUnit*)audioUnitBytes;
self.mAudioUnit = *pAudioUnit;

Actually I don't know how you code even compiled !

On a side note, maybe just my opinion, it's not a convention in Objective-C to name properties with an m prefix.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top