Swift native base class or NSObject

Objective CSwiftObjective C-Runtime

Objective C Problem Overview


I tested out some isa swizzling with Swift, and found that it only works when NSObject is a super-class (directly or further up), or by using the '@objc' decoration. Otherwise it will follow a static- and vtable-dispatch style, like C++.

Is it normal to define a Swift class without a Cocoa/NSObject base class? If it is I'm concerned this means foregoing much of the dynamism of Objective-C, such as method interception and run-time introspection.

Dynamic run-time behavior sits at the heart of features like property observers, Core Data, Aspect Oriented Programming, Higher Order Messaging, analytical & logging frameworks and so on.

Using Objective-C's style of method invocation adds around 20 machine code operands to a method call, so in certain situations (many tight calls to methods with small bodies) C++ style static and vtable dispatch can perform better.

But given the general 95-5 rule (95% of performance gains come from tuning 5% of the code), doesn't it makes sense to start with the powerful dynamic features and harden where necessary?

Objective C Solutions


Solution 1 - Objective C

Swift classes that are subclasses of NSObject:

  • are Objective-C classes themselves
  • use objc_msgSend() for calls to (most of) their methods
  • provide Objective-C runtime metadata for (most of) their method implementations

Swift classes that are not subclasses of NSObject:

  • are Objective-C classes, but implement only a handful of methods for NSObject compatibility
  • do not use objc_msgSend() for calls to their methods (by default)
  • do not provide Objective-C runtime metadata for their method implementations (by default)

Subclassing NSObject in Swift gets you Objective-C runtime flexibility but also Objective-C performance. Avoiding NSObject can improve performance if you don't need Objective-C's flexibility.

Edit:

With Xcode 6 beta 6, the dynamic attribute appears. This allows us to instruct Swift that a method should use dynamic dispatch, and will therefore support interception.

public dynamic func foobar() -> AnyObject {
}

Solution 2 - Objective C

I also found that if basing a Swift class on NSObject, I saw some unexpected run-time behaviour that could hide coding bugs. Here is an example.

In this example, where we don't base on NSObject, the compiler correctly spots the error in testIncorrect_CompilerShouldSpot, reporting "... 'MyClass' is not convertible to '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 this example, where we base on NSObject, the compiler doesn't spot the error 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
      }
  }
}

I guess the moral is, only base on NSObject where you really have to!

Solution 3 - Objective C

According to the language reference, there is no requirement for classes to subclass any standard root class, so you can include or omit a superclass as needed.

Note that omitting a superclass from the class declaration, doesn't assign a implicit base superclass of any kind. It defines a base class, which will effectively become the root for an independent class hierarchy.

From the language reference:

> Swift classes do not inherit from a universal base class. Classes you > define without specifying a superclass automatically become base > classes for you to build upon.

Trying to reference super from a class without a super class (i.e. a base class) will result in a compile time error

'super' members cannot be referenced in a root class

Solution 4 - Objective C

The following is copied from Apple's Swift-eBook and gives an appropriate answer to your question:

Defining a Base-Class

Any class that does not inherit from another class is known as a base class.

Swift classes do not inherit from a universal base class. Classes you define without specifying a superclass automatically become base classes for you to build upon.


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

Solution 5 - Objective C

I believe that the vast majority of Swift data will not be objc. Only those parts that do need to communicate with te Objective C infrastructure will be explicitly marked as such.

To which extent runtime introspection will be added to the language, I do not know. Method interception will likely become only possible if the method explicitly allows it. This is my guess, but only the language designers within Apple really know where they are really heading.

Solution 6 - Objective C

It is normal. Look at the design goals of Swift: The goal is to make huge classes of programming problems disappear. Method swizzling is probably not one of the things that you want to do with Swift.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJasper BluesView Question on Stackoverflow
Solution 1 - Objective CGreg ParkerView Answer on Stackoverflow
Solution 2 - Objective CPeteView Answer on Stackoverflow
Solution 3 - Objective CCezarView Answer on Stackoverflow
Solution 4 - Objective CzomaView Answer on Stackoverflow
Solution 5 - Objective CAnalog FileView Answer on Stackoverflow
Solution 6 - Objective Cgnasher729View Answer on Stackoverflow