Quel est L'équivalent Swift de respondsToSelector?
j'ai googlé mais je n'ai pas pu trouver ce qu'est l'équivalent swift de respondsToSelector:
.
C'est la seule chose que j'ai pu trouver ( alternative Swift à respondsToSelector: ) mais ce n'est pas très pertinent dans mon cas car elle vérifie l'existence du délégué, Je n'ai pas de délégué je veux juste vérifier si une nouvelle API existe ou non en cours d'exécution sur le périphérique et si ce n'est pas retomber sur une version précédente de l'api.
16 réponses
comme mentionné, dans Swift la plupart du temps, vous pouvez obtenir ce dont vous avez besoin avec l'opérateur ?
optionnel unwrapper . Cela vous permet d'appeler une méthode sur un objet si et seulement si l'objet existe (pas nil
) et que la méthode est implémentée.
dans le cas où vous avez encore besoin de respondsToSelector:
, il est toujours présent dans le cadre du protocole NSObject
.
Si vous appelez respondsToSelector:
sur un Obj-C tapez dans Swift, puis ça fonctionne comme vous vous y attendez. Si vous l'utilisez sur votre propre classe Swift, vous devez vous assurer que votre classe dérive de NSObject
.
voici un exemple de classe Swift que vous pouvez vérifier si elle répond à un sélecteur:
class Worker : NSObject
{
func work() { }
func eat(food: AnyObject) { }
func sleep(hours: Int, minutes: Int) { }
}
let worker = Worker()
let canWork = worker.respondsToSelector(Selector("work")) // true
let canEat = worker.respondsToSelector(Selector("eat:")) // true
let canSleep = worker.respondsToSelector(Selector("sleep:minutes:")) // true
let canQuit = worker.respondsToSelector(Selector("quit")) // false
il est important de ne pas omettre les noms des paramètres. Dans cet exemple, Selector("sleep::")
est et non comme Selector("sleep:minutes:")
.
il n'y a pas de véritable remplacement Swift.
vous pouvez enregistrer de la manière suivante:
someObject.someMethod?()
ceci appelle la méthode someMethod
seulement si elle est définie sur l'objet someObject
mais vous pouvez l'utiliser seulement pour les protocoles @objc
qui ont déclaré la méthode comme optional
.
Swift est intrinsèquement une langue sûre donc chaque fois que vous appelez une méthode Swift doit savoir que la méthode est là. Pas de contrôle d'exécution est possible. Vous ne pouvez pas appeler des méthodes aléatoires sur des objets aléatoires.
Même en Obj-C, vous devriez éviter de telles choses lorsque cela est possible parce qu'il ne joue pas bien avec de l'ARC (ARC déclenche alors des avertissements pour les performSelector:
).
cependant, lors de la vérification des API disponibles, vous pouvez toujours utiliser respondsToSelector:
, même si Swift, si vous avez affaire à des NSObject
instances:
@interface TestA : NSObject
- (void)someMethod;
@end
@implementation TestA
//this triggers a warning
@end
var a = TestA()
if a.respondsToSelector("someMethod") {
a.someMethod()
}
mise à jour du 20 mars 2017 pour la syntaxe Swift 3:
si vous ne vous souciez pas si la méthode optionnelle existe, appelez simplement delegate?.optionalMethod?()
sinon, utiliser guard
est probablement la meilleure approche:
weak var delegate: SomeDelegateWithOptionals?
func someMethod() {
guard let method = delegate?.optionalMethod else {
// optional not implemented
alternativeMethod()
return
}
method()
}
réponse originale:
, Vous pouvez utiliser le "laissé" approche pour tester un protocole facultatif comme ceci:
weak var delegate: SomeDelegateWithOptionals?
func someMethod() {
if let delegate = delegate {
if let theMethod = delegate.theOptionalProtocolMethod? {
theMethod()
return
}
}
// Reaching here means the delegate doesn't exist or doesn't respond to the optional method
alternativeMethod()
}
il semble que vous ayez besoin de définir votre protocole comme un sous-protocole de NSObjectProtocol ... vous obtiendrez alors la méthode respondsToSelector
@objc protocol YourDelegate : NSObjectProtocol
{
func yourDelegateMethod(passObject: SomeObject)
}
notez qu'il ne suffit pas de spécifier @objc. Vous devez également veiller à ce que le délégué réel soit une sous - classe de NSObject-ce qui n'est peut-être pas le cas dans Swift.
si la méthode que vous testez est définie comme une méthode optionnelle dans un @objc protocole (qui ressemble à votre cas), puis utiliser le chaîne optionnelle motif comme:
if let result = object.method?(args) {
/* method exists, result assigned, use result */
}
else { ... }
lorsque la méthode est déclarée comme retournant Void
, il suffit d'utiliser:
if object.method?(args) { ... }
voir:
" Méthodes D'Appel Optionnelles Chaînage "
Extrait De: Apple Inc. "Le Langage De Programmation Swift."
iBooks. https://itun.es/us/jEUH0.l
les fonctions sont de premier ordre dans Swift, vous pouvez donc vérifier si une fonction optionnelle définie dans un protocole a été implémentée en la comparant à nil:
if (someObject.someMethod != nil) {
someObject.someMethod!(someArgument)
} else {
// do something else
}
dans Swift 2,Apple a introduit une nouvelle fonctionnalité appelée API availability checking
, qui pourrait remplacer la méthode respondsToSelector:
.La comparaison d'extraits de code suivante est copiée de la session 106 de la WWDC2015 Quoi de neuf dans Swift qui pourrait vous aider,s'il vous plaît vérifiez si vous avez besoin d'en savoir plus.
L'Ancienne Approche:
@IBOutlet var dropButton: NSButton!
override func awakeFromNib() {
if dropButton.respondsToSelector("setSpringLoaded:") {
dropButton.springLoaded = true
}
}
La Meilleure Approche:
@IBOutlet var dropButton: NSButton!
override func awakeFromNib() {
if #available(OSX 10.10.3, *) {
dropButton.springLoaded = true
}
}
pour swift3
si vous voulez simplement appeler la méthode, lancez le code ci-dessous.
self.delegate?.method?()
actuellement (Swift 2.1), vous pouvez le vérifier en utilisant 3 méthodes:
- en utilisant repondstoselector answered by @Erik_at_Digit
-
par "?' , a répondu par @Sulthan
-
et en utilisant
as?
opérateur:if let delegateMe = self.delegate as? YourCustomViewController { delegateMe.onSuccess() }
fondamentalement, cela dépend de ce que vous essayez d'atteindre:
- si par exemple votre logique app doit effectuer une action et que le délégué n'est pas défini ou que le délégué pointé n'a pas implémenté la méthode onSuccess () (méthode de protocole) donc les options 1 et 3 sont le meilleur choix, bien que j'utilise l'option 3 qui est Swift way.
- si vous ne voulez rien faire lorsque délégué est nul ou que la méthode n'est pas implémentée, utilisez l'option 2.
pour swift 3.0
import UIKit
@objc protocol ADelegate : NSObjectProtocol {
@objc optional func hi1()
@objc optional func hi2(message1:String, message2:String)
}
class SomeObject : NSObject {
weak var delegate:ADelegate?
func run() {
// single method
if let methodHi1 = delegate?.hi1 {
methodHi1()
} else {
print("fail h1")
}
// multiple parameters
if let methodHi2 = delegate?.hi2 {
methodHi2("superman", "batman")
} else {
print("fail h2")
}
}
}
class ViewController: UIViewController, ADelegate {
let someObject = SomeObject()
override func viewDidLoad() {
super.viewDidLoad()
someObject.delegate = self
someObject.run()
}
// MARK: ADelegate
func hi1() {
print("Hi")
}
func hi2(message1: String, message2: String) {
print("Hi \(message1) \(message2)")
}
}
je viens de mettre en œuvre moi-même dans un projet, voir code ci-dessous. Comme le mentionne @Christopher Pickslay, il est important de se rappeler que les fonctions sont des citoyens de première classe et peuvent donc être traitées comme des variables optionnelles.
@objc protocol ContactDetailsDelegate: class {
optional func deleteContact(contact: Contact) -> NSError?
}
...
weak var delegate:ContactDetailsDelegate!
if let deleteContact = delegate.deleteContact {
deleteContact(contact)
}
une autre syntaxe possible de swift..
if let delegate = self.delegate, method = delegate.somemethod{
method()
}
alors que j'ai commencé à mettre à jour mon ancien projet vers Swift 3.2, j'ai juste eu besoin de changer la méthode de
respondsToSelector(selector)
à:
responds(to: selector)
j'utilise guard let else
, donc cela peut faire quelques trucs par défaut si la func déléguée n'est pas implémentée.
@objc protocol ViewController2Delegate: NSObjectProtocol {
optional func viewController2(controller: ViewController2, didSomethingWithStringAndReturnVoid string: String)
optional func viewController2(controller: ViewController2, didSomethingWithStringAndReturnString string: String) -> String
}
class ViewController2: UIViewController {
weak var delegate: ViewController2Delegate?
@IBAction func onVoidButtonClicked(sender: AnyObject){
if (delegate != nil && delegate!.respondsToSelector(Selector("viewController2:didSomethingWithStringAndReturnVoid:"))) {
NSLog("ReturnVoid is implemented")
delegate!.viewController2!(self, didSomethingWithStringAndReturnVoid: "dummy")
}
else{
NSLog("ReturnVoid is not implemented")
// Do something by default
}
}
@IBAction func onStringButtonClicked(sender: AnyObject){
guard let result = delegate?.viewController2?(self, didSomethingWithStringAndReturnString: "dummy") else {
NSLog("ReturnString is not implemented")
// Do something by default
return
}
NSLog("ReturnString is implemented with result: \(result)")
}
}
Swift 3:
protocole
@objc protocol SomeDelegate {
@objc optional func method()
}
objet
class SomeObject : NSObject {
weak var delegate:SomeObject?
func delegateMethod() {
if let delegateMethod = delegate?.method{
delegateMethod()
}else {
//Failed
}
}
}
l'équivalent est le ? exploitant:
var value: NSNumber? = myQuestionableObject?.importantMethod()
méthode importante ne sera appelée que si myquestionabject existe et l'implémente.