MKAnnotationView子类在Swift中应该具有哪些初始值设定项?
我正在项目中创建MKAnnotationView子类在Swift中应该具有哪些初始值设定项?,swift,initialization,mapkit,mkannotationview,initializer,Swift,Initialization,Mapkit,Mkannotationview,Initializer,我正在项目中创建MKAnnotationView的子类。它需要有两个属性来存储子视图,我需要在开始的某个地方初始化这些子视图 MKAnnotationView的文档中列出了一个初始值设定项,initWithAnnotation:reuseIdentifier:,所以我想我应该简单地覆盖它: class PulsatingDotMarker: MKAnnotationView { let innerCircle: UIView let outerCircle: UIView
MKAnnotationView
的子类。它需要有两个属性来存储子视图,我需要在开始的某个地方初始化这些子视图
MKAnnotationView
的文档中列出了一个初始值设定项,initWithAnnotation:reuseIdentifier:
,所以我想我应该简单地覆盖它:
class PulsatingDotMarker: MKAnnotationView {
let innerCircle: UIView
let outerCircle: UIView
override init!(annotation: MKAnnotation!, reuseIdentifier: String!) {
innerCircle = ...
outerCircle = ...
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
}
...
}
但这会导致运行时异常:
致命错误:对类“脉动点标记器”使用未实现的初始值设定项“init(frame:)”
好的,我猜initWithAnnotation:reuseIdentifier:
在内部调用initWithFrame:
,所以我应该替代它。让我们试试:
class PulsatingDotMarker: MKAnnotationView {
let innerCircle: UIView
let outerCircle: UIView
override init(frame: CGRect) {
innerCircle = ...
outerCircle = ...
super.init(frame: frame)
}
...
}
但是,这会在创建注释视图对象时导致编译错误:
调用中的额外参数“reuseIdentifier”
嗯,所以如果我实现(必需的)初始值设定项initWithFrame:
,它现在会丢失默认的初始值设定项initWithAnnotation:reuseIdentifier:
如果我添加了一个只调用super
的initWithAnnotation:reuseIdentifier:
重写,它可能会再次可用,可以吗
class PulsatingDotMarker: MKAnnotationView {
let innerCircle: UIView
let outerCircle: UIView
init!(annotation: MKAnnotation!, reuseIdentifier: String!) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
}
override init(frame: CGRect) {
innerCircle = ...
outerCircle = ...
super.init(frame: frame)
}
...
}
不,仍然不好-编译错误:
在super.init调用时未初始化属性“self.innerCircle”
好的,如果我有一个initWithFrame:
,但是在initWithAnnotation:reuseIdentifier:
中初始化了子视图,会怎么样?(但如果有人直接调用initWithFrame:
,该怎么办?…)
毫不奇怪,斯威夫特告诉我:
在super.init调用时未初始化属性“self.innerCircle”
(这次在initWithFrame:
中)
那我该怎么办?我不能在这里和那里创建子视图,对吗
class PulsatingDotMarker: MKAnnotationView {
let innerCircle: UIView
let outerCircle: UIView
init!(annotation: MKAnnotation!, reuseIdentifier: String!) {
innerCircle = ...
outerCircle = ...
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
}
override init(frame: CGRect) {
innerCircle = ...
outerCircle = ...
super.init(frame: frame)
}
...
}
再次出错,这实际上是可行的-即使我在同一个对象中两次指定常量属性(!)
如何正确地做到这一点
(注意:该类还包括一个必需的
initWithCoder:
初始值设定项,该初始值设定项仅调用第一个示例中的fatalError
,但该对象从未从情节提要中创建。)对于我的应用程序,我选择的解决方案是将子视图声明为可选,并在initFrame中实例化它
var innerCircle:UIView
这是我的密码
class EventAnnotationView: MKPinAnnotationView
{
static var REUSE_ID = "EventAnnotationView"
var imageView: UIImageView?
override init(frame: CGRect)
{
super.init(frame: frame)
// Create subview for custom images
imageView = UIImageView(frame: CGRectMake(0, 0, 22, 22))
...
}
override init(annotation: MKAnnotation!, reuseIdentifier: String!)
{
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
}
required init(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
}
感觉不像黑客:),但需要更多的代码/工作,因为子视图是可选的
希望这有帮助。不幸的是,
MKAnnotationView
强制您实现init(frame:CGRect)
,这意味着您也必须初始化该方法中的所有实例变量
再解释一下
对于只能使用传入值初始化的变量,您必须使这些变量成为可选变量,并在init(frame:CGRect)
中将它们设置为nil
原因是我怀疑MKAnnotationView在其objective-C init方法中调用了self.initWithFrame:rect
。这样,如果子类重写了initWithFrame:(CGRect)rect
,它将被调用。然而,这在swift中会导致一个问题,因为如果您声明一个自定义指定的初始化器,您就不会继承超类的初始化器。因此,您必须在子类中实现init(frame:CGRect)
我对UITableViewController
也有同样的问题。其标题看起来遵循相同的模式。i、 e两个不可靠的指定初始值设定者
这让我很难过。但是你能做什么呢 考虑到指定的初始值设定项在运行时没有被iOS调用,Swift 3中显然存在一些实际问题 我发现其他答案中的建议不可编译(在XCode 8.1 GM/iOS 10.1上测试),但经过各种黑客攻击后,我发现这种组合是有效的:
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier);
/* Your actual init code */
}
convenience init(frame: CGRect) {
self.init(annotation: nil, reuseIdentifier: nil);
}
如果子视图被声明为
var innerCircle:UIView怎么办代码>?这可能会避免“required init(xxx)”错误。这正是我最终所做的,但听起来像是一种黑客行为——将属性标记为可空和可变的,即使它应该是非空和常量,只是为了让编译器满意……我在类似的问题上花了一些时间,并做了一个测试项目,我认为我设法找出了原因(Objective C类在其公共init
方法中调用[self initWith…]
方法),但不幸的是,还没有解决方案-
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier);
/* Your actual init code */
}
convenience init(frame: CGRect) {
self.init(annotation: nil, reuseIdentifier: nil);
}