Mirroring objects quickly by iterating through their memory. Will this break once shipped?

Long story short, I need to get all the property wrappers in an object. Many such objects are created, and mirroring is too slow. Returning a list of the property wrappers manually from the object worked, but was tedious, and the list required updating alongside the properties of the object, which occasionally led to annoying bugs.

My solution was to mirror one instance of the object, then for each relevant property, run the following function:

static func makeInstanceVariableGetter<Base: AnyObject, IVar: AnyObject>(object: Base, ivar: IVar) -> (Base) -> IVar {
    let objectPtr = Unmanaged.passUnretained(object).toOpaque()
    let ivarPtr = UInt(bitPattern: Unmanaged.passUnretained(ivar).toOpaque())

    var searchPtr = objectPtr
    while searchPtr.load(as: UInt.self) != ivarPtr {
        searchPtr = searchPtr.advanced(by: MemoryLayout<UInt>.stride)
    }

    let offset = objectPtr.distance(to: searchPtr)
    let result: (Base) -> IVar = {
        let ivarPtr = Unmanaged.passUnretained($0).toOpaque().advanced(by: offset)
        return Unmanaged.fromOpaque(UnsafeRawPointer(bitPattern: ivarPtr.load(as: UInt.self))!).takeUnretainedValue()
    }
    assert(result(object) === ivar)
    return result
}

and then store these getters to a a cache.

I know this is terrible, but how terrible is it? Can I ship this in an app without worrying about it breaking randomly?

It is not safe to directly read or write to class properties without going through their accessors. If you want a function to access an ivar, you can use a closure like { $0.property }.

Hi @Joe_Groff,

Is there an easy way to get a list of said closures from an object, or a class?

For context, I'm writing a middleware framework where the programmer defines subclasses of my Magic root class, and wraps properties that they wish for the middleware to manage in my MagicProperty property wrapper.

For the middleware to do its job, it needs a dictionary of all the MagicProperty properties of some subclass of Magic. I'd been using Mirror for this, but was running into some performance problems mirroring each object each time it is created. The obvious solution is to just have the programmer return a dictionary of their defined Magic properties, but this is less than optimal ergonomically, as the dictionary must be updated in parallel with the object's properties.

So, I was looking for a way to iterate over all of these @propertyWrappers more quickly. Can you elaborate on the safety problems reading these @propertyWrapper MagicProperty objects from their parent?

The easiest way is Mirror. If it's too expensive, you might look at some of the libraries that frameworks like Vapor use to interpret Swift runtime data structures directly. You could also try caching the result of traversing the mirror children of one object of any type, since for a class or struct, the set of children should be constant across instances.

For anyone stumbling across this thread, I found the excellent-looking Runtime library, which is definitely more polished than my solution: https://github.com/wickwirew/Runtime

Terms of Service

Privacy Policy

Cookie Policy