简体   繁体   English

在Swift 1.2中将self作为参数传递给init方法

[英]Pass self as argument within init method in Swift 1.2

The following class has a ' let ' property declared as implicitly unwrapped variable. 以下类具有声明为隐式展开变量的' let '属性。 This previously worked with Xcode 6.2: 以前这适用于Xcode 6.2:

class SubView: UIView {

    let pandGestureRecognizer: UIPanGestureRecognizer!

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.pandGestureRecognizer = UIPanGestureRecognizer(target: self, action: "panAction:")
    }

    func panAction(gesture: UIPanGestureRecognizer) {
        // ...
    }
}

After updating to Xcode 6.3 (with Swift 1.2), the following compilation errors occur: 更新到Xcode 6.3(使用Swift 1.2)后,会发生以下编译错误:

Property 'self.panGestureRecognizer' not initialized at super.init call
Immutable value 'self.panGestureRecognizer' may only be initialized once

Moving the following line before the super.init call: super.init调用之前移动以下行:

self.pandGestureRecognizer = UIPanGestureRecognizer(target: self, action: "panAction:")

gives the following error: 给出以下错误:

'self' is used before super.init call

The property ' panGestureRecognizer ' requires no mutation, therefore it has to be declared as constant ' let '. 属性' panGestureRecognizer '不需要变异,因此必须将其声明为常量' let '。 Since it is a constant, it has to have an initial value upon declaration, or initialize it within the init method. 由于它是常量,因此必须在声明时具有初始值,或者在init方法中初始化它。 To initialize it, it requires to pass ' self ' in the ' target ' parameter. 要初始化它,需要在' target '参数中传递' self '。

Other thread suggested to declare it as implicitly unwrapped optional, and initialize it after the super.init call. 其他线程建议将其声明为隐式解包可选,并在super.init调用后初始化它。 This previously worked until I updated to Xcode 6.3. 这之前一直有效,直到我更新到Xcode 6.3。

Does anybody know a proper implementation or a workaround for this case? 有没有人知道这种情况的正确实施或解决方法?

The Problem 问题

The problem is your use of let - optionals declared as let aren't given a default value of nil ( var is however). 问题是你使用let -optionals声明为let没有给出默认值nil (但是var是)。 The following, introduced in Swift 1.2, wouldn't be valid otherwise since you wouldn't be able to give myOptional a value after declaring it: 以下是在Swift 1.2中引入的,否则将无效,因为在声明之后你将无法给myOptional一个值:

let myOptional: Int?

if myCondition {
    myOptional = 1
} else {
    myOptional = nil
}

Therefore, you're getting the error 'Property 'self.panGestureRecognizer' not initialized at super.init call' because before calling super.init(coder: aDecoder) , because panGestureRecognizer isn't nil ; 因此,你得到错误'属性'self.panGestureRecognizer'没有在super.init调用'初始化'因为在调用super.init(coder: aDecoder) ,因为panGestureRecognizer不是nil ; it hasn't been initialised at all. 它根本没有初始化。

The Solutions: 解决方案:

1. Declare panGestureRecognizer as a var , meaning it will be given a default value of nil , which you could then change after calling super.init(coder: aDecoder) . 1.将 panGestureRecognizer声明为var ,意味着它将被赋予默认值nil ,然后在调用super.init(coder: aDecoder)之后可以更改。

2. In my opinion, the better solution: don't use an implicitly unwrapped optional and declare panGestureRecognizer with an initial value of UIPanGestureRecognizer() . 2.在我看来,更好的解决方案是:不要使用隐式展开的可选项,并使用初始值UIPanGestureRecognizer()声明panGestureRecognizer Then set the target after super.init is called: 然后在调用super.init后设置目标:

class SubView: UIView {
    let panGestureRecognizer = UIPanGestureRecognizer()

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        panGestureRecognizer.addTarget(self, action: Selector("panAction:"))
    }
}

You can't use self unless the class is initialized. 除非初始化类,否则不能使用self And if you would like to use self for property initialization, it must be lazy . 如果你想使用self进行属性初始化,它必须是lazy But lazy is not supported for let , just var . 但是let不支持lazy ,只是var

That's because: 那是因为:

You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes. 您必须始终将惰性属性声明为变量(使用var关键字),因为在实例初始化完成之后,可能无法检索其初始值。 Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy. 常量属性在初始化完成之前必须始终具有值,因此不能声明为惰性。

It's kind of compromise and if you can live with private setter, you can do this: 这是妥协,如果你可以住私人二手,你可以这样做:

class SubView: UIView {

  private(set) lazy var panGestureRecognizer: UIPanGestureRecognizer = { [unowned self] in UIPanGestureRecognizer(target: self, action: "panAction:") }()

  required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
  }

  func panAction(gesture: UIPanGestureRecognizer) {
  }
}

Or initialize panGestureRecognizer with just UIPanGestureRecognizer() and add target later. 或者仅使用UIPanGestureRecognizer()初始化panGestureRecognizer并稍后添加目标。

A workaround for this specific case would be: 针对此特定情况的解决方法是:

class SubView: UIView {

let pandGestureRecognizer: UIPanGestureRecognizer

required init(coder aDecoder: NSCoder) {
    self.pandGestureRecognizer = UIPanGestureRecognizer()
    super.init(coder: aDecoder)
    self.pandGestureRecognizer.addTarget(self, action: "panAction:")
}

func panAction(gesture: UIPanGestureRecognizer) {
    // ...
}

} }

If you want to pass self to initializer of an object, you should declare your object as lazy. 如果要将self传递给对象的初始值设定项,则应将对象声明为惰性。 Because when this object is initialized, self is not ready yet. 因为初始化此对象时,self还没有准备好。

lazy var viewModel = IntroViewModel(controller: self)

class IntroViewModel {

    private weak var controller: IntroViewController?

    init(controller: IntroViewController?) {
        self.controller = controller
    }
}

I had this problem for a different reason, it had nothing to do with Optionals or lazy. 我有这个问题的原因不同,它与Optionals或懒惰无关。 Just literally that the person object had to be initialized once. 从字面上看, person对象必须初始化一次。

class Person {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Account {
    static let shared = Account(person: Person(name: "Bobby")) // <-- person initialized once
    let person: Person = Person(name: "Lio") // initialized again!

    init(person: Person) {
        self.person = person
    }
}

It's quite interesting that Swift can catch this error Swift可以捕获这个错误,这很有趣

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

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