Mi è capitato di vedere questo nella barra laterale, ho avuto di recente questo stesso problema ..Sfortunatamente, a causa delle limitazioni del runtime Objective-C non è possibile utilizzare @objc sulle estensioni del protocollo, credo che questo problema sia stato chiuso all'inizio di quest'anno.
Il problema sorge perché l'estensione viene aggiunta dopo la conformità del protocollo, quindi non c'è modo di garantire che la conformità al protocollo sia soddisfatta. Detto questo, è possibile chiamare un metodo come selettore da qualsiasi sottoclasse di NSObject e conforme al protocollo. Questo è più spesso fatto con delega.
Ciò implica che è possibile creare una sottoclasse wrapper vuota conforme al protocollo e utilizzare il wrapper per richiamare i suoi metodi dal protocollo definito nel wrapper, eventuali altri metodi non definiti dal protocollo possono essere passati al delegato. Esistono altre soluzioni simili che utilizzano un'estensione privata di una classe concreta come UIViewController e definiscono un metodo che chiama il metodo del protocollo, ma sono anche legate a una particolare classe e non a un'implementazione predefinita di una particolare classe che si conforma a il protocollo.
Realizzare che si sta tentando di implementare un'implementazione predefinita di una funzione di protocollo che utilizza un'altra delle proprie funzioni di protocollo per definire un valore per la propria implementazione. wow!
Protocollo:
public protocol CustomViewDelegate {
func update()
func nonDelegatedMethod()
}
Vista:
Utilizzare un delegato, e definire un metodo wrapper per scartare in modo sicuro il metodo del delegato.
class CustomView: UIView {
let updateButton: UIButton = {
let button = UIButton(frame: CGRect(origin: CGPoint(x: 50, y: 50), size: CGSize(width: 150, height: 50)))
button.backgroundColor = UIColor.lightGray
button.addTarget(self, action: #selector(doDelegateMethod), for: .touchUpInside)
return button
}()
var delegate:CustomViewDelegate?
required init?(coder aDecoder: NSCoder) {
fatalError("Pew pew, Aghh!")
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(updateButton)
}
@objc func doDelegateMethod() {
if delegate != nil {
delegate!.update()
} else {
print("Gottfried: I wanted to be a brain surgeon, but I had a bad habit of dropping things")
}
}
}
ViewController:
conformare il controller della vista al delegato della vista: e implementare il metodo del protocollo.
class ViewController: UIViewController, CustomViewDelegate {
let customView = CustomView(frame: CGRect(origin: CGPoint(x: 100, y: 100), size: CGSize(width: 200, height: 200)))
override func viewDidLoad() {
super.viewDidLoad()
customView.backgroundColor = UIColor.red
customView.delegate = self //if delegate is not set, the app will not crash
self.view.addSubview(customView)
}
// Protocol -> UIView Button Action -> View Controller's Method
func update() {
print("Delegating work from View that Conforms to CustomViewDelegate to View Controller")
}
//Protocol > View Controller's Required Implementation
func nonDelegatedMethod() {
//Do something else
}
}
noti che il controller della vista aveva solo conformarsi al delegato e non impostare il selettore di alcune proprietà della vista, questo separa la vista (ed è protocollo) dal controller della vista.
hai già un UIView chiamato toccare Visualizza che eredita da UIView e tappable così l'implementazione potrebbe essere:
Protocollo:
protocol TappableViewDelegate {
func tapGestureDetected(gesture:UITapGestureRecognizer)
}
TappableView:
class TappableView: UIView {
var delegate:TappableViewDelegate?
required init?(coder aDecoder: NSCoder) {
fatalError("Pew pew, Aghh!")
}
override init(frame: CGRect) {
super.init(frame: frame)
let gesture = UITapGestureRecognizer(target: self, action: #selector(doDelegateMethod(gesture:)))
addGestureRecognizer(gesture)
}
@objc func doDelegateMethod(gesture:UITapGestureRecognizer) {
if delegate != nil {
delegate!.tapGestureDetected(gesture: gesture)
} else {
print("Gottfried: I wanted to be a brain surgeon, but I had a bad habit of dropping things")
}
}
}
ViewController:
class ViewController: UIViewController, TappableViewDelegate {
let tapView = TappableView(frame: CGRect(origin: CGPoint(x: 100, y: 100), size: CGSize(width: 200, height: 200)))
override func viewDidLoad() {
super.viewDidLoad()
tapView.backgroundColor = UIColor.red
tapView.delegate = self
self.view.addSubview(tapView)
}
func tapGestureDetected(gesture: UITapGestureRecognizer) {
print("User did tap")
}
}
Potresti pubblicare un esempio compilabile? Come viene dichiarato 'panGestureDetected'? – Sulthan
L'aggiungerò domani, grazie Sulthan – Andrea
@Andrea Cambia Pannable.panGestureDetected (_ :). metti il nome della classe dove viene dichiarato panGestureDetected invece di 'Pannable.whatever' metti 'YourClass.panGestureDetected (_ :) ' –