Snelle native basisklasse of NSObject

Ik heb wat isa swizzlingmet Swift uitgeprobeerd en ontdekte dat het alleen werkt als NSObject een superklasse is ( direct of verder naar boven), of door de versiering ‘@objc’ te gebruiken. Anders zal het een statische en vtable-verzendstijl volgen, zoals C++.

Is het normaal om een ​​Swift-klasse te definiëren zonder een Cocoa/NSObject-basisklasse? Als ik me zorgen maak, betekent dit dat we veel van de dynamiek van Objective-C moeten missen, zoals het onderscheppen van methoden en runtime-introspectie.

Dynamisch runtime-gedrag vormt de kern van functies zoals eigendomswaarnemers, kerngegevens, Aspect-georiënteerd Programmering, Hogere Orde Messaging, analytisch & logging-frameworks enzovoort.

Het gebruik van Objective-C’s stijl van methodeaanroep voegt ongeveer 20 machinecode-operands toe aan een methodeaanroep, dus in bepaalde situaties (veel strakke aanroepen naar methoden met kleine lichamen) C++-stijl statische en vtable verzending kan beter presteren.

Maar gezien de algemene 95-5-regel (95% van de prestatiewinst komt van het afstemmen van 5% van de code), is het dan niet logisch om te beginnen met de krachtige dynamische functies en uit te harden waar vereist?


Antwoord 1, autoriteit 100%

Snelle klassen die subklassen zijn van NSObject:

  • zijn zelf Objective-C-klassen
  • gebruik objc_msgSend()voor aanroepen naar (de meeste van) hun methoden
  • voorzie Objective-C runtime-metadata voor (de meeste van) hun methode-implementaties

Snelle klassen die geen subklassen zijn van NSObject:

  • zijn Objective-C-klassen, maar implementeren slechts een handvol methoden voor NSObject-compatibiliteit
  • gebruik objc_msgSend()niet voor het aanroepen van hun methoden (standaard)
  • geef geen Objective-C runtime-metadata voor hun methode-implementaties (standaard)

Door NSObject in Swift onder te classificeren, krijgt u Objective-C runtime-flexibiliteit, maar ook Objective-C-prestaties. Het vermijden van NSObject kan de prestaties verbeteren als u de flexibiliteit van Objective-C niet nodig hebt.

Bewerken:

Met Xcode 6 beta 6 verschijnt het dynamische kenmerk. Hierdoor kunnen we Swift instrueren dat een methode dynamische verzending moet gebruiken en dus onderschepping zal ondersteunen.

public dynamic func foobar() -> AnyObject {
}

Antwoord 2, autoriteit 12%

Ik ontdekte ook dat als ik een Swift-klasse op NSObject baseerde, ik onverwacht runtime-gedrag zag dat codeerfouten kon verbergen. Hier is een voorbeeld.

In dit voorbeeld, waar we nietbaseren op NSObject, detecteert de compiler de fout correct in testIncorrect_CompilerShouldSpot,
rapportage “… ‘MyClass’ kan niet worden omgezet in ‘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
      }
  }
}

In dit voorbeeld, waar we uitgaan van NSObject, vindt de compiler nietde fout in 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
      }
  }
}

Ik denk dat de moraal is: baseer alleen op NSObject waar het echt moet!


Antwoord 3, autoriteit 12%

Volgens de taalreferentie is er geen vereiste voor klassen om een ​​standaard rootklasse te subclasseren, dus u kunt een superklasse opnemen of weglaten als dat nodig is.

Houd er rekening mee dat het weglaten van een superklasse uit de klassedeclaratie geen impliciete basissuperklasse van welke aard dan ook toewijst. Het definieert een basisklasse, die in feite de basis zal worden voor een onafhankelijke klassenhiërarchie.

Van de taalreferentie:

Swift-klassen erven niet van een universele basisklasse. geeft les aan jou
definiëren zonder een superklasse op te geven, wordt automatisch basis
lessen waarop u kunt voortbouwen.

Proberen te verwijzen naar supervan een klasse zonder een superklasse (d.w.z. een basisklasse) zal resulteren in een compileerfout

'super' members cannot be referenced in a root class

Antwoord 4, autoriteit 2%

Het volgende is gekopieerd uit Apple’s Swift-eBook en geeft een passend antwoord op je vraag:

Een basisklasse definiëren

Elke klasse die niet van een andere klasse erft, staat bekend als een basisklasse.

Swift-klassen erven niet van een universele basisklasse. Klassen die u definieert zonder een superklasse op te geven, worden automatisch basisklassen waarop u kunt voortbouwen.

Referentie

https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Inheritance.html#//apple_ref/doc/uid /TP40014097-CH17-XID_251


Antwoord 5

Ik geloof dat de overgrote meerderheid van Swift-gegevens niet objczal zijn. Alleen die delen die wel moeten communiceren met de Objective C-infrastructuur worden expliciet als zodanig gemarkeerd.

In hoeverre runtime-introspectie aan de taal wordt toegevoegd, weet ik niet. Het onderscheppen van methoden wordt waarschijnlijk alleen mogelijk als de methode dit expliciet toestaat. Dit is mijn gok, maar alleen de taalontwerpers binnen Apple weten echt waar ze naartoe gaan.


Antwoord 6

Het is normaal. Kijk naar de ontwerpdoelen van Swift: Het doel is om enorme klassen programmeerproblemen te laten verdwijnen. Method swizzling is waarschijnlijk niet een van de dingen die je met Swift wilt doen.

Other episodes