Thursday, July 23, 2015

Dynamic Swift

Lee Morgan:

We’ll go ahead and extend our KVC protocol and add our default implementation.

extension KVC {
    
    func valueForKey(key : String) -> Any? {
    
        let mirror = reflect(self)
        
        for index in 0 ..< mirror.count {
            let (childKey, childMirror) = mirror[index]
            if childKey == key {
                return childMirror.value
            }
        }
        return nil
    }
}

David Owens II has a different implementation that also handles setting values:

As you might be gathering, the basic premise is to use a backing store to maintain our values and type information. The implementation can then verify that the data coming in is correct.

David Owens II:

But wait… if we can shadow the functions and replace them with our own implementations, then this means that method swizzling is back on the table!

There are several caveats, though.

Adrian Kashivskyy:

Remember that reflection in Swift is currently read-only and there’s no way to modify your program at runtime (with Objective-C-derived classes being an exception as you can still class_addMethod() in Swift).

Brent Simmons asks how to instantiate an arbitrary class at runtime.

David Owens II:

The same way as C++, an ugly switch statement!

Wil Shipley:

On the latest Swift you have to add the word “init” to make this more explicit. Then it works. e.g:

let a:P = clsA.init(i:1)

Brent Simmons:

Jim takes this one step further: what if all you have is the class name as a string?

Alas, that’s currently only possible using Objective-C classes. There is no NSClassFromString() for Swift. [Update (2015-07-23): Actually, there is. See the comments below.]

David Owens II:

Xcode 7 Beta 4 is out and it is a doozy! One of the changes is that performSelector is now available from Swift. Now, this isn’t going to make your Swift types dynamic all of a sudden. However, what it does open the door for, is writing both your ObjC-style code and your Swift code all in the same language: Swift.

Brent Simmons:

Here’s the deal I’m willing to make: to make my code more elegant (read: smaller, easier to maintain, reusable), I’m willing to let it crash if I’ve configured things incorrectly.

[…]

So my case is that Swift itself needs things like this. If not a clone of KVC, then something very much like it.

Rob Rhyne:

When Apple announced the Swift programming language in 2014, there were questions about the future of frameworks that depended heavily on the dynamic nature of Objective-C. Frameworks such as Core Data marshall objects with type dependencies determined at runtime. The strict type checks required by the Swift compiler appeared in conflict with Core Data.

[…]

It turns out the answer to one question begat the solution to the other. By turning this class extension into a protocol and with a clever use of typealias, I resolved the insidious casting problem while maintaining type safety. Protocols to the rescue!

In other words, there are ways to use Core Data from Swift in a type-safe way. But it would still be impossible to write Core Data itself in pure Swift.

9 Comments RSS · Twitter

Michael,

I have a post at

http://www.spanware.com/blog/index.html

which describes a truly dynamic way to create an object factory in Swift whose subclasses are unknown at runtime.

@David Cool. But is it documented that NSClassFromString() can look up Swift classes if you prefix their names? Seems like you are relying on an implementation detail.

Very interesting that NSClassFromString() actually works on native-Swift classes. I wouldn't even have thought to try that as I would have been sure that it wouldn't work.

@Michael, I'm pretty sure the ModuleName.ClassName is standard.

Maybe the Swift team is unifying the runtime models more than I had anticipated.

@DavidOwens Yes, I think the naming is standard. My question is: are they intentionally unifying the runtime models? Or does this accidentally work because they reused some code? Any idea what happens if you do this with generics?

Joe Groff:

Yeah, all Swift classes get registered with the ObjC runtime.

One limitation: classes with generic heritage won’t be registered until they’re used from Swift

This is an intentional part of the design, and should have been working since Swift 1 for simple swift classes.

Joe,

Can you clarify what you mean by not being registered until used?

@Chris That’s great to hear!

[…] Previously: The Case for Message Passing in Swift, “It’s a Coup”, Dynamic Swift. […]

Leave a Comment