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)
होता है जिसे घटनाओं की कार्रवाई के रूप में उपयोग किया जाता है।
अगला हम लक्ष्य को जोड़ने और हटाने के लिए object association
का उपयोग करते हैं क्योंकि यह UIControl
द्वारा बनाए नहीं रखा जाएगा।
ईवेंट हैंडलर फ़ंक्शन किसी Protocol
को Target
वर्ग के आंतरिक कामकाज को छिपाने के लिए देता है, लेकिन आपको किसी भी समय लक्ष्य को enable
और disable
करने की अनुमति देता है।
उपयोग उदाहरण:
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()
}
}