How can I override the description property of NSObject when subclassing in Swift?

2.5k Views Asked by At

I am subclassing NSObject in order to have an ordered collection that is accessible to Cocoa Bindings. My class looks more or less like this:

public class OrderedCollection<Tk: Hashable, Tv>  : NSObject {

    var keys: Array<Tk> = []
    var values: Dictionary<Tk,Tv> = [:]

    override init() {
        super.init()
    }

    // Subscript methods go here

    override public var description: String {
            var result = "{\n"
            for i in 0..<self.count {
                result += "[\(i)]: \(self.keys[i]) => \(self[i]!)\n"
            }
            result += "}"
            return result

    }  

}

It doesn't compile. The error says: '@objc' getter for non-'@objc' property.

Is there a way of making the getter non-'@objc' as it were? I don't need the property to be accessible from Objective-C...

2

There are 2 best solutions below

0
On

It seems the answer was in the comments of an entirely different question. https://stackoverflow.com/a/26688572/4180258

Essentially, there is a bit of an ugly workaround:

class BaseNSObjectWithDescriptionFix: NSObject {
 func makeDescription() -> String {
   return super.description
 }

 override var description: String {
   return makeDescription()
 }
}

Now you just use BaseNSObjectWithDescriptionFix instead of NSObject and override makeDescription as you like.

In my case, I didn't need it because for my purposes I could use [String] and [String:AnyObject], but this may be of some use to someone in the future.

0
On

To override the description property of NSObject when subclassing in Swift, with two generic types like you have and keeping your class public, you just need this:

public class OrderedCollection<Tk: Hashable, Tv>: NSObject {    
    override public var description: String {
        return "hello"
    }
}

You could also, instead, conform to the CustomStringConvertible protocol (formerly, pre-Swift 2, known as Printable) and forget NSObject, like so:

public class OrderedCollection<Tk: Hashable, Tv>: CustomStringConvertible {

    public var description: String {
        return "hello"
    }
}

In other words, generics don't really change anything for this case. (Not sure if things were different in an earlier version of Swift...)

The content of description I leave to you (e.g. you don't have a count property above, so I'm guessing you omitted more code than just subscript methods).