views:

41

answers:

3

iPhone/Mac "play a sound class": link text

I find an awful lot of great objective-c classes and code samples here... and elsewhere.

I successfully create the .h and .m files, but how do I call them from my existing code?

  • Where do I put the @class or #import statements?
  • How do I call the methods?
  • What if I need to play 2-3 different sounds files?
  • Why include the code... without any info about how to ever use it anywhere?
A: 

Wherever you want to call a method from one of the classes, put #import "SomeClass.h" at the top of the .h file.

Then you can do [SomeClass someMethod] or SomeClass *object = [[SomeClass alloc] init], or whatever you want to do.

This is pretty basic, you should read through The Objective-C Programming Language Guide

Kurbz
I've read that... and many others... several times. No place do I find it all just "spelled out clearly". Maybe because there are so many different ways to do it... and no 1 way is "correct".So I don't have to use @class ever?
Annette
I managed to get things to compile without any errors... and it seems to work... (So I know I'm 99% sucessful)... but "build and analyze" seems to alway report a memory leak on this line: aSound = [[Sound alloc] initWithPath:@"pathtoSound"];
Annette
@class vs. #import: http://stackoverflow.com/questions/322597/objective-c-class-vs-import
Kurbz
Regarding the memory leak, you have to release the object once you're done with it.
Kurbz
It is released in my file.m dealloc with: [mySound release]; (But "build and analyze" reports a leak right when I alloc it anyway.) I've done a clean-all several times. And since I didn't really do anything wildly-tricky... I would think "build and analyze" would easy see my "dealloc/release".
Annette
For the method where you alloc the object, is it ever called more than once?
Kurbz
Well even if it isn't, it still has the possibility of being called more than once so that's probably why you're getting a leak. Can you post the code you have so far?
Kurbz
No one mentioned that. (Is there a way to learn the-exact-way-with-everything-mentioned-in-one-list?) What is a good way to ensure it's only called once? It reports a memory-leak with (or without) a line before my alloc, such as: if(mySound == nil) // Only alloc once, here
Annette
Well you should do something like this: - (void) someFunction() { aSound = [[Sound alloc] initWithPath:@"pathtoSound"]; //do something with the aSound; [aSound release];}
Kurbz
I need this sound only in 1 place... but I need to very often there. So I didn't want to alloc/release it many times. Or should I?
Annette
I didn't want to alloc in my app-delegate... since I only need to play this sound in 1 of my classes.
Annette
Every time you alloc, you need to release, it's perfectly fine to do that. No you don't need it in the delegate. If you only have one sound object, you could define it in the class and alloc it in the -init, then just release it in dealloc.
Kurbz
Is there a code-sample that shows actual code: "This is how you install this sound-class in your code" (It would be SO much easier than all this trial-and-error and guessing.)
Annette
It's only a short 0.5 second sound file. But it might get played over and over very quickly by the user (think of a fire-button in a game). I was trying to avoid loading it... alloc it... play it... free it.... 1000 times. Instead: load it ONCE. alloc it ONCE. Play it 1000 times. Then free it ONCE. Is that not a good plan?
Annette
A quick google turned up this... http://iphoneincubator.com/blog/tutorial/how-to-play-audio-with-the-iphone-sdk
Kurbz
This is actually exactly what you want: http://howtomakeiphoneapps.com/2009/08/how-to-play-a-short-sound-in-iphone-code/
Kurbz
I notice his example didn't alloc or free anything anywhere. How is that possible? (Why do I even struggle with memory-issues when you can also do it a totally-memory-alloc'less way???) Also... wouldn't it be VERY slow and inefficient the way he does it: Search the bundle 1000 times. Find the sound-file 1000 times. Load it into memory 1000 times. Create it 1000 times. Play it 1000 times.
Annette
Because he's using some framework, you had no choice but to alloc with the sample code you were using.
Kurbz
The iphoneincubator.com code always is now marked "outdated" by its author. (Not sure what that means... but I think I should avoid 'learning' from outdated examples.)
Annette
Let me ask this way: If you *HAD TO* put your sound-alloc line in your viewWillAppear or viewDidLoad methods... how would you do it? (The reasons I need it inside 1 of those 2 are too long to post here... but I will if you need to know them.) Where is the "put it here to ensure it only runs once" part of my code? But I thought that's what "if(mySound == nil)" would help ensure... no matter WHERE I put the code. It will always only alloc ONCE. No?
Annette
In the .h do Sound *mySound (With the Sound class #import'ed). Then in -viewDidLoad: mySound = [[Sound alloc] initWithPath:@"pathtoSound"]; and release it in -dealloc
Kurbz
Wow. That's how I did it... and I still get "fully working code" but "build and analyze" still reporting "possible leak". I tried it with (and with) @property/@synthesis statements. Same problem.
Annette
what line is leaking
Kurbz
Leaking: mySound = [[Sound alloc] initWithPath:@"pathtoSound"]; (The code compiles and runs fine... so I know "most" of it is working.) But somewhere I must have a VERY small error in my code. But where?
Annette
+1  A: 

Usually Annette, you can tell what needs to be done by looking at the objects superclass

in this case, if you look at the .h file you can see @interface Sound : NSObject

Sound is the name of this Class, NSObject is our superclass

the initWithPath method is returning itself and does a [super init] meaning that it calls the parents init method.

In order for you to call this methods theres one of two ways.

You can have a property that you manage lets say, in your delegate.

@class Sound;
@interface ScanViewController : UIViewController  {
    Sound *aSound;
}
@property (nonatomic, retain) Sound *aSound;

then somwhere in your delegate

- (void) someFunction() {
   aSound = [[Sound alloc] initWithPath:@"pathtoSound"];
}

If you didnt want it to be a property you can easily create a new Sound object anywhere in a .m file like so.

Sound *mySound = [[Sound alloc] initWithPath:@"pathtoSound"];

If you wanted multiple sounds, Store them in a Sound Array

P.S. dont forget to release these objects since you alloc'ed them.

Kyle Browning
So I don't have to import anything?
Annette
When should I use "self." instead: self.aSound = [[Sound alloc] initWithPath:@"pathtoSound"];
Annette
A: 

I can't 'edit' my main question. (it crashes IE7 and IE8)

I can't post as a comment. (it destroys all my formatted text.)

Annette