【问题标题】:Loading different media files for each view subclass using NSString *const使用 NSString *const 为每个视图子类加载不同的媒体文件
【发布时间】:2011-09-14 15:16:42
【问题描述】:

我正在完全用代码(没有 IB)制作 UIView 的子类,我们称之为 ContentView。在这个视图中,我已经为声音和视频设置了几个播放器,以及几个 imageViews(没什么特别的)。

接下来,我计划将 ContentView 子类化几次,以便为每个视图加载不同的媒体。所有这些视图都将具有相同的视图控制器,因为它们的界面都是相同的,只有内容(声音、视频和图像)会发生变化。

所以我解决这个问题的方法是在 ContentView.h 中声明几个 NSString *const 并在 ContentView 的每个子类视图的实现文件中指定它们的键/值,以static NSString *const 的形式,因为我将重用它们来为每个视图加载不同的媒体,并且不希望它们在全局名称空间中。

这里有一些模型代码来说明我在说什么:

在 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;

在 ContentView.m 中,类似的东西,

@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];

...等等,对于其余的声音文件和电影(图像除外,我使用imageNamed:)。

然后在 ContentView 的每个子类的实现文件上我只有这个:

@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

我无法完成这项工作。没有编译器错误或警告,根本没有播放或显示。我做错了什么,还是这不是解决问题的正确方法?

我真的很感激一些见解。提前致谢。

【问题讨论】:

  • 您是否使用调试器单步执行代码以查看失败的原因?
  • 是的,我有。问题在于子类上的静态 NSString 常量声明。

标签: iphone objective-c xcode cocoa-touch nsstring


【解决方案1】:

虽然@deanWombourne 下面的回答非常有道理,但我对他的解决方案有疑问。但我发现了它的问题所在(至少这是我的看法,并且现在可以正常工作)。

UIView 子类已经有自己指定的初始化程序,即-(id)initWithFrame,因此在 ContentView 的任何后续子类上调用 -(id)init 不会更新任何实例变量,因为 [super init] 指示无处可去(或者更好的是,首先超类运行initWithFrame,然后才运行init,这与什么都不做一样)。

所以我的解决方案如下:

(将ContentView.h上的ivars改成NSString *pointer的形式后,例如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

首先更新指定初始化器-(id)initWithFrame上的字符串,然后才调用super。 现在可以正常使用了。

衷心感谢@deanWombourne 为解决这个问题提供的帮助。

【讨论】:

    【解决方案2】:

    我想我可能已经解决了,忽略我的其他答案:)

    您已将字符串设置为 ContentView 的成员(在 ContentView.h 中)。他们开始初始化为nil

    然后,在每个子类中创建 new 具有相同名称但仅在该 .m 文件中的字符串(静态关键字就是这样做的!)。仅仅因为它们在 C 代码中具有相同的名称并不意味着它们指向同一个对象:)

    您的 ContentView.m 文件看不到新字符串,它只使用在您的 .h 文件中定义的字符串,这些字符串从未设置为任何内容,所以我敢打赌它们仍然是 nil

    您需要像这样在子类中定义字符串:

    @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 这些名字前面的k 已经没有多大意义了——我会去掉它)

    【讨论】:

    • 院长,您的回答很有道理。但我认为我仍然做错了什么。好的,所以我将 ContentView.h 中的字符串声明更改为 NSString *pointer;(取消了 const 位)。然后我 init 使用子类的 .m 文件中的值,就像您在上面发布的一样。我什么也得不到。
    【解决方案3】:

    编辑:这个答案完全是错误的树。试试this one :)


    我立即寻找这条线:

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

    SDK想要告诉你错误,但你要求它不要。然后你抱怨没有错误!

    试试这个:

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

    让我们知道你看到了什么。

    【讨论】:

    • 我只是放了播放器代码来说明我是如何使用常量的。我很确定问题出在主 uiview 类之外的静态 NSStrings 常量的声明。但是我会把错误信息放进去。给我几个。
    • 好的,错误信息如下:error : Error Domain=NSOSStatusErrorDomain Code=1954115647 "操作无法完成。(OSStatus错误1954115647.)"
    • 嗯,这不是很有帮助!虽然该错误代码的快速谷歌确实找到了这个问题(并回答!)stackoverflow.com/questions/4901709/…
    • 我重读了你的问题 - 你可能想看看我的其他答案:)
    • 好吧,如果我不使用常量代替按键,播放器播放的声音就很好。完全没有错误...问题不仅在于音频播放器,还在于一切,包括电影和图像。如果我从子类声明 static NSString *const,它们不会加载。
    猜你喜欢
    • 2011-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-02
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    • 2018-09-06
    相关资源
    最近更新 更多