web-dev-qa-db-fra.com

Lien faible - vérifiez si une classe existe et utilisez cette classe

J'essaie de créer une application iPhone universelle, mais elle utilise une classe définie uniquement dans une version plus récente du SDK. Le framework existe sur les anciens systèmes, mais pas une classe définie dans le framework.

Je sais que je veux utiliser une sorte de liaison faible, mais toute documentation que je peux trouver parle de vérifications d'exécution de l'existence de la fonction - comment puis-je vérifier qu'une classe existe?

86
psychotik

TLDR

Courant:

  • Swift : if #available(iOS 9, *)
  • Obj-C, iOS : if (@available(iOS 11.0, *))
  • Obj-C, OS X : if (NSClassFromString(@"UIAlertController"))

Héritage:

  • Swift (versions antérieures à 2.0) : if objc_getClass("UIAlertController")
  • Obj-C, iOS (versions antérieures à 4.2) : if (NSClassFromString(@"UIAlertController"))
  • Obj-C, iOS (versions antérieures à 11.0) : if ([UIAlertController class])

Swift 2+

Bien qu'historiquement, il ait été recommandé de vérifier les capacités (ou l'existence de classe) plutôt que les versions spécifiques du système d'exploitation, cela ne fonctionne pas bien dans Swift 2.0 en raison de l'introduction de vérification de la disponibilité .

Utilisez plutôt cette méthode:

if #available(iOS 9, *) {
    // You can use UIStackView here with no errors
    let stackView = UIStackView(...)
} else {
    // Attempting to use UIStackView here will cause a compiler error
    let tableView = UITableView(...)
}

Remarque: Si vous essayez plutôt d'utiliser objc_getClass(), vous obtiendrez l'erreur suivante:

⛔️ 'UIAlertController' n'est disponible que sur iOS 8.0 ou plus récent.


Versions précédentes de Swift

if objc_getClass("UIAlertController") != nil {
    let alert = UIAlertController(...)
} else {
    let alert = UIAlertView(...)
}

Notez que objc_getClass()est plus fiable que NSClassFromString() ou objc_lookUpClass() .


Objective-C, iOS 4.2+

if ([SomeClass class]) {
    // class exists
    SomeClass *instance = [[SomeClass alloc] init];
} else {
    // class doesn't exist
}

Voir réponse du code007 pour plus de détails .


OS X ou versions précédentes d'iOS

Class klass = NSClassFromString(@"SomeClass");
if (klass) {
    // class exists
    id instance = [[klass alloc] init];
} else {
    // class doesn't exist
}

Utilisez NSClassFromString() . S'il renvoie nil, la classe n'existe pas, sinon il renverra l'objet de classe qui peut être utilisé.

C'est la manière recommandée selon Apple in ce document :

[...] Votre code testerait l'existence d'une [a] classe en utilisant NSClassFromString() qui retournera un objet de classe valide si [la] classe existe ou nil si ce n'est pas le cas. Si la classe existe, votre code peut l'utiliser [...]

161
Senseful

Pour les nouveaux projets qui utilisent un SDK de base d'iOS 4.2 ou version ultérieure, il existe cette nouvelle approche recommandée qui consiste à utiliser la méthode de classe NSObject pour vérifier la disponibilité des classes faiblement liées au moment de l'exécution. c'est à dire.

if ([UIPrintInteractionController class]) {
    // Create an instance of the class and use it.
} else {
    // Alternate code path to follow when the
    // class is not available.
}

source: https://developer.Apple.com/library/content/documentation/DeveloperTools/Conceptual/cross_development/Using/using.html#//Apple_ref/doc/uid/20002000-SW

Ce mécanisme utilise la macro NS_CLASS_AVAILABLE, qui est disponible pour la plupart des frameworks dans iOS (notez qu'il peut y avoir des frameworks qui ne prennent pas encore en charge NS_CLASS_AVAILABLE - vérifiez le Note de version iOS pour cela). Une configuration supplémentaire des paramètres peut également être nécessaire, ce qui peut être lu dans le lien de documentation d'Apple fourni ci-dessus, cependant, l'avantage de cette méthode est que vous obtenez une vérification de type statique.

69
code007