UITapGestureRecognizer导致崩溃与不同的错误消息

时间:2014-10-17 17:38:46

标签: ios uiview swift uigesturerecognizer nszombies

我有一个重要的问题,我在工作中坚持,并真的很感激一些帮助。这已经花了我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%的时间内导致崩溃。

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

 @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图像的引用

1 个答案:

答案 0 :(得分:3)

首先,看起来您正在尝试将图像添加为子视图。我不太了解斯威夫特,但_view.addSubview(k.image)对我来说看起来不对,并且会更有意义_view.addSubview(k)

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