我要做的是让我的JSON从不同的链接(4个不同的链接)加载,具体取决于我的应用程序中发生的事情。这是一个有4个不同电台的无线电网络应用程序。我可以将当前正在播放的电台推到我的JSON ViewController,但问题是我如何让JSON做“如果这个当前电台正在播放那么来自这个链接:LINK TO JSON INFO”?我知道这是可能的,但不知道如何实现它。这是我的JSON TableviewViewController的代码:
import UIKit
//----------
//MARK: JSON
//----------
//The Initial Response From The JSON
struct Response: Codable {
var playHistory: Album
}
//The Album Received Which Is An Array Of Song Data
struct Album: Codable {
var song: [SongData]
}
//The SongData From The PlayHistory Album
struct SongData: Codable{
var album: String
var artist: String
var cover: String
var duration: String
var programStartTS: String
var title: String
}
class TableViewController: UITableViewController {
//1. Create An Array To Store The SongData
var songs = [SongData]()
var currentStation: RadioStation!
var downloadTask: URLSessionDownloadTask?
override func viewDidLoad() { super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
//2. Load The JSON From The Main Bundle
guard let urlText = URL (string: currentStation.longDesc)
else { return }
do{
//a. Get The Data From The From The File
let data = try Data(contentsOf: urlText)
//b. Decode The Data To Our Structs
let albumData = try JSONDecoder().decode(Response.self, from: data)
//c. Append The Songs Array With The PlayHistory
albumData.playHistory.song.forEach { songs.append($0) }
//d. Test Some Data
print("""
**The First Album Details**
Album = \(songs[0].album)
Artist = \(songs[0].artist)
Cover = \(songs[0].cover)
Duration = \(songs[0].duration)
Start = \(songs[0].programStartTS)
Title = \(songs[0].title)
""")
//3. Load The Data
DispatchQueue.main.async {
self.tableView.reloadData()
}
}catch{
print(error)
}
}
//-----------------
//MARK: UITableView
//-----------------
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return songs.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//1. Create A Cell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
//2. Set It's Text
cell.songTitle.text = songs[indexPath.row].title
cell.artistLabel.text = songs[indexPath.row].artist
//3. Get The Image
if let imageURL = URL(string: songs[indexPath.row].cover){
let request = URLSession.shared.dataTask(with: imageURL) { (imageData, response, error) in
if let error = error{
print(error)
}else{
guard let image = imageData else { return }
DispatchQueue.main.async {
cell.songCover.image = UIImage(data: image)
cell.setNeedsLayout()
cell.layoutIfNeeded()
}
}
}
request.resume()
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("""
**Album \(indexPath.row) Selected**
Album = \(songs[indexPath.row].album)
Artist = \(songs[indexPath.row].artist)
Cover = \(songs[indexPath.row].cover)
Duration = \(songs[indexPath.row].duration)
Start = \(songs[indexPath.row].programStartTS)
Title = \(songs[indexPath.row].title)
""")
}
}
以下是我的“正在播放ViewController”中的代码:
import UIKit
import MediaPlayer
//*****************************************************************
// NowPlayingViewControllerDelegate
//*****************************************************************
protocol NowPlayingViewControllerDelegate: class {
func didPressPlayingButton()
func didPressStopButton()
func didPressNextButton()
func didPressPreviousButton()
}
//*****************************************************************
// NowPlayingViewController
//*****************************************************************
class NowPlayingViewController: UIViewController {
weak var delegate: NowPlayingViewControllerDelegate?
// MARK: - IB UI
@IBOutlet weak var albumHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var albumImageView: SpringImageView!
@IBOutlet weak var artistLabel: UILabel!
@IBOutlet weak var playingButton: UIButton!
@IBOutlet weak var songLabel: SpringLabel!
@IBOutlet weak var stationDescLabel: UILabel!
@IBOutlet weak var volumeParentView: UIView!
@IBOutlet weak var previousButton: UIButton!
@IBOutlet weak var nextButton: UIButton!
@IBOutlet weak var recentlyPlayed: UIButton!
// MARK: - Properties
var currentStation: RadioStation!
var currentTrack: Track!
var newStation = true
var nowPlayingImageView: UIImageView!
let radioPlayer = FRadioPlayer.shared
var mpVolumeSlider: UISlider?
//*****************************************************************
// MARK: - ViewDidLoad
//*****************************************************************
override func viewDidLoad() {
super.viewDidLoad()
// Create Now Playing BarItem
createNowPlayingAnimation()
// Set AlbumArtwork Constraints
optimizeForDeviceSize()
// Set View Title
self.title = currentStation.name
// Set UI
albumImageView.image = currentTrack.artworkImage
stationDescLabel.text = currentStation.desc
stationDescLabel.isHidden = currentTrack.artworkLoaded
// Check for station change
newStation ? stationDidChange() : playerStateDidChange(radioPlayer.state, animate: false)
// Setup volumeSlider
setupVolumeSlider()
// Hide / Show Next/Previous buttons
previousButton.isHidden = hideNextPreviousButtons
nextButton.isHidden = hideNextPreviousButtons
}
//*****************************************************************
// MARK: - Setup
//*****************************************************************
func setupVolumeSlider() {
// Note: This slider implementation uses a MPVolumeView
// The volume slider only works in devices, not the simulator.
for subview in MPVolumeView().subviews {
guard let volumeSlider = subview as? UISlider else { continue }
mpVolumeSlider = volumeSlider
}
guard let mpVolumeSlider = mpVolumeSlider else { return }
volumeParentView.addSubview(mpVolumeSlider)
mpVolumeSlider.translatesAutoresizingMaskIntoConstraints = false
mpVolumeSlider.leftAnchor.constraint(equalTo: volumeParentView.leftAnchor).isActive = true
mpVolumeSlider.rightAnchor.constraint(equalTo: volumeParentView.rightAnchor).isActive = true
mpVolumeSlider.centerYAnchor.constraint(equalTo: volumeParentView.centerYAnchor).isActive = true
mpVolumeSlider.setThumbImage(#imageLiteral(resourceName: "slider-ball"), for: .normal)
}
func stationDidChange() {
radioPlayer.radioURL = URL(string: currentStation.streamURL)
title = currentStation.name
}
//*****************************************************************
// MARK: - Player Controls (Play/Pause/Volume)
//*****************************************************************
// Actions
@IBAction func playingPressed(_ sender: Any) {
delegate?.didPressPlayingButton()
}
@IBAction func stopPressed(_ sender: Any) {
delegate?.didPressStopButton()
}
@IBAction func nextPressed(_ sender: Any) {
delegate?.didPressNextButton()
}
@IBAction func previousPressed(_ sender: Any) {
delegate?.didPressPreviousButton()
}
//*****************************************************************
// MARK: - Load station/track
//*****************************************************************
func load(station: RadioStation?, track: Track?, isNewStation: Bool = true) {
guard let station = station else { return }
currentStation = station
currentTrack = track
newStation = isNewStation
}
func updateTrackMetadata(with track: Track?) {
guard let track = track else { return }
currentTrack.artist = track.artist
currentTrack.title = track.title
updateLabels()
}
// Update track with new artwork
func updateTrackArtwork(with track: Track?) {
guard let track = track else { return }
// Update track struct
currentTrack.artworkImage = track.artworkImage
currentTrack.artworkLoaded = track.artworkLoaded
albumImageView.image = currentTrack.artworkImage
if track.artworkLoaded {
// Animate artwork
albumImageView.animation = "wobble"
albumImageView.duration = 3
albumImageView.animate()
stationDescLabel.isHidden = true
} else {
stationDescLabel.isHidden = false
}
// Force app to update display
view.setNeedsDisplay()
}
private func isPlayingDidChange(_ isPlaying: Bool) {
playingButton.isSelected = isPlaying
startNowPlayingAnimation(isPlaying)
}
func playbackStateDidChange(_ playbackState: FRadioPlaybackState, animate: Bool) {
let message: String?
switch playbackState {
case .paused:
message = "Station Paused..."
case .playing:
message = nil
case .stopped:
message = "Station Stopped..."
}
updateLabels(with: message, animate: animate)
isPlayingDidChange(radioPlayer.isPlaying)
}
func playerStateDidChange(_ state: FRadioPlayerState, animate: Bool) {
let message: String?
switch state {
case .loading:
message = "Loading Station ..."
case .urlNotSet:
message = "Station URL not valide"
case .readyToPlay, .loadingFinished:
playbackStateDidChange(radioPlayer.playbackState, animate: animate)
return
case .error:
message = "Error Playing"
}
updateLabels(with: message, animate: animate)
}
//*****************************************************************
// MARK: - UI Helper Methods
//*****************************************************************
func optimizeForDeviceSize() {
// Adjust album size to fit iPhone 4s, 6s & 6s+
let deviceHeight = self.view.bounds.height
if deviceHeight == 480 {
albumHeightConstraint.constant = 106
view.updateConstraints()
} else if deviceHeight == 667 {
albumHeightConstraint.constant = 230
view.updateConstraints()
} else if deviceHeight > 667 {
albumHeightConstraint.constant = 260
view.updateConstraints()
}
}
func updateLabels(with statusMessage: String? = nil, animate: Bool = true) {
guard let statusMessage = statusMessage else {
// Radio is (hopefully) streaming properly
songLabel.text = currentTrack.title
artistLabel.text = currentTrack.artist
shouldAnimateSongLabel(animate)
return
}
// There's a an interruption or pause in the audio queue
// Update UI only when it's not aleary updated
guard songLabel.text != statusMessage else { return }
songLabel.text = statusMessage
artistLabel.text = currentStation.name
if animate {
songLabel.animation = "flash"
songLabel.repeatCount = 3
songLabel.animate()
}
}
// Animations
func shouldAnimateSongLabel(_ animate: Bool) {
// Animate if the Track has album metadata
guard animate, currentTrack.title != currentStation.name else { return }
// songLabel animation
songLabel.animation = "zoomIn"
songLabel.duration = 1.5
songLabel.damping = 1
songLabel.animate()
}
func createNowPlayingAnimation() {
// Setup ImageView
nowPlayingImageView = UIImageView(image: UIImage(named: "NowPlayingBars-3"))
nowPlayingImageView.autoresizingMask = []
nowPlayingImageView.contentMode = UIViewContentMode.center
// Create Animation
// nowPlayingImageView.animationImages = AnimationFrames.createFrames()
// nowPlayingImageView.animationDuration = 0.7
// Create Top BarButton
let barButton = UIButton(type: .custom)
barButton.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
barButton.addSubview(nowPlayingImageView)
nowPlayingImageView.center = barButton.center
//let barItem = UIBarButtonItem(customView: barButton)
//self.navigationItem.rightBarButtonItem = barItem
}
func startNowPlayingAnimation(_ animate: Bool) {
animate ? nowPlayingImageView.startAnimating() : nowPlayingImageView.stopAnimating()
}
//*****************************************************************
// MARK: - Segue
//*****************************************************************
@IBAction func shareButtonPressed(_ sender: UIButton) {
let songToShare = "I'm listening to \(currentTrack.title) by: \(currentTrack.artist) on \(currentStation.name)"
let activityViewController = UIActivityViewController(activityItems: [songToShare, currentTrack.artworkImage!], applicationActivities: nil)
activityViewController.completionWithItemsHandler = {(activityType: UIActivityType?, completed:Bool, returnedItems:[Any]?, error: Error?) in
if completed {
// do something on completion if you want
}
}
present(activityViewController, animated: true, completion: nil)
}
}
答案 0 :(得分:1)
您需要将currentStation
传递给TableViewController
您声明故事板中有segue
,从NowPlayingViewController
到TableViewController
。
在这种情况下,您需要在prepare(for segue:sender:)
NowPlayingViewController
中执行以下操作:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? TableViewController {
vc.currentStation = currentStation
}
}
答案 1 :(得分:0)
对于不同的广播电台,您有不同的链接,然后创建一个var currentStationUrl
来存储该特定电台的链接,如果更新URL
,则调用您的API
以获取相应的更新数据到那个链接
var currentStationUrl: String!{
didSet{
loadData(urlString: self.currentStationUrl) { (album, status) in
if status == true{
// Do your stuff with response data here
print(album?.playHistory.song[0].title)
}else{
print("Can't get data from radio station")
}
}
}
}
在RadioStation更改时更新RadioStation
的链接。
var currentStation: RadioStation!{
didSet{
if self.currentStation == YOUR_RADIO_STATION_1{
self.currentStationUrl = "http://streamdb3web.securenetsystems.net/player_status_update/JACKSON1_history.txt"
}
else if self.currentStation == YOUR_RADIO_STATION_2{
self.currentStationUrl = LINK_FOR_RADIO_STATION_2
}
else if self.currentStation == YOUR_RADIO_STATION_3{
self.currentStationUrl = LINK_FOR_RADIO_STATION_3
}
else if self.currentStation ==YOUR_RADIO_STATION_4{
self.currentStationUrl = LINK_FOR_RADIO_STATION_4
}
}
}
最后&重要的任务是,为无线电台呼叫您的链接(API),以单独的方法进行,以便您可以重复使用它。
func loadData(urlString: String,completion: @escaping (Response?, Bool ) -> ()) {
guard let url = URL(string: urlString) else {
completion(nil, false)
return
}
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
completion(nil, false)
}
guard let data = data else {
completion(nil, false)
return }
do {
let albumData = try JSONDecoder().decode(Response.self, from: data)
completion(albumData, true)
} catch let jsonError {
completion(nil, false)
print(jsonError)
}
}.resume()
}
要从新工作站获取更新数据,只需更新currentStation
的值。
self.currentStation == YOUR_RADIO_STATION_1