0

I'm making a subclass of UIView completely in code (no IB), let's call it ContentView. In this view I've already set up several players for sounds and video, as well as several imageViews (nothing special).

Next, I was planning to subclass ContentView several times in order to load different media for each view. All of these views would have the same view controller since the interface would be the same for all of them, only the content (sounds, video and images) would change.

So my approach to this problem was to declare several NSString *const in ContentView.h and specify their keys/values in the implementation file of each subclass view of ContentView, in the form of static NSString *const, since I would be reusing them to load different media for each view and did not want them in the global name space.

Here is some mockup code that illustrates what I'm talking about:

In ContentView.h

@interface ContentView : UIView {

NSString *const kSoundFile1;
NSString *const kSoundFile2;
NSString *const kSoundFileType;
NSString *const kMovieFile1;
NSString *const kMovieFile2;
NSString *const kMovieFileType;
NSString *const kImage1;
NSString *const kImage2;

and in ContentView.m, something of the sort,

@implementation ContentView 

- (id)initWithFrame:(CGRect)frame
{ 
   self = [super initWithFrame:frame];
       if (self) {

       NSString *filePath1 = [[NSBundle mainBundle] pathForResource: kSoundFile1 
                                                         ofType: kSoundFileType;

       NSURL *url1 = [[NSURL alloc] initFileURLWithPath:filePath1];

       AVAudioPlayer *audioPlayer1 = [AVAudioPlayer alloc] initWithContentsOfURL:url  error:nil];
       [audioPlayer1 prepareToPlay];
       [url1 release];

... and so on, for the rest of the sound files and movies (except for the images, for which i'm using imageNamed:).

Then on the implementation file of each subclass of ContentView I have just this:

@implementation ContentViewSubclass

static NSString *const kSoundFile1 = @"sound1";
static NSString *const kSoundFile2 = @"sound2";
static NSString *const kSoundFileType = @"wav";
static NSString *const kMovieFile1 = @"movie1";
static NSString *const kMovieFile2 = @"movie2";
static NSString *const kMovieFileType = @"mov";
static NSString *const kImage1 = @"image1.png";
static NSString *const kImage2 = @"image2.png";

@end

I can't make this work. There are no compiler errors or warnings, simply nothing plays or shows. Am I doing something wrong, or is this just not the right approach to the problem?

I would really appreciate some insights. Thanks in advance.

MiguelB
  • 1,913
  • 18
  • 20

3 Answers3

1

Although the answer below from @deanWombourne makes perfect sense, I had an issue with his solution. But I have found out what was wrong with it (at least this is my take on it and it's working now).

A UIView subclass already has its own designated initializer, which is -(id)initWithFrame, so calling -(id)init on any subsequent subclass of ContentView is not going to update any instance variables since [super init] directs to nowhere (or better, first the superclass runs initWithFrame and only then it runs init, which is the same as having done nothing).

So my solution is the following:

(after changing the ivars on ContentView.h to the form of NSString *pointer, for example, NSString *kSoundFile1),

@implementation ContentViewSubclass

- (id)initWithFrame:(CGRect)frame {

        kSoundFile1 = @"sound1";
        kSoundFile2 = @"sound2";
        kSoundFileType = @"wav";
        kMovieFile1 = @"movie1";
        kMovieFile2 = @"movie2";
        kMovieFileType = @"mov";
        kImage1 = @"image1.png";
        kImage2 = @"image2.png";

    self = [super initWithFrame:frame];
    if (self) {

    }
    return self;
}

@end

First update the strings on the designated initializer -(id)initWithFrame, and only then call super. It works just fine now.

My sincere thanks to @deanWombourne for the help given in solving this problem.

MiguelB
  • 1,913
  • 18
  • 20
0

EDIT: This answer is completely barking up the wrong tree. Try this one instead :)


I instantly look for this line :

AVAudioPlayer *audioPlayer1 = [AVAudioPlayer alloc] initWithContentsOfURL:url  error:nil];

The SDK wants to tell you the error but you ask it not to. Then you complain that there is no error!

Try this:

NSError *error = nil;
AVAudioPlayer *audioPlayer1 = [AVAudioPlayer alloc] initWithContentsOfURL:url  error:&error];
if (error) {
    NSLog(@"error : %@", error);
}

and let us know what you see.

Community
  • 1
  • 1
deanWombourne
  • 38,189
  • 13
  • 98
  • 110
  • I just put the player code up to illustrate how i was using the constants. I'm pretty sure the problem is with the declaration of static NSStrings constants outside the main uiview class. But I'll put the error message in. Just give me a few. – MiguelB Jun 14 '11 at 12:48
  • Ok, the error message is the following: error : Error Domain=NSOSStatusErrorDomain Code=1954115647 "The operation couldn’t be completed. (OSStatus error 1954115647.)" – MiguelB Jun 14 '11 at 12:53
  • Hmm, that's not very helpful! Though a quick Google for that error code did find this question (and answer!) http://stackoverflow.com/questions/4901709/iphone-avaudioplayer-unsupported-file-type – deanWombourne Jun 14 '11 at 13:04
  • I've had a re-read of your question - you might want to take a look at my other answer :) – deanWombourne Jun 14 '11 at 13:14
  • Well, the thing is that the player plays the sound just fine if I don't use constants to substitute for the keys. No error at all... And the problem isn't just the audio player, it's everything, movies and images alike. They don't load if I declare **static NSString *const** from the subclass. – MiguelB Jun 14 '11 at 13:14
  • hah, that's exactly what my other answer says :) This answer is probably worth deleting! – deanWombourne Jun 14 '11 at 13:16
  • Yeah, you can delete it. I'm still trying your new solution, seems just what I needed. I'll get back to you in a few. – MiguelB Jun 14 '11 at 13:24
0

I think I might have worked it out, ignore my other answer :)

You've set the strings up as members of ContentView (in ContentView.h). They start out initialised to nil.

Then, in each subclass you create new strings with the same name but only in that .m file (the static keyword does that!). Just beacuse they have the same name in the C code doesn't mean they're pointing to the same object :)

Your ContentView.m file can't see the new strings, it just uses the ones defined in your .h file, which have never been set to anything so I bet they're still nil!

You need to define the strings in your subclasses like this :

@implementation ContentViewSubclass

- (id)init {
    self = [super init];
    if (self) {
        kSoundFile1 = @"sound1";
        kSoundFile2 = @"sound2";
        kSoundFileType = @"wav";
        kMovieFile1 = @"movie1";
        kMovieFile2 = @"movie2";
        kMovieFileType = @"mov";
        kImage1 = @"image1.png";
        kImage2 = @"image2.png";
    }
    return self;
}

@end

PS The k in front of these names doesn't make much sense anymore - I'd get rid of it)

deanWombourne
  • 38,189
  • 13
  • 98
  • 110
  • dean, your answer makes perfect sense. But I think I'm still doing something wrong. Ok, so I changed my strings declarations in ContentView.h to `NSString *pointer;` (took off the `const` bit). Then I `init` with the values in the .m file of the subclass, just like you posted up above. And I get nothing. – MiguelB Jun 14 '11 at 13:53