UITapGestureRecognizer, вызывающий сбой при различных сообщениях об ошибках
У меня есть серьезная проблема, с которой я застрял на работе и ДЕЙСТВИТЕЛЬНО буду признателен за помощь. Это стоило мне уже 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)
}
}
Затем код работает, и сенсорное событие запускается (как внутри 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 ответ
Во-первых, похоже, что вы пытаетесь добавить изображение в качестве подпредставления. Я не очень хорошо знаю Свифта, но _view.addSubview(k.image)
выглядит неправильно для меня и будет иметь больше смысла, как _view.addSubview(k)
,
Во-вторых, вы не держите ссылку на свой K_PreviewImage
, Вы назначаете k.image
как подпредставление, которое вызывает k
быть обнаруженным системой как "больше не используемая". Это очистит его, и когда вы попытаетесь получить к нему доступ, вы потерпите крах.