web-dev-qa-db-fra.com

Annulation du mot clé @available de Objective-C

Je voudrais exécuter un morceau de code uniquement si la version iOS du périphérique actuel est inférieure à une version spécifique, comme spécifié ici . Les exemples de code donnés par Apple ressemblent à ceci:

if (@available(iOS 10.0, *)) {
  // iOS 10.0 and above
} else {
  // below 10.0
}

Cependant, il existe des scénarios dans lesquels on souhaiterait exécuter du code uniquement si la version actuelle d'iOS est inférieure à une version spécifique. J'ai supposé que le code suivant fonctionnerait:

if (!@available(iOS 10.0, *)) {
  // below 10.0
}

Cependant, il semble que cela ne fonctionne pas, et je reçois l'avertissement suivant de Xcode:

@available does not guard availability here; use if (@available) instead

Here est le commit LLVM qui a ajouté le diagnostic que je vois.

Il existe deux solutions de rechange à cette question:

  1. Utilisez la variante if-else sans ajouter de code au bloc if (pas très élégant).
  2. Continuez à utiliser les anciennes approches telles que -[NSProcessInfo isOperatingSystemAtLeastVersion:].

Existe-t-il une autre façon prévue d'utiliser @available qui me manque?

12
StatusReport

L'idée de @available est que vous souhaitez utiliser une API uniquement disponible sur certains systèmes. Pour les autres systèmes, la fonctionnalité est soit manquante dans votre application, soit vous proposez une fonctionnalité alternative. La bonne façon de l'utiliser dans les cas où vous n'avez besoin d'aucun code au-delà d'une certaine version du système d'exploitation, mais uniquement ci-dessous, est

if (@available(iOS 10.0, *)) {
    // Happens automatically on on iOS 10 and beyond
} else {
    someOtherCode();
}

La raison en est que le compilateur doit parfois effectuer un peu plus de magie dans le code protégé par @available et qu'il doit donc clairement reconnaître quand c'est le cas. Donc, en fait, il recherche explicitement 

if (@available(...)) {

avec seulement des variations d'espaces et des sauts de ligne autorisés. Oui, vous pouvez affirmer qu'un seul pas (!) est vraiment compliqué, mais où traceriez-vous la ligne? Qu'en est-il de:

if ((todayIsTuesday() && @available(iOS 9.0, *)) 
    || (self.theWeatherIsNice && !@available(iOS 11.0, *)) {

Ainsi, seules des instructions simples sont autorisées, qui obligent uniquement le compilateur à diviser le code en deux sections et où une seule section sera toujours exécutée avec certitude: une pour les systèmes d'exploitation répertoriés et une pour les autres. Bien entendu, "le reste" peut ensuite être subdivisé à nouveau, else if est autorisé. Seule la section else peut être générée automatiquement si elle manque, donc quand vous écrivez ceci:

if (@available(...)) {
    someCode();
} // There is no else

Le compilateur est également heureux car c’est la même chose que

if (@available(...)) {
     someCode();
} else {
    // Nothing to do here
}
3
Mecki

Vous pouvez définir vos propres macros personnalisées que vous pouvez utiliser dans votre application. Exemple:-

#define isIOS11() ([[UIDevice currentDevice].systemVersion doubleValue]>= 11.0 && [[UIDevice currentDevice].systemVersion doubleValue] < 12.0)

ou 

#define SinceIOS9_2 ([[UIDevice currentDevice].systemVersion doubleValue]>= 4.2 && [[UIDevice currentDevice].systemVersion doubleValue] < 9.2)

Utilisez-le comme ci-dessous: -

if (isIOS11()) {
    // Do something for iOS 11 
} else {
    // Do something iOS Versions below 11.0
}

S'il vous plaît laissez-moi savoir si cela fonctionne pour vous.

1
Jitendra
if (@available ...) {
   ...
} else {
   ...
}

est la seule forme autorisée. Il doit en être ainsi, car des règles différentes s’appliquent dans les parties if et other. Dans la partie if, vous pouvez appeler des méthodes disponibles dans un SDK, dans la partie restante, elles proviennent d'un autre SDK. Le même appel peut être légal dans une branche et illégal dans une autre, ou déconseillé dans une branche et pas dans une autre. 

0
gnasher729