Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to add an extension to AnyObject?

In Objective-C, I created a very handy category (an extension, in Swift terms) of NSObject that added the ability to add arbitrary key/value pairs to any NSObject at runtime. It uses associated objects to attach a mutable dictionary to the object, and then provides get and set methods that get/set key/value pairs to/from that dictionary. It's only a few lines of code.

This makes it possible to attach arbitrary key/value pairs to ANY object at runtime, including objects created by the system. That's the key. There are cases where a system framework returns an object to you and you need to be able to attach a value to it.

This trick also makes it possible to create categories that have new instance variables. (Ok, they don't really, but for it does let you add new state variables to objects in a category.)

This isn't possible in Swift 1.2 because:

  • Swift doesn't have a base class for all objects like NSObject in Objective-C. It uses AnyObject, which is a protocol.
  • Swift 1.2 doesn't allow extensions to protocols.

I had to give up on this under Swift 1.2.

But Swift 2 allows extensions to protocols. I thought "Great, now I can add my extension that lets me add key/value pairs to AnyObject!"

No joy.

When I try to create my extension for AnyObject:

extension AnyObject: AssociatedObjectProtocol

I get the error message

'AnyObject' Protocol cannot be extended

Arghh! So close, but nope. It seems like the language explicitly forbids extending AnyObject. Why is this, and is there any way around it?

I don't use my category on NSObject that often, but when I do, it's a lifesaver. I'd like to add it to my bag of tricks in Swift.

I could add it to NSObject just like I do in Objective-C, but that means it only works for objects that inherit from NSObject - making it not work for native Swift classes.

like image 740
Duncan C Avatar asked Aug 12 '15 19:08

Duncan C


Video Answer


1 Answers

Unfortunately a workaround which does exactly the same as you want doesn't exist. So I would suggest to make a protocol which has an extension to add default implementations:

protocol A: AnyObject {}

// in Swift you would rather use this
protocol A: class {}

// add default implementations
extension A {
    func aMethod() {
        // code
    }
}

// Example
class B: A {}

// use the method
B().aMethod()

This approach does not make all classes automatically conform to this protocol (but only classes can conform to it). So you have to make them conform yourself. Since you don't use this as much this would be a reasonable solution.

like image 121
Qbyte Avatar answered Sep 21 '22 19:09

Qbyte