Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MKAnnotationView子类在Swift中应该具有哪些初始值设定项?_Swift_Initialization_Mapkit_Mkannotationview_Initializer - Fatal编程技术网

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