UITapGestureRecognizer 导致崩溃并显示不同的错误消息

Posted

技术标签:

【中文标题】UITapGestureRecognizer 导致崩溃并显示不同的错误消息【英文标题】:UITapGestureRecognizer Causing Crash With Differing Error Messages 【发布时间】:2014-10-17 17:38:46 【问题描述】:

我在工作中遇到了一个大问题,非常感谢一些帮助。这已经花费了我 2 天的时间。

我想要做的是让一个特殊的图像类触发它,当它被触摸时它被分配回调。就是这样。

但是当我触摸图像时它崩溃了,通常没有错误消息(lldb)。有时它会说像"[__NSCFData tapped:]: unrecognized selector sent to instance 0x1780af360" 这样的垃圾。有时会显示"message sent to deallocated object"

我可以连续运行该应用 10 次,每次只需点击屏幕上的同一个对象,就可以收到其中一条随机消息。

代码很简单:

//view controller
var k:K_PreviewImage!
override func viewDidLoad()
    
        var image:iImage = iImage(imageName: "ja3.jpg")
        k = K_PreviewImage(image: image)
        k.touchCallback = nestedTap
        _view.addSubview(k.image)
    

   func nestedTap(k:K_PreviewImage)
    
        println("Successs")
    

这是K_PreviewImage 中的代码(我的可点击图片)。这不会从任何东西继承,包括 NSObject

var touchCallback:((K_PreviewImage)->Void)
    
        set
            if(_touchCallback == nil)
            
                var tap:UIGestureRecognizer = UITapGestureRecognizer(target: self, action:"tapped:")
                _image.addGestureRecognizer(tap)
            

            _touchCallback = newValue
        
        get
            return _touchCallback
        

  func tapped(tap:UITapGestureRecognizer)
    
        println("here")
        if(_touchCallback != nil)
        
            touchCallback(self)
        
    

以上代码在 100% 的情况下都会导致崩溃。

如果我也像这样在K_PreviewImage 中添加@objc 的点击事件监听器

 @objc func tapped(tap:UITapGestureRecognizer)
    
        println("here")
        if(_touchCallback != nil)
        
            touchCallback(self)
        
    

然后代码 WORKS 并触发触摸事件(在 K_PreviewImage 和控制器回调函数 'nestedTap' 内。

不知道为什么会这样,但确实如此。但是我仍然没有桨,因为当我将 K_PreviewImage 设为函数变量而不是类成员变量时,我再次崩溃了

 override func viewDidLoad()
    
        var image:iImage = iImage(imageName: "ja3.jpg")
        var k:K_PreviewImage = K_PreviewImage(image: image)
        k.touchCallback = nestedTap
        _view.addSubview(k.image)
    

所以我的第一个问题是为什么我需要添加 @objc 来触发回调而不是给我一个不清楚的“释放”内存崩溃?

我的第二个问题是为什么当我将变量从成员变量移动到函数变量时会再次导致崩溃。如果对象被释放,它一开始就听不到点击事件,可以吗?为什么还会出现在荧幕上?为什么它只是因为它不是成员变量而被解除分配!

我怎么能动态地创建一个自定义对象并让它触发点击事件!

更新

这是完整的代码块,涉及如何通过触摸事件添加我的 K_PreviewImage

var _array:Array<iImage>!

    override func viewDidLoad()
    
        _array = Array<iImage>()
        var image:iImage = iImage(imageName: "ja3.jpg")
        var k:K_PreviewImage = K_PreviewImage(image: image)
        k.touchCallback = nestedTap
        _view.addSubview(k.image)
        _array.append(k.image)
    

    func nestedTap(k:K_PreviewImage)
    
        println("Successs")
    

已解决:

override func viewDidLoad()
    
        _array = Array<K_PreviewImage>()
        var image:iImage = iImage(imageName: "ja3.jpg")
        var k:K_PreviewImage = K_PreviewImage(image: image)
        k.touchCallback = nestedTap
        _view.addSubview(k.image)
        _array.append(k)
    

    func nestedTap(k:K_PreviewImage)
    
        println("Successs")
    

因为即使添加了子视图,我也没有存储对 K_PreviewImage 'k' 的引用,即使它属于 k,k 也没有被保留。通过使数组存储对 K_PreviewImage 而不是 iImage 的引用,编译器现在保留对 K_Preview Image 的引用

【问题讨论】:

【参考方案1】:

首先,您似乎正在尝试将图像添加为子视图。我不太了解 Swift,但 _view.addSubview(k.image) 在我看来是错误的,并且作为 _view.addSubview(k) 更有意义。

其次,您没有保留对K_PreviewImage 的引用。您将k.image 指定为子视图,这会导致k 被系统检测为“不再使用”。它会清理它,当你尝试访问它时,你会崩溃。

【讨论】:

首先感谢您抽出宝贵时间审阅本文并给予深思熟虑的回应。关于将 K 检测为“不再是用户”的系统,这是为什么?我将 K 存储在作为成员变量的数组中。通过添加 I.image 为什么系统会删除父级并保留子级? image 是 K 的成员变量!它没有在这个例子中显示,但是在使用 _array.append(K) 将它添加到视图后,我确实将 K 存储在一个数组中 您能否更新您的来源以反映k 的正确范围?因为您收到一个错误,指出 [__NSCFData tapped:] 正试图被访问,它看起来很像您期望的对象不是您拥有的对象 - 表明内存已释放回系统和一个 @ 987654328@ 对象出现在它的位置。 非常感谢你,我想通了。我将 iImage 类存储在数组引用中,但这显然没有保留作为一部分的对象(即 K_PreviewImage),而是使 K_PreviewImages 的数组和数组现在正确保留了变量。谢谢你,谢谢你,谢谢你!我被困了好几天,并求助于通过子类 UIGestureTapEvent 传递数据!现在我又可以有干净的代码了!!!!

以上是关于UITapGestureRecognizer 导致崩溃并显示不同的错误消息的主要内容,如果未能解决你的问题,请参考以下文章

UITableView添加UITapGestureRecognizer与didSelectRowAtIndexPath冲突解决方法

将 UITapGestureRecognizer 添加到 XIB

如何为 UIViewController.view 中也具有 UITapGestureRecognizer 的 UIView 挑选和操作 UITapGestureRecognizer?

UITapGestureRecognizer 不适用于 UIView 动画

触摸 MKMapView 会导致引脚轻微移动

使用 UITapGestureRecognizer 无法识别的选择器