Could not cast value of type 'Swift.Array.

I am trying to learn Xcode using iOS 14 Programming for Beginners (Packt Pub).

I am now working on the part that adds the pins to the MapView, but when I run the app the map button is unresponsive (Runtime error).

I get the following message in the Debug area: __2021-07-25 16:08:23.919240+0100 EatOut[1420:21167] Metal API Validation Enabled

Could not cast value of type 'Swift.Array<EatOut.RestaurantItem>' (0x1c31e3588) to '__C.MKAnnotation' (0x1c31e3888).

2021-07-25 16:08:24.003987+0100 EatOut[1420:21167] Could not cast value of type 'Swift.Array<EatOut.RestaurantItem>' (0x1c31e3588) to '__C.MKAnnotation' (0x1c31e3888). Could not cast value of type 'Swift.Array<EatOut.RestaurantItem>' (0x1c31e3588) to '

I'm sure that this message means a lot to you experts, but as a beginner I haven't a clue! The runtime error is in this func, in the final line:

 func addMap(_ annontations: [RestaurantItem]) {

            mapView.setRegion(manager.currentRegion(latDelta: 0.5, longDelta: 0.5), animated: true)

            mapView.addAnnotation(manager.annotations as! MKAnnotation)

I get a build error on the final line if I do not apply the fix, which adds the as! MKAnnotation. Is the error in the .plist or does the code need altering? Please can you help?

Here is the full code for the swift file:

//  MapViewController.swift
//  EatOut
//
//  Created by Tony Hudson on 15/07/2021.
//

import UIKit
import MapKit

class MapViewController: UIViewController, MKMapViewDelegate {
    let manager = MapDataManager()

    var selectedRestaurant: RestaurantItem?

    @IBOutlet weak var mapView: MKMapView!

    override func viewDidLoad() {
        initialise()

        func initialise() {
            manager.fetch { (annotations) in addMap(annotations)
            }
        }

        func addMap(_ annontations: [RestaurantItem]) {
            mapView.setRegion(manager.currentRegion(latDelta: 0.5, longDelta: 0.5), animated: true)
            mapView.addAnnotation(manager.annotations as! MKAnnotation)

        }
    }
}

Replies

You don't show enough code (as usual 😊).

How is MapDataManager defined ? (one need to register to the Packt to see it). What is RestaurantItem. Does it have a property like mkAnnotation (I guess so)

But, in any case: manager.annotations is an array of MKAnnotation hence you cannot make it a single MKAnnotation

In addition, you pass annontations (with a typo for annotations) to addMap and never use it !

So following is a best guess :

May be you should have something like:

        func addMap(_ annotations: [RestaurantItem]) {    // 
            mapView.setRegion(manager.currentRegion(latDelta: 0.5, longDelta: 0.5), animated: true)
            for restaurant in annotations {
                mapView.addAnnotation(restaurant.mkAnnotation as! MKAnnotation)
           }
        }

So, please provide enough information to confirm.

  • Hi Claude Have seen my latest post?

Add a Comment

Thank you for your reply! I did not add too many files until I got some feedback. I guess that you would like to see RestaurantItem.swift & MapDataManager.swift:

l//
//  RestaurantItem.swift
//  EatOut
//
//  Created by Tony Hudson on 12/07/2021.
//

import UIKit
import MapKit

class RestaurantItem: NSObject, MKAnnotation {
    var name: String?
    var cuisines: [String] = []
    var lat: Double?
    var long: Double?
    var address: String?
    var postalCode: String?
    var state: String?
    var imageURL: String?
    var restaurantID: Int?

    init (dict: [String: AnyObject]) {
        if let lat = dict["lat"] as? Double { self.lat = lat}
        if let long = dict["long"] as? Double { self.long = long}
        if let name = dict["name"] as? String { self.name = name}
        if let cuisines = dict["cuisines"] as? [String] { self.cuisines = cuisines}
        if let address = dict["address"] as? String { self.address = address}
        if let postalCode = dict["postalCode"] as? String { self.postalCode = postalCode}
        if let state = dict["state"] as? String { self.state = state}
        if let image = dict["imageURL"] as? String { self.imageURL = image}
        if let id = dict["id"] as? Int { self.restaurantID = id}
}

    var coordinate: CLLocationCoordinate2D {
        guard let lat = lat, let long = long else {
            return CLLocationCoordinate2D()
        }
    return CLLocationCoordinate2D(latitude: lat, longitude: long)
}
    var title: String? {
    return name
    }
    var subtitle: String? {
        if cuisines.isEmpty { return ""}
        else if cuisines.count == 1 { return cuisines.first}
        else { return cuisines.joined(separator: ", ")
        }
    }

}

//  MapDataManager.swift
//  EatOut
//
//  Created by Tony Hudson on 12/07/2021.
//

import Foundation
import MapKit

class MapDataManager: DataManager {
    fileprivate var items: [RestaurantItem] = []
    var annotations: [RestaurantItem] {
        return items
    }
    func fetch(completion: (_ annotations: [RestaurantItem]) -> ()){
    if items.count > 0 { items.removeAll() }
        for data in load(file: "MapLocations") {
    items.append(RestaurantItem(dict: data))
    }
    completion(items)
    }

    func currentRegion(latDelta: CLLocationDegrees, longDelta: CLLocationDegrees) -> MKCoordinateRegion {
        guard let item = items.first else {
            return MKCoordinateRegion()
        }
    let span = MKCoordinateSpan(latitudeDelta: latDelta, longitudeDelta: longDelta)
        return MKCoordinateRegion(center: item.coordinate, span: span)
    }
}

Could you explain what you said that annotations was not used?