简体   繁体   English

通过自定义协议符合协议MKAnnotation

[英]Conform to Protocol MKAnnotation via Custom Protocol

I want to get 2 or more different object types on a map easily. 我希望在地图上轻松获得2个或更多不同的对象类型。 Swift 2.0, I wanted to use Protocols. Swift 2.0,我想使用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! 我假设现在任何符合PinProtocol的项目与MKAnnotation基本相同......更多!

protocol PinProtocol: MKAnnotation {
    // stuff
}

I have 2 Classes, Staff and Clients 我有2个班级,员工和客户

Both conform to PinProtocol (which then also needs to conform to MKAnnotation) 两者都符合PinProtocol(然后还需要符合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. 因此,这告诉我PinProtocol正在按预期工作,因为需要遵守PinProtocol的项目也符合MKAnnotation协议。 Because coordinate:CLLocationCoordinate2D, is required by MKAnnotation. 因为坐标:CLLocationCoordinate2D,是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] 错误是,无法将[PinProtocol]类型的值转换为预期参数[MKAnnotation]

Isn't PinProtocol conforming to MKAnnotation so should work. PinProtocol是不是符合MKAnnotation所以应该工作。

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. 我可以使用AnyObject解决这个问题,但为什么我不能使用PinProtocol - 这对我来说似乎更清晰,而且整个协议扩展的想法。

Thanks for any help. 谢谢你的帮助。

Addit... 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. protocol视为模板,您可以使用该模板制作像学校演示一样有用的东西,但不能将模板本身用于任何演示。

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允许您匿名子类协议,并强制您实现所需的方法。 (Java calls it interface , don't confuse it Objective-C interface ) (Java称它为interface ,不要混淆它的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. 与java不同,Swift不支持创建匿名子类,因此任何本身都是协议的类都无法在Objective-C和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. 实例化它们的唯一方法是让另一个class (Objective C中的interface )符合该协议,并在您的情况下创建该特定类的实例, StaffClient 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. staff在这种情况下是Array类型的PinProtocol ,它不知道关于创建对象的任何其他信息。

Edit: 编辑:

I just understood your question correctly. 我正确理解你的问题。 Yes, we can declare an array of type in swift by protocol names. 是的,我们可以通过protocol名称在swift中声明一个类型的数组。 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: 关于错误错误是,无法将[PinProtocol]类型的值转换为期望的参数[MKAnnotation]我查看了文档,并发现方法addAnnotations()接受AnyObject数组如下:

func addAnnotations(annotations: [AnyObject]!) //in MKMapView 

Now the tricky part is, MKAnnotation doesn't inherit from AnyObject , but instead from NSObjectProtocol ie: 现在棘手的部分是, MKAnnotation不是从AnyObject继承,而是从NSObjectProtocol继承,即:

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. AnyObject也继承了NSObjectProtocol ,使得它成为MKAnnotation的兄弟,这就是你得到错误的原因,因为你不能传递具有MKAnnotation类型的MKAnnotation ,因为它们在它们的父层次结构中不是AnyObject

After dealing with the hassle of MapViewController's data source being 在处理了MapViewController的数据源的麻烦之后

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 我开始意识到我可以轻松避免所有相关的类型检查问题,并使用首选的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)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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