#selector Swift 2.2 中的处理程序方法
Handler Method in #selector Swift 2.2
我的想法是创建一种向按钮添加事件方法的简单方法。
以我为例:
Gist
问题是我遇到了 EXC_BAD_ACCESS 的问题,可能是因为#selector 中的执行不安全。
是否有修复或更改的方法来解决它?
调试屏幕:
堆栈跟踪:
* thread #1: tid = 0x4e8e43, 0x0000000110355547 libsystem_blocks.dylib`_Block_copy_internal + 239, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x0000000110355547 libsystem_blocks.dylib`_Block_copy_internal + 239
frame #1: 0x000000010d8c326d Swift-201-Aula2-Exercicio2.1`@objc UICallbackButton.executeCallback(UIButton, callback : (button : UIButton) -> ()) -> () + 45 at ViewController.swift:0
frame #2: 0x000000010e2d4a8d UIKit`-[UIApplication sendAction:to:from:forEvent:] + 92
frame #3: 0x000000010e447e67 UIKit`-[UIControl sendAction:to:forEvent:] + 67
frame #4: 0x000000010e448143 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 327
frame #5: 0x000000010e447263 UIKit`-[UIControl touchesEnded:withEvent:] + 601
frame #6: 0x000000010e34799f UIKit`-[UIWindow _sendTouchesForEvent:] + 835
frame #7: 0x000000010e3486d4 UIKit`-[UIWindow sendEvent:] + 865
frame #8: 0x000000010e2f3dc6 UIKit`-[UIApplication sendEvent:] + 263
frame #9: 0x000000010e2cd553 UIKit`_UIApplicationHandleEventQueue + 6660
frame #10: 0x000000010d9d0301 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #11: 0x000000010d9c622c CoreFoundation`__CFRunLoopDoSources0 + 556
frame #12: 0x000000010d9c56e3 CoreFoundation`__CFRunLoopRun + 867
frame #13: 0x000000010d9c50f8 CoreFoundation`CFRunLoopRunSpecific + 488
frame #14: 0x0000000112140ad2 GraphicsServices`GSEventRunModal + 161
frame #15: 0x000000010e2d2f09 UIKit`UIApplicationMain + 171
* frame #16: 0x000000010d8c42c2 Swift-201-Aula2-Exercicio2.1`main + 114 at AppDelegate.swift:12
frame #17: 0x000000011031292d libdyld.dylib`start + 1
老实说,我不知道如何用选择器来做,但这里是闭包。测试和工作 100%。我将尝试使用选择器找到解决方案。不可能有那么大的不同。可以传一个控制事件数组,它会占全部。
import UIKit
class ViewController: UIViewController {
var count = 1
override func viewDidLoad() {
super.viewDidLoad()
// Button 1
let button = GIBbutton(frame: CGRect(x: 60, y: 30, width: 200, height: 60), controlEvents: [.TouchUpInside], targetAction: { button in
button.setTitle("Title \(self.count)", forState: .Normal)
self.count += 1
})
button.backgroundColor = UIColor.orangeColor()
button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
button.setTitle("Title Default", forState: .Normal)
self.view.addSubview(button)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
class GIBbutton : UIButton{
var 动作:((UIButton!)->Void)!
convenience init(frame:CGRect,controlEvents:[UIControlEvents],targetAction:((UIButton!)->Void)!){
self.init()
self.frame = frame
action = targetAction
for event in controlEvents{
self.addTarget(self, action: #selector(GIBbutton.performOurAction), forControlEvents: event)
}
}
func performOurAction(button:UIButton,completion:(UIButton)){
self.action(self)
}
}
我相信您的代码有几个问题。按钮上的循环引用(可能不是问题),但可以肯定的是,您的回调不会一直到 executeCallback(:) 方法。事实证明你不需要它。只需保存对回调的引用。看看这是否有意义。有效。
import UIKit
class ViewController: UIViewController {
var count = 1
override func viewDidLoad() {
super.viewDidLoad()
// Button 1
let button = UICallbackButton(frame: CGRect(x: 60, y: 30, width: 200, height: 60))
button.backgroundColor = UIColor.orangeColor()
button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
button.setTitle("Title Default", forState: .Normal)
button.on(.TouchUpInside, then: {
button.setTitle("Title \(self.count)", forState: .Normal)
self.count = self.count + 1
})
self.view.addSubview(button)
// Button 2
let button1 = UICallbackButton(frame: CGRect(x: 60, y: 160, width: 200, height: 60))
button1.backgroundColor = UIColor.blackColor()
button1.setTitleColor(UIColor.whiteColor(), forState: .Normal)
button1.setTitle("Value Default", forState: .Normal)
button1.on(.TouchUpInside, then: {
button1.setTitle("Value \(self.count)", forState: .Normal)
self.count = self.count + 1
})
self.view.addSubview(button1)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
typealias ButtonCallback = (() -> ())
protocol UIActionButton {
func on(event : UIControlEvents, then callback: ButtonCallback)
}
final class UICallbackButton : UIButton, UIActionButton {
var buttonCallback: ButtonCallback!
func on(event : UIControlEvents, then callback: ButtonCallback) {
buttonCallback = callback
self.addTarget(self, action: #selector(UICallbackButton.executeCallback(_:)), forControlEvents: event)
}
func executeCallback (_ : UIButton) {
buttonCallback()
}
}
我的想法是创建一种向按钮添加事件方法的简单方法。
以我为例: Gist
问题是我遇到了 EXC_BAD_ACCESS 的问题,可能是因为#selector 中的执行不安全。
是否有修复或更改的方法来解决它?
调试屏幕:
堆栈跟踪:
* thread #1: tid = 0x4e8e43, 0x0000000110355547 libsystem_blocks.dylib`_Block_copy_internal + 239, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x0000000110355547 libsystem_blocks.dylib`_Block_copy_internal + 239
frame #1: 0x000000010d8c326d Swift-201-Aula2-Exercicio2.1`@objc UICallbackButton.executeCallback(UIButton, callback : (button : UIButton) -> ()) -> () + 45 at ViewController.swift:0
frame #2: 0x000000010e2d4a8d UIKit`-[UIApplication sendAction:to:from:forEvent:] + 92
frame #3: 0x000000010e447e67 UIKit`-[UIControl sendAction:to:forEvent:] + 67
frame #4: 0x000000010e448143 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 327
frame #5: 0x000000010e447263 UIKit`-[UIControl touchesEnded:withEvent:] + 601
frame #6: 0x000000010e34799f UIKit`-[UIWindow _sendTouchesForEvent:] + 835
frame #7: 0x000000010e3486d4 UIKit`-[UIWindow sendEvent:] + 865
frame #8: 0x000000010e2f3dc6 UIKit`-[UIApplication sendEvent:] + 263
frame #9: 0x000000010e2cd553 UIKit`_UIApplicationHandleEventQueue + 6660
frame #10: 0x000000010d9d0301 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #11: 0x000000010d9c622c CoreFoundation`__CFRunLoopDoSources0 + 556
frame #12: 0x000000010d9c56e3 CoreFoundation`__CFRunLoopRun + 867
frame #13: 0x000000010d9c50f8 CoreFoundation`CFRunLoopRunSpecific + 488
frame #14: 0x0000000112140ad2 GraphicsServices`GSEventRunModal + 161
frame #15: 0x000000010e2d2f09 UIKit`UIApplicationMain + 171
* frame #16: 0x000000010d8c42c2 Swift-201-Aula2-Exercicio2.1`main + 114 at AppDelegate.swift:12
frame #17: 0x000000011031292d libdyld.dylib`start + 1
老实说,我不知道如何用选择器来做,但这里是闭包。测试和工作 100%。我将尝试使用选择器找到解决方案。不可能有那么大的不同。可以传一个控制事件数组,它会占全部。
import UIKit
class ViewController: UIViewController {
var count = 1
override func viewDidLoad() {
super.viewDidLoad()
// Button 1
let button = GIBbutton(frame: CGRect(x: 60, y: 30, width: 200, height: 60), controlEvents: [.TouchUpInside], targetAction: { button in
button.setTitle("Title \(self.count)", forState: .Normal)
self.count += 1
})
button.backgroundColor = UIColor.orangeColor()
button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
button.setTitle("Title Default", forState: .Normal)
self.view.addSubview(button)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
class GIBbutton : UIButton{ var 动作:((UIButton!)->Void)!
convenience init(frame:CGRect,controlEvents:[UIControlEvents],targetAction:((UIButton!)->Void)!){
self.init()
self.frame = frame
action = targetAction
for event in controlEvents{
self.addTarget(self, action: #selector(GIBbutton.performOurAction), forControlEvents: event)
}
}
func performOurAction(button:UIButton,completion:(UIButton)){
self.action(self)
}
}
我相信您的代码有几个问题。按钮上的循环引用(可能不是问题),但可以肯定的是,您的回调不会一直到 executeCallback(:) 方法。事实证明你不需要它。只需保存对回调的引用。看看这是否有意义。有效。
import UIKit
class ViewController: UIViewController {
var count = 1
override func viewDidLoad() {
super.viewDidLoad()
// Button 1
let button = UICallbackButton(frame: CGRect(x: 60, y: 30, width: 200, height: 60))
button.backgroundColor = UIColor.orangeColor()
button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
button.setTitle("Title Default", forState: .Normal)
button.on(.TouchUpInside, then: {
button.setTitle("Title \(self.count)", forState: .Normal)
self.count = self.count + 1
})
self.view.addSubview(button)
// Button 2
let button1 = UICallbackButton(frame: CGRect(x: 60, y: 160, width: 200, height: 60))
button1.backgroundColor = UIColor.blackColor()
button1.setTitleColor(UIColor.whiteColor(), forState: .Normal)
button1.setTitle("Value Default", forState: .Normal)
button1.on(.TouchUpInside, then: {
button1.setTitle("Value \(self.count)", forState: .Normal)
self.count = self.count + 1
})
self.view.addSubview(button1)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
typealias ButtonCallback = (() -> ())
protocol UIActionButton {
func on(event : UIControlEvents, then callback: ButtonCallback)
}
final class UICallbackButton : UIButton, UIActionButton {
var buttonCallback: ButtonCallback!
func on(event : UIControlEvents, then callback: ButtonCallback) {
buttonCallback = callback
self.addTarget(self, action: #selector(UICallbackButton.executeCallback(_:)), forControlEvents: event)
}
func executeCallback (_ : UIButton) {
buttonCallback()
}
}