xcode 在 Swift 1.2 的 init 方法中将 self 作为参数传递
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29631800/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pass self as argument within init method in Swift 1.2
提问by Pette
The following class has a 'let
' property declared as implicitly unwrapped variable. This previously worked with Xcode 6.2:
以下类具有let
声明为隐式解包变量的“ ”属性。这以前适用于 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
'. Since it is a constant, it has to have an initial value upon declaration, or initialize it within the init
method. To initialize it, it requires to pass 'self
' in the 'target
' parameter.
属性“ panGestureRecognizer
”不需要更改,因此必须将其声明为常量“ let
”。因为它是一个常量,所以它必须在声明时有一个初始值,或者在init
方法中初始化它。要初始化它,它需要self
在 ' target
' 参数中传递 ' ' 。
Other thread suggested to declare it as implicitly unwrapped optional, and initialize it after the super.init
call. This previously worked until I updated to Xcode 6.3.
其他线程建议将其声明为隐式解包可选,并在super.init
调用后对其进行初始化。这之前一直有效,直到我更新到 Xcode 6.3。
Does anybody know a proper implementation or a workaround for this case?
有人知道这种情况的正确实现或解决方法吗?
回答by ABakerSmith
The Problem
问题
The problem is your use of let
- optionals declared as let
aren't given a default value of nil
(var
is however). 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:
问题是您使用let
- 声明为let
的选项没有给出默认值nil
(var
然而)。以下在 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
; it hasn't been initialised at all.
因此,您会收到错误“Property 'self.panGestureRecognizer' not initialized at super.init call”,因为在调用之前super.init(coder: aDecoder)
,因为panGestureRecognizer
不是nil
;它根本没有被初始化。
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
为 a 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()
. Then set the target after super.init
is called:
2.在我看来,更好的解决方案是:不要使用隐式解包的可选项并panGestureRecognizer
使用初始值声明UIPanGestureRecognizer()
。然后在super.init
调用后设置目标:
class SubView: UIView {
let panGestureRecognizer = UIPanGestureRecognizer()
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
panGestureRecognizer.addTarget(self, action: Selector("panAction:"))
}
}
回答by zrzka
You can't use self
unless the class is initialized. And if you would like to use self
for property initialization, it must be lazy
. But lazy
is not supported for let
, just var
.
self
除非类被初始化,否则您不能使用。如果你想self
用于属性初始化,它必须是lazy
. 但lazy
不支持let
,只是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. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.
您必须始终将惰性属性声明为变量(使用 var 关键字),因为在实例初始化完成之前可能无法检索其初始值。常量属性在初始化完成之前必须始终有一个值,因此不能声明为惰性。
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.
或者panGestureRecognizer
用 just初始化UIPanGestureRecognizer()
并稍后添加目标。
回答by Mike Pollard
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) {
// ...
}
}
}
回答by Denis Kutlubaev
If you want to pass self to initializer of an object, you should declare your object as lazy. Because when this object is initialized, self is not ready yet.
如果要将 self 传递给对象的初始化程序,则应将对象声明为惰性对象。因为这个对象初始化的时候,self还没有准备好。
lazy var viewModel = IntroViewModel(controller: self)
class IntroViewModel {
private weak var controller: IntroViewController?
init(controller: IntroViewController?) {
self.controller = controller
}
}
回答by Honey
I had this problem for a different reason, it had nothing to do with Optionals or lazy. Just literally that the person
object had to be initialized once.
我遇到这个问题的原因不同,它与 Optionals 或懒惰无关。从字面上看,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 可以捕捉到这个错误,这很有趣