Swift中的自我类型及其在两阶段初始化中的使用

Swift中的自我类型及其在两阶段初始化中的使用

问题描述:

请考虑下面的代码,它将一个手势识别器添加到视图中。Swift中的自我类型及其在两阶段初始化中的使用

class ViewController: UIViewController { 
    @IBOutlet weak var imageView: UIImageView! 

    let gesture = UITapGestureRecognizer(target: self, action: #selector(handleGesture(gesture:))) 
    let test1 = self 

    @objc func handleGesture(gesture: UITapGestureRecognizer) { 
     // some code 
     print("hello") 
    } 
    override func viewDidLoad() { 
     let test2 = self 
     super.viewDidLoad() 
     imageView.addGestureRecognizer(gesture) 
    } 
} 

按照this question,上面的代码不工作,因为我想用self(在手势识别器的初始化)时不能完全初始化了,这是因为斯威夫特的两相初始化。

我不感兴趣,容易修复,使这项工作,但是这会触发几个问题:

1)为什么编译器还允许我们在这里使用self如果self还没有准备好使用?如果我试图尽快使用self,我应该不会收到编译器错误?

2)我们不能直接检查self的类型与alt +点击XCode。但是,我们可以检查我的特设变量test1test2的类型。 test2的类型为ViewController,正如预期的那样,test1的类型为(ViewController) ->() -> ViewController(即,需要ViewController并返回无效并返回ViewController的闭包的闭包)。那是什么以及为什么self在同一个班级中有两种不同的类型?

1)

我不应该得到,如果我试图过早地使用self编译错误?

我同意。您可以发送bug report to swift.org

为什么编译器允许我们在这里使用self如果self还没有准备好使用?

不幸的是,还有另一种selfNSObjectthe method self() of NSObject后裔。

2)

那是什么?为什么自己有同一类的两种不同类型的?

当前Swift将在class上下文中解释初始值表达式,而不是在实例上下文中。

你知道方法名可以用夫特用作封闭:

class ViewController: UIViewController { 
    //.. 

    func aMethod() { 
     //... 
    } 

    func anInstanceMethod() { 
     let meth = aMethod //() ->() 
    } 
} 

夫特也可以指一个实例方法在class上下文,其产生一个所谓的未应用方法参考(见SE-0042),其目前返回咖喱功能:

class ViewController: UIViewController { 
    //... 

    func aMethod() { 
     //... 
    } 

    class func aClassMethod() { 
     let meth = aMethod // (ViewController) ->() ->() 
    } 
} 

方法self()也是如此。

通常我们不需要self()方法,我认为应该改变这种行为。

这是适用于Objective-C对象的有趣行为。让我们以这三个例子:

class Object: NSObject { 
    let test = self // compiles 
} 

class NonNSObject { 
// let test = self // errors 
    lazy var lazyTest = self // compiles 

} 

struct NonClass { 
// let test = self // errors 
    lazy var lazyTest = self // errors 
} 

NonNSObject展品你会逃避什么:

对象不能引用自身,直到其完全初始化,let绑定都必须完全初始化之前进行初始化,所以这个失败。

但是,NSObject碰巧有一个Objective-C方法- (instancetype)self;,它返回self。我们可以在NonNSObject上对此进行建模:

func returnSelf() -> NonNSObject { 
    return self 
} 

这就是我们开始看到2)的答案的地方。

如果我们在类别上参考此方法returnSelf,我们得到签名(NonNSObject) ->() -> NonNSObject

let test = NonNSObject.returnSelf 

签名很有意义在这种情况下:

  1. 的说法是,我们实际上要调用的方法
  2. 的对象,你可以用任何实例方法,这样做然后我们“应用”函数(在这种情况下没有参数)
  3. 然后我们终于得到我们的返回值

let curriedFunction = NonNSObject.returnSelf // (Self) ->() -> Self let readyToCall = curriedFunction(NonNSObject()) //() -> Self let finallyApplied = readyToCall() // Self

把所有的拼在一起,我们可以看到,在视图控制器的情况下(从UIViewController中继承其一路从NSObject的链条继承)有一个实例方法self,编译器是假设你的意思是,所以它使用它而不是实例本身(因为这将是一个错误)。因此它的签名是在类本身上使用实例方法的自然结果 - 它需要一个实例,这是第一个参数。

总结:

1)代替假设你犯了一个错误的,迅捷编译器发现上NSObject的一个函数self并返回咖喱形式。 2)这是一个函数的curried形式,特别是返回它自己类型的实例方法。 2.5)它仍然以粉红色突出显示,因为Swift-ObjC interop是轻度hacky,而self既是一种方法,也是self

作为奖励,结构不能自动引用,甚至是懒惰。