NSNotificationCenter 通知在滑动时触发了两次

Posted

技术标签:

【中文标题】NSNotificationCenter 通知在滑动时触发了两次【英文标题】:NSNotificationCenter notification fired twice on swipe 【发布时间】:2015-01-28 11:30:47 【问题描述】:

我正在使用 AVPlayer 构建一个应用程序,它将播放来自 api 的歌曲。

当一首歌曲结束时,将播放下一首歌曲。为此,我使用以下代码:

- (void)viewDidLoad

[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(playbackFinished:)
                                                 name:AVPlayerItemDidPlayToEndTimeNotification
                                               object:[_audioPlayer currentItem]];


-(void)playbackFinished:(NSNotification *)notification 
//    flagSkip = NO;
    NSLog(@"## %@ ", NSStringFromSelector(_cmd));
//    if(flagSkip == NO)
        [[DataSingleton sharedMySingleton] nextTrack];
//    else
//        flagSkip = NO;

在滑动手势时,将播放下一首歌曲。 为此,我将删除通知观察者并再次添加,如下所示:

- (IBAction)skipButtonPressed:(id)sender


        [[DataSingleton sharedMySingleton] nextTrack];
            [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:[_audioPlayer currentItem]];
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(playbackFinished:)
                                                     name:AVPlayerItemDidPlayToEndTimeNotification
                                                   object:[_audioPlayer currentItem]];

    else
        //
    

但是当我滑动时,有时会调用通知方法。

我哪里错了?我该如何解决?

编辑以包含 [[DataSingleton sharedMySingleton] nextTrack]

    -(void)nextTrack
    NSDictionary *prevTrackInfo; 
    if (currentIndex == -1)
        // We're at the start of a refilled list, so previousTrack should be 
        // the only thing in the cache dir. Clean it up.
        dispatch_queue_t removeFilesQueue;
        NSLog(@"## %@ removeFilesQueue", NSStringFromSelector(_cmd));

        removeFilesQueue = dispatch_queue_create("com.zombieprocess.removeFilesQueue", DISPATCH_QUEUE_SERIAL);

        dispatch_sync(removeFilesQueue, ^
            // Code goes here
            NSError *error = nil;
            [fileMgr removeItemAtPath:[self getFeedBandsCacheDir] error:&error];
            [fileMgr createDirectoryAtPath:[self getFeedBandsCacheDir] withIntermediateDirectories:YES attributes:nil error:nil];
        );

        //dispatch_release(removeFilesQueue);

     else
        if (trackInfo)
            prevTrackInfo = trackInfo;
        else
            NSLog(@"nextTrack, attempting to store prevTrackInfo, no trackInfo for currentIndex: %d", currentIndex);
        
    

    currentIndex += 1;

    // We should not have this, but just in case
    if (currentIndex >= self.feedEntries.count) 
        // We are at the end. Get the feed again.
        NSLog(@"## %@ currentIndex >= self.feedEntries.count", NSStringFromSelector(_cmd));
        if (self.feedEntries.count == 0) 
            [self loadFeed];
            return;
        
        currentIndex = 0; // This will loop it back to the beginning
//        [self loadFeed];
//        return;
    

    trackInfo = [self.feedEntries objectAtIndex:currentIndex];

    [self dispatchPlayNotification];

    if (prevTrackInfo && [self isTrackCached:prevTrackInfo] && prevTrackInfo != trackInfo && feedEntries.count > [self numberOfSongsToCache])
        NSLog(@"nextTrack, deleting cached copy: %@", [[prevTrackInfo objectForKey:@"file_url"] lastPathComponent]);
        [self deleteCachedTrack:prevTrackInfo completionBlock:^
            [self fillDownloadQueue];
        ];
     else 
        [self fillDownloadQueue];
    


【问题讨论】:

【参考方案1】:

我猜你已经切换下一首歌曲了。所以你不能用[_audioPlayer currentItem]删除通知观察者,因为它已经被改变了。

更新 1。

尝试替换第一行和第二行:

[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:[_audioPlayer currentItem]];
[[DataSingleton sharedMySingleton] nextTrack];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:[_audioPlayer currentItem]];

【讨论】:

做了,还是一样 所以发这个方法:[[DataSingleton sharedMySingleton] nextTrack];. 编辑了方法以包含相同的内容。请检查。【参考方案2】:

我不会删除通知侦听器,而是在方法(void)playbackFinished:(NSNotification *)notification 中读取播放器的当前状态。 例如:

- (IBAction)skipButtonPressed:(id)sender

      didSkipSong = YES;
      [[DataSingleton sharedMySingleton] nextTrack];


-(void)playbackFinished:(NSNotification *)notification

-(void)playbackFinished:(NSNotification *)notification 
  if(didSkipSong)
      didSkipSong = NO;
      return;
  
  [[DataSingleton sharedMySingleton] nextTrack];

【讨论】:

对不起,伙计,您的解决方案不能解决问题,它只是隐藏了一段时间。 为什么说它不能解决问题?我认为删除通知是一种不好的做法

以上是关于NSNotificationCenter 通知在滑动时触发了两次的主要内容,如果未能解决你的问题,请参考以下文章

通知中心 - NSNotificationCenter

选择器没有收到来自 NSNotificationCenter (iOS) 的通知

iOS NSNotificationCenter 移除通知带来的crash

NSNotificationCenter 观察者没有收到通知

如何在 QT 应用程序中处理来自 NSNotificationCenter 的通知?

NSNotificationCenter 通知在滑动时触发了两次