将 class 设置为 UITapGestureRecognizer 的目标而不是 'self' 时应用程序崩溃
App crashes when setting a class to UITapGestureRecognizer's target instead of 'self'
当我将 'self' 设置为 UITapGestureRecognizer 实例的目标时,下面的代码有效,但是当我将它设置为 'SkinViewTransitionHelper' 实例时,应用程序崩溃并且 Xcode 不显示任何有用的信息,实际上什么都没有,当应用程序崩溃时,控件(我的意思是绿色指示器)转到 AppDelegate。此外,堆栈跟踪是空的,只显示一些与崩溃无关的线程。我确实进行了很多搜索并重新阅读了 UIGestureRecognizer 的文档,但没有帮助。我究竟做错了什么?我在 Xcode 版本 6.2 (6C107a) 中编写应用程序。此外,我正在 iOS 模拟器版本 8.2 (553.8) 中测试该应用程序。我也检查了 UITapGestureRecognizer calling another class
/**
Manages the view that contains logo and button.
*/
class LaunchView: UIView {
// MARK: Instance variables
/** Logo image view */
private var logoImageView: UIImageView!
/** x Button image view */
private var xButtonImageView: UIImageView!
// MARK: Designated Initializer
/**
Initialize LaunchView view with logo and button.
:param: frame Frame of this view
:param: logoImage Logo Image used at the top of the view
:param: xButtonImage Button Image used at the bottom of the view
*/
init(frame: CGRect, logoImage: UIImage, xButtonImage: UIImage){
super.init(frame: frame)
// Initialize the logoImageView
logoImageView = UIImageView(frame: frame)
// Set the image of logoImageView
logoImageView.image = logoImage
// Initialize the capriceButtonImage
// Note: It's kinda hard coding the (x,y) values. Look for a generic way.
xButtonImageView = UIImageView(frame: CGRect(x: frame.size.width / 4 + 20, y: frame.size.height - 200, width: xButtonImage.size.width, height: xButtonImage.size.height))
// Set the image of xButtonImageView
xButtonImageView.image = xButtonImage
// SingleTap recognizer for xButtonImageView
// Note: Find a generic solution instead of writing method name in "". It's kinda horrible; Maybe I forget to write the name of function correctly.
// Note: Still not possible in Swift. reflect() helps if we want information about properties.
// Note: https://github.com/ksm/SwiftInFlux#reflection
// FIXME: App crashes using SkinViewTransitionHelper() as target
let singleTapGestureRecognizer: UITapGestureRecognizer =
UITapGestureRecognizer(target: SkinViewTransitionHelper(), action: "handleGesture:")
// works like a charm if I remove the comment and comment above line
// let singleTapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handleGesture:")
// Set the nunmber of taps required
singleTapGestureRecognizer.numberOfTapsRequired = 1
singleTapGestureRecognizer.numberOfTouchesRequired = 1
// Add tap gesture to xButtonImageView
xButtonImageView.addGestureRecognizer(singleTapGestureRecognizer)
xButtonImageView.userInteractionEnabled = true
// Add logoImageView to the view
self.addSubview(logoImageView)
// Add xButtonImageView to the view
self.addSubview(xButtonImageView)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// func handleGesture(gestureRecongnizer: UIGestureRecognizer) {
// if .Ended == gestureRecongnizer.state {
// T0D0: Notify LaunchViewController of gesture
// }
// }
}
/**
Handle gesture recognized by a UIView instance
*/
class SkinViewTransitionHelper {
// MARK: Gesture Handler
/**
Handle gesture recognized by a UIView instance
*/
func handleGesture(gestureRecongnizer: UIGestureRecognizer) {
println(__FUNCTION__)
if .Ended == gestureRecongnizer.state {
// TODO: Load SkinViewController
}
}
}
import UIKit
class LaunchViewViewController: UIViewController {
override func viewDidLoad() {
println(self)
println(__FUNCTION__)
super.viewDidLoad()
}
override func loadView() {
println(self)
println(__FUNCTION__)
// Set LaunchView as the view of LaunchViewViewController
self.view = LaunchView(frame: UIScreen.mainScreen().bounds, logoImage: ImagesCatalog.Logo, xButtonImage: ImagesCatalog.xButton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
它崩溃了,因为 target
是 UITapGestureRecognizer
class 的弱 属性,因此 SkinViewTransitionHelper
的实例没有被 UITapGestureRecognizer
.
创建一个 属性 类型 SKinViewTransitionHelper
并在其上存储一个实例并将其设置为 UITapGestureRecognizer
目标。
class LaunchView {
var skinViewHelper : SKinViewTransitionHelper!
init(frame: CGRect, logoImage: UIImage, xButtonImage: UIImage){
//Your code
self.skinViewHelper = SKinViewTransitionHelper()
let singleTapGestureRecognizer: UITapGestureRecognizer =
UITapGestureRecognizer(target: self.skinViewHelper, action: "handleGesture:")
}
}
同时使用 @objc
将要引用的函数标记为选择器
class SkinViewTransitionHelper {
@objc func handleGesture(gestureRecongnizer: UIGestureRecognizer) {
println(__FUNCTION__)
if .Ended == gestureRecongnizer.state {
// TODO: Load SkinViewController
}
}
}
如果您实例化 SkinViewTransitionHelper 并将其值存储到变量中(可能需要 class 属性)然后将其指定为目标,会发生什么情况?
我认为您的 SkinViewTransitionHelper 实例可能在 'target' 赋值后被释放,因为在任何地方都没有对它的硬引用。
当我将 'self' 设置为 UITapGestureRecognizer 实例的目标时,下面的代码有效,但是当我将它设置为 'SkinViewTransitionHelper' 实例时,应用程序崩溃并且 Xcode 不显示任何有用的信息,实际上什么都没有,当应用程序崩溃时,控件(我的意思是绿色指示器)转到 AppDelegate。此外,堆栈跟踪是空的,只显示一些与崩溃无关的线程。我确实进行了很多搜索并重新阅读了 UIGestureRecognizer 的文档,但没有帮助。我究竟做错了什么?我在 Xcode 版本 6.2 (6C107a) 中编写应用程序。此外,我正在 iOS 模拟器版本 8.2 (553.8) 中测试该应用程序。我也检查了 UITapGestureRecognizer calling another class
/**
Manages the view that contains logo and button.
*/
class LaunchView: UIView {
// MARK: Instance variables
/** Logo image view */
private var logoImageView: UIImageView!
/** x Button image view */
private var xButtonImageView: UIImageView!
// MARK: Designated Initializer
/**
Initialize LaunchView view with logo and button.
:param: frame Frame of this view
:param: logoImage Logo Image used at the top of the view
:param: xButtonImage Button Image used at the bottom of the view
*/
init(frame: CGRect, logoImage: UIImage, xButtonImage: UIImage){
super.init(frame: frame)
// Initialize the logoImageView
logoImageView = UIImageView(frame: frame)
// Set the image of logoImageView
logoImageView.image = logoImage
// Initialize the capriceButtonImage
// Note: It's kinda hard coding the (x,y) values. Look for a generic way.
xButtonImageView = UIImageView(frame: CGRect(x: frame.size.width / 4 + 20, y: frame.size.height - 200, width: xButtonImage.size.width, height: xButtonImage.size.height))
// Set the image of xButtonImageView
xButtonImageView.image = xButtonImage
// SingleTap recognizer for xButtonImageView
// Note: Find a generic solution instead of writing method name in "". It's kinda horrible; Maybe I forget to write the name of function correctly.
// Note: Still not possible in Swift. reflect() helps if we want information about properties.
// Note: https://github.com/ksm/SwiftInFlux#reflection
// FIXME: App crashes using SkinViewTransitionHelper() as target
let singleTapGestureRecognizer: UITapGestureRecognizer =
UITapGestureRecognizer(target: SkinViewTransitionHelper(), action: "handleGesture:")
// works like a charm if I remove the comment and comment above line
// let singleTapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handleGesture:")
// Set the nunmber of taps required
singleTapGestureRecognizer.numberOfTapsRequired = 1
singleTapGestureRecognizer.numberOfTouchesRequired = 1
// Add tap gesture to xButtonImageView
xButtonImageView.addGestureRecognizer(singleTapGestureRecognizer)
xButtonImageView.userInteractionEnabled = true
// Add logoImageView to the view
self.addSubview(logoImageView)
// Add xButtonImageView to the view
self.addSubview(xButtonImageView)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// func handleGesture(gestureRecongnizer: UIGestureRecognizer) {
// if .Ended == gestureRecongnizer.state {
// T0D0: Notify LaunchViewController of gesture
// }
// }
}
/**
Handle gesture recognized by a UIView instance
*/
class SkinViewTransitionHelper {
// MARK: Gesture Handler
/**
Handle gesture recognized by a UIView instance
*/
func handleGesture(gestureRecongnizer: UIGestureRecognizer) {
println(__FUNCTION__)
if .Ended == gestureRecongnizer.state {
// TODO: Load SkinViewController
}
}
}
import UIKit
class LaunchViewViewController: UIViewController {
override func viewDidLoad() {
println(self)
println(__FUNCTION__)
super.viewDidLoad()
}
override func loadView() {
println(self)
println(__FUNCTION__)
// Set LaunchView as the view of LaunchViewViewController
self.view = LaunchView(frame: UIScreen.mainScreen().bounds, logoImage: ImagesCatalog.Logo, xButtonImage: ImagesCatalog.xButton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
它崩溃了,因为 target
是 UITapGestureRecognizer
class 的弱 属性,因此 SkinViewTransitionHelper
的实例没有被 UITapGestureRecognizer
.
创建一个 属性 类型 SKinViewTransitionHelper
并在其上存储一个实例并将其设置为 UITapGestureRecognizer
目标。
class LaunchView {
var skinViewHelper : SKinViewTransitionHelper!
init(frame: CGRect, logoImage: UIImage, xButtonImage: UIImage){
//Your code
self.skinViewHelper = SKinViewTransitionHelper()
let singleTapGestureRecognizer: UITapGestureRecognizer =
UITapGestureRecognizer(target: self.skinViewHelper, action: "handleGesture:")
}
}
同时使用 @objc
class SkinViewTransitionHelper {
@objc func handleGesture(gestureRecongnizer: UIGestureRecognizer) {
println(__FUNCTION__)
if .Ended == gestureRecongnizer.state {
// TODO: Load SkinViewController
}
}
}
如果您实例化 SkinViewTransitionHelper 并将其值存储到变量中(可能需要 class 属性)然后将其指定为目标,会发生什么情况?
我认为您的 SkinViewTransitionHelper 实例可能在 'target' 赋值后被释放,因为在任何地方都没有对它的硬引用。