简体   繁体   中英

Argument type does not conform to expected type MKAnnotation

I'm using this article as reference https://www.thorntech.com/2016/01/how-to-search-for-location-using-apples-mapkit/ to build my app I try to use matchingItem when searchBarText are equal then append to matchingItems. I currently have a error message that Argument type 'ServiceLocation' does not conform to expected type 'MKAnnotation' which means I need to change the variable type for matchingItem. I am not sure what is the best variable types when you want store ServiceLocation later for using as MapView. Any Suggestion?

var matchingItems = [MKAnnotation]()
        var handleMapSearchDelegate:HandleMapSearch? = nil
    var allServiceLocations : [ServiceLocation] = []
        
        func updateSearchResults(for searchController: UISearchController) {
            
           
            matchingItems = []
            guard let mapView = mapView,
                let searchBarText = searchController.searchBar.text else { return }
            for location in allServiceLocations{
                if(location.locationName == searchBarText){
                   matchingItems.append(location)
                    
                }
            }

ServiceLocation.swift

struct ServiceLocation: Codable {
    var id: Int
    var locationType : LocationType
    var locationName: String
    var latitude: Double
    var longitude: Double
    var active: Bool
    var home : Bool
    var numAvailableChargers : Int
    var acronym : String?
    var eta: Int?
}

So what the compiler is telling you is that you have an array of MKAnnotation but you're trying to stuff a ServiceLocation into it which is an unrelated type. As Swift is strongly typed, this is just invalid (thing square peg - round hole situation).

What you need to do is map your ServiceLocation to MKAnnotation , eg like so:

var matchingItems = [MKAnnotation]()
var handleMapSearchDelegate:HandleMapSearch? = nil
var allServiceLocations : [ServiceLocation] = []
        
func updateSearchResults(for searchController: UISearchController) {
      guard let mapView = mapView,
            let searchBarText = searchController.searchBar.text else { return }

        matchingItems = allServiceLocations.filter({ $0.locationName == searchBarText })
        .map({ 
            let annotation = MKPointAnnotation()
            annotation.coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(exactly: $0.latitude)!, longitude: CLLocationDegrees(exactly: $0.longitude)!)
            annotation.title = $0.locationName
            annotation.subtitle = $0.locationType
        return annotation
       })
}

A few options:

  1. You could make ServiceLocation an annotation, by making it a NSObject subclass that conforms to MKAnnotation . So, first make it a class:

     class ServiceLocation: NSObject, Codable { var id: Int var locationType: LocationType var locationName: String var latitude: Double var longitude: Double var active: Bool var home: Bool var numAvailableChargers: Int var acronym: String? var eta: Int? init(id: Int, locationType: LocationType, locationName: String, latitude: Double, longitude: Double, active: Bool, home: Bool, numAvailableChargers: Int, acronym: String?, eta: Int?) { self.id = id self.locationType = locationType self.locationName = locationName self.latitude = latitude self.longitude = longitude self.active = active self.home = home self.numAvailableChargers = numAvailableChargers self.acronym = acronym self.eta = eta super.init() } }

    Second, add MKAnnotation protocol conformance with a few computed properties:

     extension ServiceLocation: MKAnnotation { var coordinate: CLLocationCoordinate2D { CLLocationCoordinate2D(latitude: latitude, longitude: longitude) } var title: String? { locationName } var subtitle: String? { "\(numAvailableChargers) chargers" } }
  2. Alternatively, you could create an annotation class that has your original service location struct as a property:

     class ServiceLocationAnnotation: NSObject, MKAnnotation { var coordinate: CLLocationCoordinate2D { CLLocationCoordinate2D(latitude: serviceLocation.latitude, longitude: serviceLocation.longitude) } var title: String? { serviceLocation.locationName } var subtitle: String? { "\(serviceLocation.numAvailableChargers) chargers" } let serviceLocation: ServiceLocation init(serviceLocation: ServiceLocation) { self.serviceLocation = serviceLocation super.init() } }

    There are other permutations on this idea, but the key is to just make an annotation that has your struct as a property, and then, rather than adding the ServiceLocation to the map's annotations, add a ServiceLocationAnnotation .

Obviously, make the subtitle whatever you want, but hopefully this illustrates the idea.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM