How to access private members of an Objective-C class from a Swift extension?
Asked Answered
S

2

8

I'm trying to extend an Objective-C class in Swift and make it conform to the Equatable protocol. This requires to access some private members of the extended class, which the compiler doesn't let me do. What is the correct way to do it without making the private members public?

My Swift code:

import Foundation

extension ShortDate : Equatable {  }

public func == (lhs: ShortDate, rhs: ShortDate) -> Bool {
    if (lhs.components.year == rhs.components.year)
        && (lhs.components.month == rhs.components.month)
        && (lhs.components.day == rhs.components.day) {
            return true;
    }
    return false;
}

Objective-C:

@interface ShortDate : NSObject<NSCopying, NSCoding> {
    NSDate           *inner;
    NSDateComponents *components; // The date split into components.
}

...

@end

The error I'm getting:

ShortDate.swift:26:9: 'ShortDate' does not have a member named 'components'

Sportswoman answered 26/10, 2014 at 12:20 Comment(2)
Did you add proper header to Swift header: YourAppName-Bridging-Header.h?Individual
Yes, sure, the bridging header is in place and I can use the ShortDate class in my Swift code. I simply want to add comparison using operators instead of member functions.Sportswoman
L
5

I believe that there is no way to access Objective-C instance variables from Swift. Only Objective-C properties get mapped to Swift properties.

Lauricelaurie answered 28/10, 2014 at 0:24 Comment(1)
Looks like that. I solved it with properties instead.Sportswoman
U
7

I came across this question while trying to find a way to access a private variable of a class from one of the SDKs we use. Since we don't have or control the source code we can't change the variables to properties. I did find that the following solution works for this case:

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

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

Overriding value(forUndefinedKey:) is optional. value(forKey:) will crash if the private variable doesn't exist on the class unless you override value(forUndefinedKey:) and provide a default value.

Unequal answered 14/2, 2018 at 4:51 Comment(0)
L
5

I believe that there is no way to access Objective-C instance variables from Swift. Only Objective-C properties get mapped to Swift properties.

Lauricelaurie answered 28/10, 2014 at 0:24 Comment(1)
Looks like that. I solved it with properties instead.Sportswoman

© 2022 - 2024 — McMap. All rights reserved.