저는 GitHub 프로젝트를 개선하기 위해 노력하고 있습니다 (https://github.com/giacmarangoni/Swift-Radio-Pro/tree/xcode8). 일부 수정 및 변경 작업이 모두 잘된 것 같지만 갑자기 정말 이상한 행동을 발견했습니다. "NowPlayingViewController"를 처음 열었을 때 방송국에서 스트리밍을 시작하면 모든 것이 작동하고 AVPlayer 대리인이 사용자 인터페이스를 예상대로 업데이트합니다 (songLabel, titleLabel 및 albumArtwork). 그런 다음 라디오 스트리밍을 중단하지 않고 "StationsViewController"로 돌아가서 "지금 재생 중"버튼을 사용하여 "NowPlayingViewController"를 다시 열려고했습니다.
위임은 여전히 활성화되어 있지만 스트리밍이 진행 중입니다.하지만 노래가 변경되면이보기 컨트롤러의 모든 변수가 업데이트되지만 사용자 인터페이스에 대해 동일한 내용을 말할 수는 없습니다. 디버깅을 시도하고 레이블이 채워지지만 업데이트되지 않은 것으로 나타났습니다. 메인 스레드의 UI 업데이트 및 setNeedDisplay
가 도움이되지 않았습니다.
스위프트를 사용하여 라벨이 업데이트되지 않습니다.
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()
}
}
}
}
}
이 방법은 timedMetaData
키 경로에 따라 "CustomAVPlayerItem"에서 관찰됩니다. AVPlayer 메타 데이터가 변경 될 때마다 해고됩니다.
import MediaPlayer
//*****************************************************************
// This is a singleton struct using Swift
//*****************************************************************
struct Player {
static var radio = AVPlayer()
}
이 내가 "NowPlayingViewController"을 열고 사용하는 SEGUE 기능입니다 :
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를하다 :이 클래스는 AVPlayerItem의 서브 클래스입니다.
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
}
}
}
}
'onMetaData'를 호출하는 코드가 없습니다. – matt
내 질문이 업데이트되었습니다. –
왜'onMetaData'만이 문제가된다면 많은 코드를 게시 했습니까? – matt