MKAnnotationView子类在Swift中应该具有哪些初始值设定项?

Kub*_*der 11 initialization initializer mapkit mkannotationview swift

我正在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)
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

但这会导致运行时异常:

致命错误:对'PulsatingDotMarker'类使用未实现的初始化程序'init(frame :)'

好的,所以我猜initWithAnnotation:reuseIdentifier:内部调用initWithFrame:,所以可能是我应该覆盖的那个.我们试试看:

class PulsatingDotMarker: MKAnnotationView {

    let innerCircle: UIView
    let outerCircle: UIView

    override init(frame: CGRect) {
        innerCircle = ...
        outerCircle = ...

        super.init(frame: frame)
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

但是,这会在创建注释视图对象时导致编译错误:

调用中的额外参数'reuseIdentifier'

嗯,所以如果我实现(必需的)初始化器initWithFrame:,它现在会丢失默认的初始化器initWithAnnotation:reuseIdentifier:

也许如果我添加一个覆盖initWithAnnotation:reuseIdentifier:,只是调用super它将再次可用,这会工作吗?

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)
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

不,还是不好 - 编译错误:

属性'self.innerCircle'未在super.init调用时初始化

好吧,如果我有一个initWithFrame:,但初始化了子视图initWithAnnotation:reuseIdentifier:怎么办?(但是如果有人直接打电话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) {
        super.init(frame: frame)
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

毫不奇怪,Swift通过告诉我保护我:

属性'self.innerCircle'未在super.init调用时初始化

(这一次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)
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

错了,这实际上有效 - 即使我在同一个对象(!)中分配两次常量属性.

该如何正确完成?

(注意:该类还包括一个必需的initWithCoder:初始化程序,它只是fatalError从第一个示例调用,但该对象永远不会从故事板创建.)

vil*_*393 8

不幸的是,MKAnnotationView您要实施的强制措施init(frame: CGRect)意味着您必须初始化该方法中的所有实例变量.

本文将对此进行更多解释

对于只能使用传入值初始化的变量,您必须使这些变量可选,并将它们设置为nil init(frame: CGRect).

原因是我怀疑MKAnnotationView正在调用self.initWithFrame: rect其Objective-C init方法.这样,如果子类重写initWithFrame:(CGRect) rect它将被调用.但是,这会导致swift问题,因为如果声明自定义指定的初始化程序,则不会继承超类的初始化程序.因此,您必须init(frame: CGRect)在子类中实现它.

我遇到了同样的问题UITableVeiwController.它的标题看起来遵循相同的模式.即两个可归属的指定初始化程序.

这让我非常伤心.但你能做什么呢.


nan*_*nta 2

对于我的应用程序,我选择的解决方案是将子视图声明为可选并在 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)
}
}
Run Code Online (Sandbox Code Playgroud)

感觉不像黑客:),但需要更多代码/工作,因为子视图是可选的。

希望这可以帮助。