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

Swift中的自我类型及其在两阶段初始化中的使用,swift,initialization,self,Swift,Initialization,Self,考虑下面的代码,它将手势识别器添加到视图中 class ViewController: UIViewController { @IBOutlet weak var imageView: UIImageView! let gesture = UITapGestureRecognizer(target: self, action: #selector(handleGesture(gesture:))) let test1 = self @objc func han

考虑下面的代码,它将手势识别器添加到视图中

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)
    }
}
根据,上述代码不起作用,因为我试图在未完全初始化时使用
self
(在手势识别器的初始值设定项中),这是因为Swift的两阶段初始化

我对简单的解决方案不感兴趣,但这引发了几个问题:

1) 如果
self
还没有准备好使用,为什么编译器允许我们在这里使用
self
?如果我试图过早地使用
self
,是否应该出现编译器错误

2) 我们不能直接用alt+点击XCode来检查
self
的类型。但是,我们可以检查特殊变量的类型
test1
test2
。虽然
test2
的类型是
ViewController
,但正如预期的那样,
test1
的类型是
(ViewController)->()->ViewController
(即,接受
ViewController
并返回不接受任何内容并返回
ViewController
的闭包)。这是什么?为什么同一个类中有两种不同的类型

如果我试图过早地使用
self
,是否应该出现编译器错误?

我同意。你可以发一封信

如果
self
未准备好使用,编译器为什么允许我们在此处使用
self

不幸的是,在
NSObject
的后代中还有另一个
self

(二)

这是什么?为什么self在同一个类中有两种不同的类型?

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

您知道,方法名称可以用作Swift中的闭包:

class ViewController: UIViewController {
    //..

    func aMethod() {
        //...
    }

    func anInstanceMethod() {
        let meth = aMethod // () -> ()
    }
}
Swift还可以引用
上下文中的实例方法,该方法生成所谓的未应用方法引用(请参阅),该引用当前返回一个curried函数:

class ViewController: UIViewController {
    //...

    func aMethod() {
        //...
    }

    class func aClassMethod() {
        let meth = aMethod // (ViewController) -> () -> ()
    }
}
方法
self()
也是如此

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

1)

如果我试图过早地使用
self
,是否应该出现编译器错误?

我同意。你可以发一封信

如果
self
未准备好使用,编译器为什么允许我们在此处使用
self

不幸的是,在
NSObject
的后代中还有另一个
self

(二)

这是什么?为什么self在同一个类中有两种不同的类型?

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

您知道,方法名称可以用作Swift中的闭包:

class ViewController: UIViewController {
    //..

    func aMethod() {
        //...
    }

    func anInstanceMethod() {
        let meth = aMethod // () -> ()
    }
}
Swift还可以引用
上下文中的实例方法,该方法生成所谓的未应用方法引用(请参阅),该引用当前返回一个curried函数:

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。我们可以在非NSObject上对此进行建模,如下所示:

func returnSelf() -> NonNSObject {
    return self
}
这就是我们开始看到2)答案的地方

如果我们在类上引用这个方法
returnSelf
,我们就会得到签名
(NonNSObject)->()->NonNSObject
。您可以使用任何实例方法执行此操作,如下所示:

let test = NonNSObject.returnSelf 
在这种情况下,签名是有意义的:

  • 参数是我们实际想要调用方法的对象
  • 然后我们“应用”函数(在本例中,没有参数)
  • 我们最终得到了回报值
  • 
    让curriedFunction=NonNSObject.returnSelf/(Self)->()->Self
    让readyToCall=curriedFunction(NonNSObject())/()->Self
    让finallyApplied=readyToCall()//Self
    

    把所有的部分放在一起,我们可以看到,在ViewController(从UIViewController继承,从NSObject继承)的情况下,有一个实例方法
    self
    ,编译器认为这是您的意思,所以它使用它而不是实例本身(因为这将是一个错误)。因此,它的签名是在类本身上使用实例方法的自然结果。它需要一个实例,这是第一个参数

    总之:

    1) Swift编译器在NSObject上找到一个函数
    self
    ,并返回当前格式,而不是假设您出错。 2) 这是函数的货币形式,尤其是返回自己类型的实例方法。 2.5)它仍然以粉红色突出显示,因为Swift ObjC interop有点粗糙,
    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。我们可以在非NSObject上对此进行建模,如下所示:

    func returnSelf() -> NonNSObject {
        return self
    }
    
    这是w