Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I access private instance variables in Obj-C or Swift?

I'm trying to get access to MKMapSnapshotter's private instance variables _lodpiSnapshotCreator and _hidpiSnapshotCreator in Swift on macOS.

Thanks to class-dump, I know they're there (see here):

@interface MKMapSnapshotter : NSObject
{
    [...]
    VKMapSnapshotCreator *_lodpiSnapshotCreator;
    VKMapSnapshotCreator *_hidpiSnapshotCreator;
}

but no matter what I do, I can't get ahold of them.

This is how I checked whether I could access them or not:

let snapshotter = MKMapSnapshotter(options: snapshotOptions)

let varNames = ["_lodpiSnapshotCreator", "_hidpiSnapshotCreator"]
for varName in varNames {
    if let testIVar = class_getInstanceVariable(MKMapSnapshotter.self, varName) {
        if let test = object_getIvar(snapshotter, testIVar) as? VKMapSnapshotCreator {
            print(test)
        } else {
            print("Got ivar, but \(varName) is still nil (getInstanceVariable)")
        }
    } else {
        print("\(varName) is nil (getInstanceVariable)")
    }
}

Curiously, class_getInstanceVariable doesn't return nil, but object_getIvar does.

Got ivar, but _lodpiSnapshotCreator is still nil (getInstanceVariable)
Got ivar, but _hidpiSnapshotCreator is still nil (getInstanceVariable)

I'm at my wit's end here. All I can find via Google is people recommending the use of class_getInstanceVariable (which I already use) and key-value-coding (which doesn't work at all).

This must have been done before. Can anyone help me out?

Edit: So far, I have tried this:

@interface MKMapSnapshotter() {
    @public VKMapSnapshotCreator *_lodpiSnapshotCreator;
    @public VKMapSnapshotCreator *_hidpiSnapshotCreator;
}

@end

That compiles successfully, but when trying to use it, Swift keeps insisting that the members _lodpiSnapshotCreator and _hidpiSnapshotCreator don't exist.

like image 557
Peter W. Avatar asked Nov 19 '25 09:11

Peter W.


1 Answers

Since we don't have or control the source code we can't change the variables to properties. Just tried this works for your case:

extension MKMapSnapshotter {
   func getPrivateVariable() -> String? {
       return value(forKey: "_lodpiSnapshotCreator") as? String
   }

   open override func value(forUndefinedKey key: String) -> Any? {
       if key == "_lodpiSnapshotCreator" {
           return nil
       }
       return super.value(forUndefinedKey: key)
   }
}

You can find more about this here.

If this does not work then I believe that there is no way to access Objective-C instance variables from Swift. Only Objective-C properties get mapped to Swift properties.

Hope this helps!!

like image 171
Agent Smith Avatar answered Nov 21 '25 09:11

Agent Smith