web-dev-qa-db-fra.com

Swift classe de base native ou NSObject

J'ai testé quelques isa swizzling avec Swift et ai constaté que cela ne fonctionne que lorsque NSObject est une super-classe (directement ou ultérieurement), ou en utilisant la décoration '@objc'. Sinon, il suivra un style de dispatch statique et vtable, comme C++.

Est-il normal de définir une classe Swift sans classe de base Cocoa/NSObject? Si cela me concerne, cela signifie renoncer à une grande partie du dynamisme d'Objective-C, comme les méthodes d'interception et d'exécution introspection.

Le comportement dynamique de l'exécution est au cœur de fonctionnalités telles que les observateurs de propriétés, les données de base, programmation orientée aspect , messagerie d'ordre supérieur , les cadres d'analyse et de journalisation, etc.

L'utilisation du style d'invocation de méthode d'Objective-C ajoute environ 20 opérandes de code machine à un appel de méthode. Ainsi, dans certaines situations (, de nombreux appels restreints à des méthodes comportant des petits corps ) Les commandes statiques et vtable de style C++ peuvent être plus performantes.

Mais étant donné la règle générale 95-5 (, 95% des gains de performance proviennent du réglage de 5% du code ), n’est-il pas logique de commencer avec les puissantes fonctionnalités dynamiques et durcir si nécessaire?

98
Jasper Blues

Les classes Swift qui sont des sous-classes de NSObject:

  • sont les classes Objective-C elles-mêmes
  • utiliser objc_msgSend() pour les appels vers (la plupart de) leurs méthodes
  • fournir des métadonnées d'exécution Objective-C pour la plupart des implémentations de méthodes

Les classes Swift qui ne sont pas des sous-classes de NSObject:

  • sont des classes Objective-C, mais n'implémentent qu'une poignée de méthodes pour la compatibilité avec NSObject
  • n'utilisez pas objc_msgSend() pour les appels à leurs méthodes (par défaut)
  • ne fournit pas de métadonnées d'exécution Objective-C pour leurs implémentations de méthodes (par défaut)

Sous-classer NSObject dans Swift vous offre une flexibilité d'exécution Objective-C, mais également des performances Objective-C. Éviter NSObject peut améliorer les performances si vous n'avez pas besoin de la flexibilité d'Objective-C.

Edit:

Avec Xcode 6 beta 6, l'attribut dynamique apparaît. Cela nous permet d’indiquer à Swift) qu’une méthode doit utiliser la répartition dynamique et prend donc en charge l’interception.

public dynamic func foobar() -> AnyObject {
}
98
Greg Parker

J'ai également constaté que si je basais une classe Swift sur NSObject, je voyais un comportement inattendu à l'exécution qui pourrait masquer des bogues de code. Voici un exemple.

Dans cet exemple, où ne ne basons pas sur NSObject, le compilateur repère correctement l'erreur dans testIncorrect_CompilerShouldSpot, en signalant "... 'MyClass' n'est pas convertible en 'MirrorDisposition' "

class MyClass {
  let mString = "Test"

  func getAsString() -> String {
    return mString
  }

  func testIncorrect_CompilerShouldSpot() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject == myString) {
        // Do something
      }
  }

  func testCorrect_CorrectlyWritten() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject.getAsString() == myString) {
        // Do something
      }
  }
}

Dans cet exemple, où nous nous basons sur NSObject , le compilateur ne fonctionne pas repérez l’erreur dans testIncorrect_CompilerShouldSpot:

class myClass : NSObject {
  let mString = "Test"

  func getAsString() -> String {
    return mString
  }

  func testIncorrect_CompilerShouldSpot() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject == myString) {
        // Do something
      }
  }

  func testCorrect_CorrectlyWritten() {
    var myString = "Compare to me"
      var myObject = MyClass()
      if (myObject.getAsString() == myString) {
        // Do something
      }
  }
}

J'imagine que la morale est que vous devez uniquement vous baser sur NSObject!

14
Pete

Selon la référence du langage, il n'est pas nécessaire que les classes sous-classent une classe racine standard. Vous pouvez donc inclure ou omettre une superclasse selon vos besoins.

Notez que l'omission d'une superclasse de la déclaration de classe n'affecte aucune superclasse de base implicite. Il définit une classe de base, qui deviendra effectivement la racine d'une hiérarchie de classes indépendante.

De la référence de langue:

Les classes Swift n'héritent pas d'une classe de base universelle. Les classes que vous définissez sans spécifier de superclasse deviennent automatiquement des classes de base sur lesquelles vous pouvez vous appuyer.

Essayer de référencer super à partir d'une classe sans super classe (c'est-à-dire une classe de base) entraînera une erreur lors de la compilation

'super' members cannot be referenced in a root class
12
Cezar

Je pense que la grande majorité des données Swift ne seront pas objc. Seules les parties qui doivent communiquer avec l’infrastructure Objective C seront explicitement désignées comme telles.

Dans quelle mesure l'introspection à l'exécution sera ajoutée à la langue, je ne le sais pas. L'interception de méthode ne deviendra probablement possible que si la méthode le permet explicitement. C’est ce que je suppose, mais seuls les concepteurs de langage au sein de Apple) savent vraiment dans quelle direction ils se dirigent.

1
Analog File