mercredi 21 décembre 2022

Get marked variable name as default value for propertyWrapper

Lets say I have a property Wrapper to fetch Feature Flag from a service and assign to a Boolean if it is enabled of not

@propertyWrapper final class FeatureToggle {
    
    var clientContainer: ConfigurableFeatureFlagClient
    private let key: String
    
    var wrappedValue: Bool {
       FeatureFlag(clientContainer: clientContainer).isEnabled(key: key)
     }

    init(key: String, container: ConfigurableRemoteConfigClient = RemoteConfigClient.shared) {
        self.clientContainer = container
        self.key = key
    }
}

// Test Class
class TestFeatureToggle {

  @FeatureToggle(key: "isFeatureEnabled")
  var isFeatureEnabled 
}

I'm trying to Make this FeatureToggle Property Wrapper to assume that key default value will be the variable name marked with the property Wrapper, so if @FeatureToggle is marking var isFeatureEnabled so the key will automatically be isFeatureEnabled

Currently I tried using the #function as default value to get the class and use Mirror reflection to get the variable name of the class marked with the property Wrapper

@propertyWrapper final class FeatureToggle {

var clientContainer: ConfigurableRemoteConfigClient
private let key: String

var wrappedValue: Bool {
    let factoryClass = Bundle.main.classNamed(key) as! NSObject.Type // Force Unwrap just to simplify the example
    let factory = factoryClass.init()
    let mirror = Mirror(reflecting: factory)
    for child in mirror.children {
        guard let featureToggle = child.value as? FeatureToggle else { continue }
        let formattedValue = child.label?.dropFirst() // Drop the _ inserted by OBJC
        return FeatureFlag(clientContainer: clientContainer).isEnabled(key: formattedValue)
    }
    return false
}

init(key: String = #function, container: ConfigurableRemoteConfigClient = RemoteConfigClient.shared) {
    self.clientContainer = container
    self.key = key
    print("Self.key == \(self.key)") // It will print "TestFeatureToggle" using my class in previous code
} }

It works but i have to make the class TestFeatureToggle with @objc and makes it inherit from NSObject. Not to mention that this solution looks kind of ugly and hacky. My question is, is there an easier way without exposing to OBJC runtime or a more clean solution?





Aucun commentaire:

Enregistrer un commentaire