2016-12-22 5 views
-2

Я пытаюсь улучшить проект GitHub, который я разветвил (https://github.com/giacmarangoni/Swift-Radio-Pro/tree/xcode8). После некоторых исправлений и изменений все, кажется, работает хорошо, но вдруг я заметил действительно странное поведение. Когда я открываю «NowPlayingViewController» в первый раз, и станция начинает поток, все работает, и делегат AVPlayer обновляет пользовательский интерфейс, как ожидалось (songLabel, titleLabel и albumArtwork). После этого, не останавливая передачу радио, я попытался вернуться к «StationsViewController» и сразу же открыть «NowPlayingViewController», используя кнопку «Now playing».
На данный момент делегирование по-прежнему активно, потоковая передача продолжается, но когда песня меняет все переменные в этом представлении, контроллер обновляется, но я не могу сказать то же самое для пользовательского интерфейса. Я попытался отладить, и я заметил, что метки заполнены, но не обновлены. Обновления пользовательского интерфейса в основном потоке и setNeedDisplay не помогли.
Ярлык не обновляется с помощью Swift

NowPlayingViewController

установки AVPlayer:

func setUpPlayer(){ 
     radioPlayer = Player.radio 
     radioPlayer.rate = 1 
     NotificationCenter.default.addObserver(
      self, 
      selector: #selector(self.playerItemDidReachEnd), 
      name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, 
      object: self.radioPlayer.currentItem 
     ) 

    } 

Здесь вы можете найти func onMetaData(_ metaData: [AVMetadataItem]?)).

//***************************************************************** 
// MARK: - AVPlayerItem Delegate (for metadata) 
//***************************************************************** 
extension NowPlayingViewController: CustomAVPlayerItemDelegate { 
    func onMetaData(_ metaData: [AVMetadataItem]?) { 
     if let metaDatas = metaData{ 
      startNowPlayingAnimation() 
      let firstMeta: AVMetadataItem = metaDatas.first! 
      let metaData = firstMeta.value as! String 
      var stringParts = [String]() 
      if metaData.range(of: " - ") != nil { 
       stringParts = metaData.components(separatedBy: " - ") 
      } else { 
       stringParts = metaData.components(separatedBy: "-") 
      } 
      // Set artist & songvariables 
      let currentSongName = track.title 
      track.artist = stringParts[0].decodeAllChars() 
      track.title = stringParts[0].decodeAllChars() 
      if stringParts.count > 1 { 
       track.title = stringParts[1].decodeAllChars() 
      }     
      if track.artist == "" && track.title == "" { 
       track.artist = currentStation.stationDesc 
       track.title = currentStation.stationName 
      } 

      DispatchQueue.main.async { 
       if currentSongName != self.track.title { 
        if kDebugLog { 
         print("METADATA artist: \(self.track.artist) | title: \(self.track.title)") 
        } 

        // Update Labels 
        self.artistLabel.text = self.track.artist 
        self.songLabel.text = self.track.title 
        self.updateUserActivityState(self.userActivity!) 
        // songLabel animation 
        self.songLabel.animation = "zoomIn" 
        self.songLabel.duration = 1.5 
        self.songLabel.damping = 1 
        self.songLabel.animate() 
        // Update Stations Screen 
        self.delegate?.songMetaDataDidUpdate(self.track) 
        // Query API for album art 
        self.resetAlbumArtwork() 
        self.queryAlbumArt() 
       } 
      } 
     } 
    } 
} 

Этот метод наблюдается в "CustomAVPlayerItem" в соответствии с timedMetaData ключевого пути; Это срабатывает при каждом изменении метаданных AVPlayer. Этот класс является подклассом AVPlayerItem:

import MediaPlayer 
import Foundation 

protocol CustomAVPlayerItemDelegate { 
    func onMetaData(_ metaData:[AVMetadataItem]?) 
} 

//***************************************************************** 
// Makes sure that observers are removed before deallocation 
//***************************************************************** 
class CustomAVPlayerItem: AVPlayerItem { 

    var delegate : CustomAVPlayerItemDelegate? 

    init(url URL:URL) 
    { 
     if kDebugLog {print("CustomAVPlayerItem.init")} 
     super.init(asset: AVAsset(url: URL) , automaticallyLoadedAssetKeys:[]) 
     addObserver(self, forKeyPath: "timedMetadata", options: NSKeyValueObservingOptions.new, context: nil) 
    } 

    deinit{   
     if kDebugLog {print("CustomAVPlayerItem.deinit")} 
     removeObserver(self, forKeyPath: "timedMetadata") 
    } 

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 
     if let avpItem: AVPlayerItem = object as? AVPlayerItem { 
      if keyPath == "timedMetadata" {     
       delegate?.onMetaData(avpItem.timedMetadata) 
      } 
     } 
    } 
} 

Следующая моя AVPlayer:

import MediaPlayer 

//***************************************************************** 
// This is a singleton struct using Swift 
//***************************************************************** 
struct Player { 
    static var radio = AVPlayer() 
} 

Это функция Segue я использую, чтобы открыть для "NowPlayingViewController".
StationsViewController

override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 
     if segue.identifier == "NowPlaying" { 

      self.title = "" 
      firstTime = false 

      let nowPlayingVC = segue.destination as! NowPlayingViewController 
      nowPlayingVC.delegate = self 

      if let indexPath = (sender as? IndexPath) { 
       // User clicked on row, load/reset station 
       if searchController.isActive { 
        currentStation = searchedStations[indexPath.row] 
       } else { 
        currentStation = stations[indexPath.row] 
       } 
       nowPlayingVC.currentStation = currentStation 
       nowPlayingVC.newStation = true 

      } else { 
       // User clicked on a now playing button 
       if let currentTrack = currentTrack { 
        // Return to NowPlaying controller without reloading station 
        nowPlayingVC.track = currentTrack 
        nowPlayingVC.currentStation = currentStation 
        nowPlayingVC.newStation = false 
       } else { 
        // Issue with track, reload station 
        nowPlayingVC.currentStation = currentStation 
        nowPlayingVC.newStation = true 
       } 
      } 
     } 
    } 
+0

Я не вижу кода, который когда-либо называет 'onMetaData'. – matt

+0

Я обновил свой вопрос. –

+0

Почему вы разместили здесь столько кода, если речь идет только о 'onMetaData'? – matt

ответ

1

Вот что я думаю, что вы не понимая, и то, что происходит на самом деле.

Обычно, когда вы «возвращаетесь» с контроллера толкаемого вида, выталкивается контроллер толкаемого вида и уничтожается. Ваш толкаемый контроллер представлений - это элемент управления NowPlayingViewController. Это должно быть уничтожено, когда вы «возвращаетесь» от него к StationsViewController. Таким образом, когда вы снова показываете NowPlayingViewController , вам нужно будет создать новый новый, отличный NowPlayingViewController.

Хорошо, так хорошо, если вы понимаете все это. Но в ваш случай есть еще одно осложнение: у вас есть утечка! Ваш старый контроллер NowPlayingView - не уничтожается. Таким образом, когда вы «возвращаетесь» в StationsViewController и снова показываете «NowPlayingViewController», теперь есть два NowPlayingViewControllers - новый, который вы видите, и старый, который протекает.

Хорошо, так что ваш каротаж продолжает показывать старый NowPlayingViewController, который до сих пор наблюдения и обновления.Но ваши глаза видят новый NowPlayingViewController, который ничего не делает. И это объясняет описанные вами явления.

Если это правильно - и, из того, что вы сказали, я уверен, что это так - тогда вам нужно реорганизовать свою архитектуру либо так, чтобы вы не получили эту утечку, либо когда вы показываете NowPlayingViewController во второй раз вы показываете тот же NowPlayingViewController, а не создаете другой. (Первый подход был бы лучше.)

+0

Привет матовый, я действительно хочу поблагодарить вас за ваш ответ! Я понимаю, что вы сказали. Я попытался отлаживать иерархию представлений приложений в симуляторе и кажется, что NowPlayingViewController правильно уничтожен. Вот некоторые изображения: при открытии (https://www.dropbox.com/s/xam343xrt3abbwk/1st_time.png?dl=0) после возвращения и возвращения (https://www.dropbox.com/s/5y9byuw9zujhide/ 2nd_time.png? дл = 0). –

Смежные вопросы