0

全て、

UIViewController をロードするときに、一連のサウンドを非同期的にロードしようとしています。ほぼ同時に、(時折) UIView を ViewController の階層の一番上に配置して、ヘルプ オーバーレイを表示しています。これを行うと、アプリが不適切な exec でクラッシュします。ビューが追加されていない場合、アプリはクラッシュしません。私の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];
}

ブロックが終了すると、クラッシュが発生するようです。のinitFHSCoachMarkView次のようになります。

- (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;
}

NSBlockOperationと の両方を使用して非同期ブロックを呼び出してみdispatch_asyncましたが、どちらも同じ結果になりました。さらに、aysnch 呼び出しを完全に削除し、サウンドをメイン スレッドにロードしました。それはうまくいきます。@Jason で提案されたソリューションも試しました: NSOperationQueue and UITableView release is crashing my appしかし、同じことがそこでも起こりました。

これは実際には FHSCoachMarkView に追加されているビューの問題ですか、それとも両方がアクセスするという事実に関連している可能性がありますmainBundleか? 私はiOSでの非同期コーディングに少し慣れていないので、少し途方に暮れています。どんな助けでも大歓迎です!

ありがとう、スコット

4

1 に答える 1

0

私はこれを理解しました: NSUserDefaults が変更されたときにリッスンするSoundHelperオブジェクト ( NSUserDefaultsDidChangeNotification) にリスナーを設定し、ユーザーのデフォルトがそう示している場合はサウンドをロードしました。FHSCoachMarkViewも に変更を加えていましたNSUserDefaults。では、SoundHelperどのデフォルトが変更されているかを適切にチェックしていなかったので、変更が行われるたびに非同期のサウンド ロード メソッドが呼び出されていました。そのため、複数のスレッドが__soundCacheインスタンス変数を変更しようとしていました。それが気に入らなかったようです。

質問: これはあなた自身の質問に答える正しい方法ですか? それとも、質問自体にコメントを追加する必要がありましたか?

ありがとう。

于 2012-02-20T02:16:55.223 に答える