I want to get 2 or more different object types on a map easily. Swift 2.0, I wanted to use Protocols.
I created a protocol that these object need to conform too. I assume that now any item the conforms to PinProtocol as essentially the same as being an MKAnnotation... just more!
protocol PinProtocol: MKAnnotation {
// stuff
}
I have 2 Classes, Staff and Clients
Both conform to PinProtocol (which then also needs to conform to MKAnnotation)
I know this is working as if I set up my class as such,
class Client: NSObject, PinProtocol {
//var coordinate:CLLocationCoordinate2D // Leave out get doesn't conform to protocol warning as expected
}
So, this tells me that that PinProtocol is working as expected, as items that need to adhere to the PinProtocol are also conforming to the MKAnnotation protocol as well. Because coordinate:CLLocationCoordinate2D, is required by MKAnnotation.
So why do I get this issue with
let staffAndClients = [PinProtocol]()
mapView.addAnnotations(staffAndClients) // not allowed!
//mapView.addAnnotations(pins as! [MKAnnotation]) // also not allowed
The error is, cannot convert value of type [PinProtocol] to to expected argument [MKAnnotation]
Isn't PinProtocol conforming to MKAnnotation so should work.
But doing this works fine
let staff = [Staff]()
mapView.addAnnotations(staff) // no problem
let clients = [Client]()
mapView.addAnnotations(clients) // no problem
I can get around the issue using AnyObject, but why cannot I use PinProtocol - which to me seems cleaner and the whole idea of protocol extensions.
Thanks for any help.
Addit...
The way I am getting around it for those who are facing a similar issue is
var pins = [AnyObject]()
mapView.addAnnotations(pins as! [MKAnnotation])
Consider protocol
as a template, you can use that template to make something useful like school presentation, but you cannot use the template itself for any presentation.
That's because protocol lacks the implementation of the methods or properties. To really get an object of that particular protocol, these methods needs to be implemented. Java in that case lets you anonymously sub-class a protocol, and forces you to implement the required methods. (Java calls it interface
, don't confuse it Objective-C interface
)
Unlike java, Swift doesn't support creating anonymous sub-classes, so any class that itself is a protocol cannot create objects in Objective-C and Swift. The only way of instantiating them is getting another class
( interface
in Objective C) conform that protocol and create instance of that particular class, Staff
and Client
in your case. However you can have a variable with the type of protocol as follow:
let staff = [PinProtocol]() //PinProtocol type array. can hold any type of objects that conform to this protocol
staff
in this case is Array
of type PinProtocol
, it doesn't know any other info regarding the object created.
I just understood your question correctly. Yes, we can declare an array of type in swift by protocol
names. And that array can hold objects of the classes that conform to the protocol. Your syntax of declaring array is correct.
let staffAndClients = [PinProtocol]()
Regarding the error The error is, cannot convert value of type [PinProtocol]
to to expected argument [MKAnnotation]
I looked into documentations, and found out that the method addAnnotations()
takes array of AnyObject
as follow:
func addAnnotations(annotations: [AnyObject]!) //in MKMapView
Now the tricky part is, MKAnnotation
doesn't inherit from AnyObject
, but instead from NSObjectProtocol
ie:
protocol MKAnnotation : NSObjectProtocol
Whereas AnyObject
also inherit from NSObjectProtocol
, making it sibling of MKAnnotation
that's why you're getting error, because you cannot pass object with types of MKAnnotation
, because they're not AnyObject
in their parent hierarchy.
After dealing with the hassle of MapViewController's data source being
var pins = [AnyObject]()
I came to the realisation that I could easily avoid all the associated issues of type checking and use the preferred array of PinProtocols
var pins = [PinProtocol]()
The workaround was simply
func addToMap() {
let mappingPins = pins.map{ $0 as AnyObject }
mapView.addAnnotations(mappingPins as! [MKAnnotation])
mapView.showAnnotations(mappingPins as! [MKAnnotation], animated: true)
}
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.