0

My goal is to store the reference of an audioPlayer instance in core data in that way, that i can use properties on that entry later. like this:

-(void)didTapButton
{
    if (!self.sound.audioPlayer.playing)
    {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"playSound" object:self.sound];
        self.soundProgress.hidden = NO;
    } else {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"stopSound" object:self.sound];
        self.soundProgress.hidden = YES;
    }
}

My MOS looks like this

@interface MCSound : NSManagedObject

@property (nonatomic, retain) AVAudioPlayer *audioPlayer;
@property (nonatomic, retain) NSString * category;
@property (nonatomic, retain) NSString * duration;
@property (nonatomic, retain) NSString * fileURL;
@property (nonatomic, retain) NSString * id;
@property (nonatomic, retain) NSNumber * isLooping;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSString * theme;
@property (nonatomic, retain) MCTheme *ofTheme;

@end

That works so far. But if i'd generate again the MOSs the AVAudioPlayer Class would be replaced by id. Is there a way how i can do that with categories? Would i have to use after that of the category the category for my sound instances?

EDIT

I need a reference to AVAudioPlayer while the app is running as i'm switching views a lot and the AVAudioPlayer are initialized one gridView. Structure is:

gridView -> detailView -> soundButton

Buttons send a notification to gridView where the AVAudioPlayer is instatiated. When i come back to the detailView i have to show if a sound is still playing and the playingTime must be shown on a progressBar. I had that all using a NSMutableDisctionary but now switching to a core data model cause i have to prefill the data base with default sound sets.

And therefore i thought its the best way to plase the reference to the AVAudioPlayer in the sound records. Because need the reference of the audioPlayer when i come back to the detailView. I have to know if it is still playing and the playingTime.

How would you solve that?

rockstarberlin
  • 1,853
  • 1
  • 18
  • 31

1 Answers1

1

AVAudioPlayer should not be added to a persistant store in core-data since it does not conform to the NSCoding protocol.

What I would do is remove the AVAudioPlayer from your model but keep it in your NSManagedObject. Then in the implementation switch @dynamic to @synthesized for the audioPlayer. (Add a line too to release the audio player on dealloc).

Then do something like this

-(AVAudioPlayer*)audioPlayer {
if (self.audioPlayer) return audioPlayer;
else {
NSError * error = nil;
AVAudioPlayer * lAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.fileURL error:&error];

if (!error) {
self.audioPlayer = lAudioPlayer;
[lAudioPlayer release];
} else {
[lAudioPlayer release];
NSLog(@"%@",error);
}

}

}

I would also recommend to something similar with isLooping and duration and have them come off the audioPlayer directly and not store them in your persistant store unless you need them to persist.

EDIT

Sounds like your problem is that you are referencing the avaudioplayer in your object (for persistance sake) then saving the context then later when you come back you are rerequesting the object from the persistant store, this will not work since your persistant store can not handle avaudioplayer. There are multiple ways to solve this problem.

The first is to store all your avaudioplayers in a nsmutabledictionary (i would make it static or in a singleton). This nsmutabledictionary would be keyed by a unique identifier. You can either create a unique identifier and store it in your persistent store (with a new attribute on your object) or just use the objectid of the sound object (I believe). At that point do what I said before about making the audioPlayer in your managed object class but instead of creating it there just get it back from the nsmutabledictionary with the unique identifier that was made, if there is none that means you need to make a new audio player and add it to the nsmutabledictionary.

I hope I am understanding your problem, I think this is the easiest solution and also the most elegant. The other one that is also really easy is that you keep in memory all the sound managed objects that are playing, like that you won't need to rerequest them from the persistant store and therefor your audioplayer will still be accessible.

There are really a thousand ways to do this, I am just giving you the 2 I would use, and don't forget to release your audioplayers and remove them from the mutable dictionary when you are done with them.

thewormsterror
  • 1,608
  • 14
  • 27
  • isLooping and duration comes from an remote json file and i need that before i start the audioPlayer. hm, what i don't understand is why should i keep the AVAudioPlayer in my manged object if there is no attribute in the entity? – rockstarberlin Nov 08 '12 at 04:01
  • oh ok for isLooping and duration. – thewormsterror Nov 08 '12 at 07:57
  • The reason for keeping AVAudioPlayer in the managed object is just for convenience, you wanted to do self.sound.audioPlayer.playing, this would allow it without pushing it to the persistant store (which it is not allowed) since it does not conform to NSCoding. – thewormsterror Nov 08 '12 at 07:59
  • It also is better on memory and in coding style, you basically are saying that a sound has a AVAudioPlayer, and that the AVAudioPlayer is lazily created when needed. It will stay on the sound until the sound is deallocated (aka you no longer need it) – thewormsterror Nov 08 '12 at 08:01
  • I just did it like i´ve described it. Storing AVAudioReference in my model and it works. But the question now is rather how to keep the AVAudioPlayer property in the managed object model subclass when i recreate the subclasses. Thanks anyway. – rockstarberlin Nov 12 '12 at 17:28
  • thewormsterror: I just had to change my code. It worked until i stored new records to the database. I did what you suggested, only changed removed the attribute in the mode, changed dynamic to property in my managed object subclass and it worked instantly with no further changes. Thanks again! – rockstarberlin Nov 14 '12 at 15:41