swiftPunk
swiftPunk

Reputation: 1

Converting optional Binding to non-optional Binding

I want extend Binding extension with a func that we can convert an optional Binding to a non-optional Binding and use it as a normal Binding. I almost could finish it but xCode through an error which I cannot handle it, I think I done everything correct.

extension Binding {
    
    mutating func safeBinding<T>(defaultValue: T) -> Binding<T> where Value == Optional<T> {
        
        let safeValue: T
        
        if let unwrappedValue: T = self.wrappedValue { safeValue = unwrappedValue }
        else { safeValue = defaultValue }

        return Binding.init(get: { () -> T in return safeValue },
                            set: { (newValue) in self.wrappedValue = newValue })
 
        
    }
}

The error:

Cannot convert return expression of type 'Binding<Optional<T>>' to return type 'Binding<T>'

Updated code for my way:

extension Binding {
    
     func safeBinding<T>(defaultValue: T) -> Binding<T> where Value == Optional<T> {
        
        let safeValue: T
        
        if let unwrappedValue: T = self.wrappedValue { safeValue = unwrappedValue }
        else { safeValue = defaultValue }

        return SwiftUI.Binding.init(get: { () -> T in return safeValue },
                                    set: { (newValue) in self.wrappedValue = newValue })
 
        
    }
}

Upvotes: 7

Views: 1383

Answers (1)

jnpdx
jnpdx

Reputation: 52387

Binding has an associated type Value already, so by trying to use T, you're putting a new generic on top of Value, which already exists.

But, you will still end up using T because you'll want to constrain Value to scenarios where it is Optional:

extension Binding {
    func safeBinding<T>(defaultValue: T) -> Binding<T> where Value == Optional<T> {
        .init {
            self.wrappedValue ?? defaultValue
        } set: { newValue in
            self.wrappedValue = newValue
        }
    }
}

As noted in the comments, the Xcode compiler has difficulty if just Binding.init is used (note that I used just .init). This can be solved by explicitly using Binding<T>.init:

extension Binding {
    func safeBinding<T>(defaultValue: T) -> Binding<T> where Value == Optional<T> {
        Binding<T>.init {
            self.wrappedValue ?? defaultValue
        } set: { newValue in
            self.wrappedValue = newValue
        }
    }
} 

Upvotes: 9

Related Questions