iOS
UIControl - 블록을 사용한 이벤트 처리
수색…
소개
일반적으로 UIControl
또는 UIButton
을 사용할 때 사용자가 버튼을 누르거나 컨트롤을 터치하는 것과 같은 이벤트가 버튼이나 컨트롤에서 발생하는 경우 콜백 액션으로 selector
를 추가합니다.
예를 들어 다음과 같이 할 수 있습니다.
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 44))
button.addTarget(self, action: #selector(self.onButtonPress(_:)), for: .touchUpInside)
self.view.addSubview(button)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func onButtonPress(_ button: UIButton!) {
print("PRESSED")
}
}
selector
관해서, 컴파일러는 그것이 존재한다는 것을 알아야합니다. 이것은 protocol
통해 수행 될 수 있고 구현되지 않을 수 있습니다.
예를 들어 다음과 같이하면 응용 프로그램이 중단됩니다.
import UIKit
@objc
protocol ButtonEvent {
@objc optional func onButtonPress(_ button: UIButton)
}
class ViewController: UIViewController, ButtonEvent {
@IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 44))
button.addTarget(self, action: #selector(ButtonEvent.onButtonPress(_:)), for: .touchUpInside)
self.view.addSubview(button)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
응용 프로그램이 onButtonPress
함수를 구현하지 않기 때문입니다.
이제 버튼 초기화와 함께이 모든 작업을 수행 할 수 있다면 어떨까요? 콜백을 지정할 필요가 없으며 언제든지 추가 및 제거 할 수있는 블록을 지정할 수 있습니까? 왜 셀렉터를 구현해야 할까?
해결책
import Foundation
import UIKit
protocol RemovableTarget {
func enable();
func disable();
}
extension UIControl {
func addEventHandler(event: UIControlEvents, runnable: (control: UIControl) -> Void) -> RemovableTarget {
class Target : RemovableTarget {
private var event: UIControlEvents
private weak var control: UIControl?
private var runnable: (control: UIControl) -> Void
private init(event: UIControlEvents, control: UIControl, runnable: (control: UIControl) -> Void) {
self.event = event
self.control = control
self.runnable = runnable
}
@objc
private func run(_ control: UIControl) {
runnable(control: control)
}
private func enable() {
control?.addTarget(self, action: #selector(Target.run(_:)), for: event)
objc_setAssociatedObject(self, unsafeAddress(of: self), self, .OBJC_ASSOCIATION_RETAIN)
}
private func disable() {
control?.removeTarget(self, action: #selector(Target.run(_:)), for: self.event)
objc_setAssociatedObject(self, unsafeAddress(of: self), nil, .OBJC_ASSOCIATION_ASSIGN)
}
}
let target = Target(event: event, control: self, runnable: runnable)
target.enable()
return target
}
}
위의 내용은 UIControl
의 간단한 확장입니다. 이벤트의 액션으로 사용되는 콜백 func run(_ control: UIControl)
이있는 내부 전용 클래스를 추가합니다.
다음으로 우리는 UIControl
의해 유지되지 않기 때문에 대상 object association
을 사용하여 대상을 추가하고 제거합니다.
이벤트 처리기 함수는 Target
클래스의 내부 동작을 숨기고 특정 시점에 대상을 enable
및 disable
할 수 있도록 Protocol
을 반환합니다.
사용 예제 :
import Foundation
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Create a button.
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 44))
//Add an event action block/listener -- Handles Button Press.
let target = button.addEventHandler(event: .touchUpInside) { (control) in
print("Pressed")
}
self.view.addSubview(button)
//Example of enabling/disabling the listener/event-action-block.
DispatchQueue.main.after(when: DispatchTime.now() + 5) {
target.disable() //Disable the listener.
DispatchQueue.main.after(when: DispatchTime.now() + 5) {
target.enable() //Enable the listener.
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow