@Claude31 Should I add that kind of switch? If yes it is still showing only first VC:
switch annotation.title!! {
case "0-One":
annotationView.markerTintColor = UIColor.gray
annotationView.glyphImage = UIImage(named: "one")
case "1-Two":
annotationView.markerTintColor = UIColor.black
annotationView.glyphImage = UIImage(named: "white_flag")
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure2(button:)), for: .touchUpInside)// it should show the second VC but it still shows just this one
When I do this:
switch annotation.title {
case 0:
annotationView.markerTintColor = UIColor.gray
annotationView.glyphImage = UIImage(named: "kopula")
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure(button:)), for: .touchUpInside)
case 1:
annotationView.markerTintColor = UIColor.black
annotationView.glyphImage = UIImage(named: "white_flag")
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure2(button:)), for: .touchUpInside)
}
It shows me Expression pattern of type 'Int' cannot match values of type 'String??'
Post
Replies
Boosts
Views
Activity
@Claude31 I did sth like this and it changes the icon, but it does not change the VC:
switch annotation.title!! {
case "One":
annotationView.markerTintColor = UIColor.gray
annotationView.glyphImage = UIImage(named: "one")
case "Two":
annotationView.markerTintColor = UIColor.black
annotationView.glyphImage = UIImage(named: "two")
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure2(button:)), for: .touchUpInside)
What do you mean by setting a tag to each annotation? Is it impossible to do it this way like icon style? Thank you in advance for your help.
Ok, so I've added this and it works with objc function:
@objc func didClickDetailDisclosure(button: UIButton) {
guard let vc = storyboard?.instantiateViewController(withIdentifier: "second_vc") as? SecondController else {
return
}
present(vc, animated: true)
}
and this in my mapView func:
rightButton.addTarget(self, action: #selector(didClickDetailDisclosure(button:)), for: .touchUpInside)
But still I would like each annotation to open each VC. Thank you in advance for your help.
Here is the shorter version of my code (without API parsing):
import UIKit
import AVKit
import MediaPlayer
class ViewController: UIViewController, AVAudioPlayerDelegate {
@IBAction func buttonPressed(_ sender: UIButton){
if isPlaying {
player.pause()
sender.setImage(playImage, for: .normal)
} else {
let url = "https://myradio.com/radio.mp3"
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: [])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
player = AVPlayer(url: URL(string: url)!)
player.volume = 1.0
player.rate = 1.0
player.play()
sender.setImage(pauseImage, for: .normal)
}
isPlaying.toggle()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
overrideUserInterfaceStyle = .light
setupRemoteTransportControls()
requestNowPlaying()
setupNowPlaying()
}
// Here is the API data downloading part, so i skipped it
//Command Center audio controls
func setupRemoteTransportControls() {
// Get the shared MPRemoteCommandCenter
let commandCenter = MPRemoteCommandCenter.shared()
// Add handler for Play Command
commandCenter.playCommand.addTarget { [unowned self] event in
if self.player.rate == 1.0 {
self.player.play()
return .success
}
return .commandFailed
}
// Add handler for Pause Command
commandCenter.pauseCommand.addTarget { [unowned self] event in
if self.player.rate == 1.0 {
self.player.pause()
return .success
}
return .commandFailed
}
}
func setupNowPlaying() {
// Define Now Playing Info
var nowPlayingInfo = [String : Any]()
nowPlayingInfo[MPMediaItemPropertyTitle] = "Test"
if let image = UIImage(named: "Default_albumart") {
nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { size in
return image
}
}
nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = true
// Set the metadata
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}
func updateNowPlaying(isPause: Bool) {
// Define Now Playing Info
let nowPlayingInfo = MPNowPlayingInfoCenter.default().nowPlayingInfo!
//nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = player.currentTime
//nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = isPause ? 0 : 1
// Set the metadata
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}
//audio interruption
@objc func handleInterruption(notification: Notification) {
guard let userInfo = notification.userInfo,
let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
return
}
// Switch over the interruption type.
switch type {
case .began:
print("Interruption began")
case .ended:
// An interruption ended. Resume playback, if appropriate.
guard let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else { return }
let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
if options.contains(.shouldResume) {
player.play()
} else {
// An interruption ended. Don't resume playback.
}
default: ()
}
}
}
@OOPer here is the full code:
import UIKit
import AVKit
import MediaPlayer
class ViewController: UIViewController, AVAudioPlayerDelegate {
var player : AVPlayer!
var dict = NSDictionary()
var isPlaying = false
let playImage = UIImage(named: "play.png")
let pauseImage = UIImage(named: "pause.png")
@IBOutlet weak var artist: UILabel!
@IBOutlet weak var songtitle: UILabel!
@IBOutlet weak var artUrl: UIImageView!
@IBAction func buttonPressed(_ sender: UIButton){
if isPlaying {
player.pause()
sender.setImage(playImage, for: .normal)
} else {
let url = "https://admin.radiopromil.online/radio/8000/radio.mp3"
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: [])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
player = AVPlayer(url: URL(string: url)!)
player.volume = 1.0
player.rate = 1.0
player.play()
sender.setImage(pauseImage, for: .normal)
}
isPlaying.toggle()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
overrideUserInterfaceStyle = .light
setupRemoteCommandCenter()
//Radio API endpoint title and artist labels
let urlString = "https://admin.radiopromil.online/api/nowplaying/radio_promil"
let url = URL(string: urlString)!
let session = URLSession.shared
let dataTask = session.dataTask(with: url) { data, response, error in
if let error = error {
print(error)
return
}
guard let data = data else {
print("data is nil")
return
}
let decoder = JSONDecoder()
do {
let radio = try decoder.decode(RadioAPI.self, from: data)
print(radio)
DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
self.songtitle.text = radio.nowPlaying.song.title
self.artist.text = radio.nowPlaying.song.artist
//albumcover art section
if let artUrl = URL(string: radio.nowPlaying.song.art) {
//I need to load an image from `artUrl`
let imageDatatask = session.dataTask(with: artUrl) { imageData, imageResponse, imageError in
if let imageError = imageError {
print(imageError)
return
}
guard let imageData = imageData else {
print("image_data is nil")
return
}
//let albumArt = UIImage(data: imageData)
DispatchQueue.main.async {
let albumArt = UIImage(data: imageData)
let albumView = UIImageView(image: albumArt)
}
}
imageDatatask.resume()
}
})
}
catch {
print("Error Parsing JSON: \(error)")
}
}
dataTask.resume()
}
func setupRemoteCommandCenter() {
// Get the shared MPRemoteCommandCenter
MPNowPlayingInfoCenter.default().nowPlayingInfo = [MPMediaItemPropertyTitle: "Radio Promil"]
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.isEnabled = true
commandCenter.pauseCommand.isEnabled = true
commandCenter.playCommand.addTarget { [weak self] (event) -> MPRemoteCommandHandlerStatus in
self?.player.play()
return .success
}
commandCenter.pauseCommand.addTarget { [weak self] (event) -> MPRemoteCommandHandlerStatus in
self?.player.pause()
return .success
}
}
}
@OOPer here is the full code
import UIKit
import AVKit
import MediaPlayer
class ViewController: UIViewController, AVAudioPlayerDelegate {
var player : AVPlayer!
var dict = NSDictionary()
var isPlaying = false
let playImage = UIImage(named: "play.png")
let pauseImage = UIImage(named: "pause.png")
@IBOutlet weak var artist: UILabel!
@IBOutlet weak var songtitle: UILabel!
@IBOutlet weak var artUrl: UIImageView!
@IBAction func buttonPressed(_ sender: UIButton){
if isPlaying {
player.pause()
sender.setImage(playImage, for: .normal)
} else {
let url = "https://admin.radiopromil.online/radio/8000/radio.mp3"
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: [])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
player = AVPlayer(url: URL(string: url)!)
player.volume = 1.0
player.rate = 1.0
player.play()
sender.setImage(pauseImage, for: .normal)
}
isPlaying.toggle()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
overrideUserInterfaceStyle = .light
setupRemoteCommandCenter()
//Radio API endpoint title and artist labels
let urlString = "https://admin.radiopromil.online/api/nowplaying/radio_promil"
let url = URL(string: urlString)!
let session = URLSession.shared
let dataTask = session.dataTask(with: url) { data, response, error in
if let error = error {
print(error)
return
}
guard let data = data else {
print("data is nil")
return
}
let decoder = JSONDecoder()
do {
let radio = try decoder.decode(RadioAPI.self, from: data)
print(radio)
DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: {
self.songtitle.text = radio.nowPlaying.song.title
self.artist.text = radio.nowPlaying.song.artist
//albumcover art section
if let artUrl = URL(string: radio.nowPlaying.song.art) {
//I need to load an image from `artUrl`
let imageDatatask = session.dataTask(with: artUrl) { imageData, imageResponse, imageError in
if let imageError = imageError {
print(imageError)
return
}
guard let imageData = imageData else {
print("image_data is nil")
return
}
//let albumArt = UIImage(data: imageData)
DispatchQueue.main.async {
let albumArt = UIImage(data: imageData)
let albumView = UIImageView(image: albumArt)
}
}
imageDatatask.resume()
}
})
}
catch {
print("Error Parsing JSON: \(error)")
}
}
dataTask.resume()
}
func setupRemoteCommandCenter() {
// Get the shared MPRemoteCommandCenter
MPNowPlayingInfoCenter.default().nowPlayingInfo = [MPMediaItemPropertyTitle: "Radio Promil"]
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.isEnabled = true
commandCenter.pauseCommand.isEnabled = true
commandCenter.playCommand.addTarget { [weak self] (event) -> MPRemoteCommandHandlerStatus in
self?.player.play()
return .success
}
commandCenter.pauseCommand.addTarget { [weak self] (event) -> MPRemoteCommandHandlerStatus in
self?.player.pause()
return .success
}
}
}
@Claude31 thanks for the tip with the style. It is the radio stream. Now, I've got nowPlaying data only once when the app is starting. I would like to change it and fetch data when the next song is played. My API is here in static JSON: https://admin.radiopromil.online/api/nowplaying_static/radio_promil.json and here the general one: https://admin.radiopromil.online/api/nowplaying/radio_promil - this one Im using in let urlString. Album arts are URL's and I would like to fetch them as an Image and show with song title and artists, there are more than 5000 songs, and the database kepps growing, so the array is not the solution for me. @OOPer You can find full code here: https://github.com/pawelzet/promil_test/blob/main/ViewController.swift . On the top you can see IBOutlets, coneccted to two labels and UIImageView object. The app is building, but the titles in labels does not change and I cant see album art in this UIImageView. Alson in the API there is a part duration: which show how many seconds the song have. Maybe thats the way I can solve fetching new data? Adding this duration of each song parameter + 15 more seconds for the jingle (which is playing between songs and it is not shown in the API). Thank you in advance for your help.
I dont need any code, just ideas and advices hot to deal with it :)
@OOPer maybe you have any tips and advices what to use in my next steps? I dont mean to write me a code, but some good advices. Thanks.
Ok, so I've got
private(set) var circles: [MKCircle]!
override func viewDidLoad() {
super.viewDidLoad()
checkLocationServices()
findSzczyty(szczyty)
mapView.delegate = self
circles = szczyty.map {
MKCircle(center: $0.coordinate, radius: 200)
}
}
...
func findSzczyty(_ szczyty: [Szczyt]) {
for szczyt in szczyty {
let annotations = MKPointAnnotation()
annotations.title = szczyt.name
annotations.subtitle = szczyt.describtion
annotations.coordinate = CLLocationCoordinate2D(latitude:
szczyt.lattitude, longitude: szczyt.longtitude)
mapView.addAnnotation(annotations)
mapView.addOverlay(circles as! MKOverlay) // when I try to add it on the map I get an error when building - Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
}
}