viewDidLoad 中异步加载声音资源崩溃

发布于 2025-01-06 14:59:26 字数 4602 浏览 4 评论 0原文

所有,

我试图在加载 UIViewController 时异步加载一组声音。大约在同一时间,我(偶尔)还会将 UIView 放置在 ViewController 层次结构的顶部以显示帮助叠加层。当我这样做时,应用程序会因执行错误而崩溃。如果未添加视图,应用程序不会崩溃。我的 ViewController 看起来像这样:

- (void)viewDidLoad
{
    [super viewDidLoad];

    __soundHelper = [[SoundHelper alloc] initWithSounds];

    // Other stuff
}

- (void)viewDidAppear:(BOOL)animated
    {
    // ****** Set up the Help Screen
    self.coachMarkView = [[FHSCoachMarkView alloc] initWithImageName:@"help_GradingVC" 
                                                    coveringView:self.view 
                                                     withOpacity:0.9 
                                                    dismissOnTap:YES 
                                                    withDelegate:self];

    [self.coachMarkView showCoachMarkView];
    [super viewDidAppear:animated];
}

SoundHelper 的主要异步加载方法(从“initWithSounds”调用)看起来像这样:

// Helper method that loads sounds as needed
- (void)loadSounds {

    // Run this loading code in a separate thread
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
    NSBlockOperation *loadSoundsOp = [NSBlockOperation blockOperationWithBlock:^{
        // Find all sound files (*.caf) in resource bundles
        __soundCache = [[NSMutableDictionary alloc]initWithCapacity:0];

        NSString * sndFileName;
        NSArray *soundFiles = [[NSBundle mainBundle] pathsForResourcesOfType:STR_SOUND_EXT inDirectory:nil];

        // Loop through all of the sounds found
        for (NSString * soundFileNamePath in soundFiles) {
            // Add the sound file to the dictionary
            sndFileName = [[soundFileNamePath lastPathComponent] lowercaseString];
            [__soundCache setObject:[self soundPath:soundFileNamePath] forKey:sndFileName];
        }

        // From: https://stackoverflow.com/questions/7334647/nsoperationqueue-and-uitableview-release-is-crashing-my-app
        [self performSelectorOnMainThread:@selector(description) withObject:nil waitUntilDone:NO];
    }];
    [operationQueue addOperation:loadSoundsOp];
}

崩溃似乎发生在块退出时。 FHSCoachMarkViewinit 看起来像这样:

- (FHSCoachMarkView *)initWithImageName:(NSString *) imageName 
                           coveringView:(UIView *) view
                            withOpacity:(CGFloat) opacity
                           dismissOnTap:(BOOL) dismissOnTap
                           withDelegate:(id<FHSCoachMarkViewDelegate>) delegateID
{
    // Reset Viewed Coach Marks if User Setting is set to show them
    [self resetSettings];

    __coveringView = view;        
    self = [super initWithFrame:__coveringView.frame];
    if (self) {
        // Record the string for later reference
        __coachMarkName = [NSString stringWithString:imageName];
        self.delegate = delegateID;

        UIImage * image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:imageName ofType:@"png"]];

        // ****** Configure the View Hierarchy
        UIImageView *imgView = [[UIImageView alloc] initWithImage:image];

        [self addSubview:imgView];
        [__coveringView.superview insertSubview:self aboveSubview:__coveringView];

        // ****** Configure the View Hierarchy with the proper opacity
        __coachMarkViewOpacity = opacity;
        self.hidden = YES;
        self.opaque = NO;
        self.alpha = __coachMarkViewOpacity;

        imgView.hidden = NO;
        imgView.opaque = NO;
        imgView.alpha = __coachMarkViewOpacity;

        // ****** Configure whether the coachMark can be dismissed when it's body is tapped
        __dismissOnTap = dismissOnTap;

        // If it is dismissable, set up a gesture recognizer
        if (__dismissOnTap) {
            UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self 
                                                                                      action:@selector(coachMarkWasTapped:)];
            [self addGestureRecognizer:tapGesture];
        }
    }
    return self;
}

我尝试使用 NSBlockOperationdispatch_async 以及两者来调用异步块也得到了同样的结果。此外,我完全删除了 aysnch 调用并将声音加载到主线程上。效果很好。我还尝试了@Jason建议的解决方案: NSOperationQueue 和 UITableView 版本是使我的应用程序崩溃,但同样的事情也发生在那里。

这实际上是 FHSCoachMarkView 中添加的视图的问题,还是可能与两者访问 mainBundle 的事实有关?我对 iOS 中的异步编码有点陌生,所以我有点不知所措。任何帮助将不胜感激!

谢谢, 斯科特

All,

I am attempting to load a set of sounds asynchronously when I load a UIViewController. At about the same time, I am (occasionally) also placing a UIView on the top of my ViewController's hierarchy to present a help overlay. When I do this, the app crashes with a bad exec. If the view is not added, the app does not crash. My ViewController looks something like this:

- (void)viewDidLoad
{
    [super viewDidLoad];

    __soundHelper = [[SoundHelper alloc] initWithSounds];

    // Other stuff
}

- (void)viewDidAppear:(BOOL)animated
    {
    // ****** Set up the Help Screen
    self.coachMarkView = [[FHSCoachMarkView alloc] initWithImageName:@"help_GradingVC" 
                                                    coveringView:self.view 
                                                     withOpacity:0.9 
                                                    dismissOnTap:YES 
                                                    withDelegate:self];

    [self.coachMarkView showCoachMarkView];
    [super viewDidAppear:animated];
}

The main asynchronous loading method of SoundHelper (called from 'initWithSounds') looks like this:

// Helper method that loads sounds as needed
- (void)loadSounds {

    // Run this loading code in a separate thread
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
    NSBlockOperation *loadSoundsOp = [NSBlockOperation blockOperationWithBlock:^{
        // Find all sound files (*.caf) in resource bundles
        __soundCache = [[NSMutableDictionary alloc]initWithCapacity:0];

        NSString * sndFileName;
        NSArray *soundFiles = [[NSBundle mainBundle] pathsForResourcesOfType:STR_SOUND_EXT inDirectory:nil];

        // Loop through all of the sounds found
        for (NSString * soundFileNamePath in soundFiles) {
            // Add the sound file to the dictionary
            sndFileName = [[soundFileNamePath lastPathComponent] lowercaseString];
            [__soundCache setObject:[self soundPath:soundFileNamePath] forKey:sndFileName];
        }

        // From: https://stackoverflow.com/questions/7334647/nsoperationqueue-and-uitableview-release-is-crashing-my-app
        [self performSelectorOnMainThread:@selector(description) withObject:nil waitUntilDone:NO];
    }];
    [operationQueue addOperation:loadSoundsOp];
}

The crash seems to occur when the block exits. The init of FHSCoachMarkView looks like this:

- (FHSCoachMarkView *)initWithImageName:(NSString *) imageName 
                           coveringView:(UIView *) view
                            withOpacity:(CGFloat) opacity
                           dismissOnTap:(BOOL) dismissOnTap
                           withDelegate:(id<FHSCoachMarkViewDelegate>) delegateID
{
    // Reset Viewed Coach Marks if User Setting is set to show them
    [self resetSettings];

    __coveringView = view;        
    self = [super initWithFrame:__coveringView.frame];
    if (self) {
        // Record the string for later reference
        __coachMarkName = [NSString stringWithString:imageName];
        self.delegate = delegateID;

        UIImage * image = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:imageName ofType:@"png"]];

        // ****** Configure the View Hierarchy
        UIImageView *imgView = [[UIImageView alloc] initWithImage:image];

        [self addSubview:imgView];
        [__coveringView.superview insertSubview:self aboveSubview:__coveringView];

        // ****** Configure the View Hierarchy with the proper opacity
        __coachMarkViewOpacity = opacity;
        self.hidden = YES;
        self.opaque = NO;
        self.alpha = __coachMarkViewOpacity;

        imgView.hidden = NO;
        imgView.opaque = NO;
        imgView.alpha = __coachMarkViewOpacity;

        // ****** Configure whether the coachMark can be dismissed when it's body is tapped
        __dismissOnTap = dismissOnTap;

        // If it is dismissable, set up a gesture recognizer
        if (__dismissOnTap) {
            UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self 
                                                                                      action:@selector(coachMarkWasTapped:)];
            [self addGestureRecognizer:tapGesture];
        }
    }
    return self;
}

I have tried invoking the asynchronous block using both NSBlockOperation and dispatch_async and both have had the same results. Additionally, I've removed the aysnch call altogether and loaded the sounds on the main thread. That works fine. I also tried the solution suggested by @Jason in: NSOperationQueue and UITableView release is crashing my app but the same thing happened there too.

Is this actually an issue with the view being added in FHSCoachMarkView, or is it possibly related to the fact that both access mainBundle? I'm a bit new to asynch coding in iOS, so I'm at a bit of a loss. Any help would be appreciated!

Thanks,
Scott

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

软糖 2025-01-13 14:59:26

我发现了这一点:我在 SoundHelper 对象 (NSUserDefaultsDidChangeNotification) 上设置了一个监听器,用于监听 NSUserDefaults 何时更改,并在用户默认指示时加载声音。 FHSCoachMarkView 还对 NSUserDefaults 进行了更改。在 SoundHelper 中,我没有正确检查哪些默认值正在更改,因此每次进行更改时都会调用异步声音加载方法。因此多个线程试图修改 __soundCache 实例变量。它似乎不喜欢那样。

问题:这是回答您自己的问题的正确方法吗?或者我应该只对问题本身添加评论?

谢谢。

I figured this out: I had set up a listener on the SoundHelper object (NSUserDefaultsDidChangeNotification) that listened for when NSUserDefaults were changed, and loaded the sounds if the user defaults indicated so. The FHSCoachMarkView was also making changes to NSUserDefaults. In the SoundHelper, I was not properly checking which defaults were being changed, so the asynch sound loading method was being called each time a change was made. So multiple threads were attempting to modify the __soundCache instance variable. it didn't seem to like that.

Question: Is this the correct way to answer your own question? Or should I have just added a comment to the question it self?

Thanks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文