如果在初始时间创建时手势识别器不工作

问题描述:

在集合视图中,我在类init时创建手势识别器。在viewDidLoad方法中,我然后将手势识别器添加到集合视图。如果在初始时间创建时手势识别器不工作

class ViewController: UIViewController { 
    @IBOutlet weak var collectionView: UICollectionView! 
    let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongGesture(gesture:))) 

    @objc func handleLongGesture(gesture: UILongPressGestureRecognizer) { 
     // some code 
    } 
    override func viewDidLoad() { 
     super.viewDidLoad() 
     collectionView.addGestureRecognizer(longPressGesture) 
    } 
} 

由此,手势识别器不起作用。

修复很简单:将let longPressGesture移动到viewDidLoad方法就足够了,一切都按预期工作。不过,我觉得第一个版本不起作用有点令人惊讶。

任何人都可以解释为什么第一个版本不工作?这是因为,当手势识别器被创建时,集合视图还没有准备好手势?那么,手势识别器必须知道其目标才能创建?

好问题。这是因为您在未完全初始化时尝试使用self

现在,如何以你想要的方式使这项工作?也许它声明懒洋洋地,就像这样:

private lazy var longPressGesture: UILongPressGestureRecognizer! = { 
    let gesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongGesture(gesture:))) 
    return gesture 
}() 

编辑:从这个question报价giorashc的回答是:

由于SWIFT的2相初始化,你需要之前,你可以初始化 父类在继承类中使用self。

在你实现自我又是这样,你说你应该把它移动到 视图控制器的init方法并调用父类的 初始化方法后创建的按钮被父 类初始化

2 Phase Initialization SO问题&答案。

+1

确实懒惰的声明会起作用。你可以简单地接受我的声明,并用'lazy var'替换'let',而不需要代码块。但是,我的问题是关于初次尝试失败的确切原因。我知道'self'可能没有完全初始化,但是那个时候手势识别器缺少的是什么(应该定义'self'作为指针,如果没有,我们不应该被允许使用它由编译器)?如果它关于它应该处理的视图范围,那么即使在'viewDidLoad'的级别,几何图形也没有设置。 – Maiaux

+0

再次看到我的回答。我希望我补充了正确的解释。 – Glenn

+0

毫无疑问,这是正确的解释(我会接受)。然而,这引发了一个问题:如果'self'没有准备好使用,为什么编译器允许我们在那里使用'self'?如您所知,我们无法直接通过在XCode中单击鼠标来检查自己的类型。然而,通过编写'let test = self'和alt -''点击''我发现我自己的'self'类型不是'ViewController',而是'(ViewController) - >() - > ViewController'(即一个采用'ViewController'并返回一个不需要任何东西并返回一个'ViewController'的闭包的闭包。现在我有点困惑... – Maiaux