Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
346 views
in Technique[技术] by (71.8m points)

protocols - 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...