Search code examples
swiftgenericsprotocols

How to check if Data Type equals Generic Data Type and assign to Property if True?


Context

I have a Generic Swift Class containing a component Property of the Generic Type. A few other Variables with different Data Types are passed through the Initializer, however, all of them are conforming to the Generic Protocol.

However, I get the following Compiler Error in Line 11:

'ComponentA' is not convertible to 'C'


Code

protocol Component { ... }

struct ComponentA: Component { ... }
struct ComponentB: Component { ... }

class Main<C: Component> {
    var component: C

    init(componentA: ComponentA, componentB: ComponentB) {
        // I am trying to check, whether componentA equals the Generic Data Type and assign it to the component Property if true.
        if case let safeComponent = componentA as C {
            self.component = safeComponent
        }
    }
}

Question

How can I achieve my goal of checking whether a Data Type equals the Generic Data Type and assign it to the component Property if true?


Solution

  • You have at least 3 possible approaches. All deal with the possibility that componentA can not be cast to C

    protocol Component {  }
    
    struct ComponentA: Component {  }
    struct ComponentB: Component {  }
    
    // optional `component`
    class Main1<C: Component> {
        var component: C?
    
        init?(componentA: ComponentA, componentB: ComponentB) {
            if let safeComponent = componentA as? C {
                self.component = safeComponent
            }
        }
    }
    
    // init throws when precondtions not met
    class Main2<C: Component> {
    
        enum Errors: Error {
            case preconditionsNotSatisfied
        }
    
        var component: C
    
        init(componentA: ComponentA, componentB: ComponentB) throws {
            if let safeComponent = componentA as? C {
                self.component = safeComponent
            } else {
                throw Errors.preconditionsNotSatisfied
            }
        }
    }
    
    
    // init can return nil
    class Main3<C: Component> {
        var component: C
    
        init?(componentA: ComponentA, componentB: ComponentB) {
            if let safeComponent = componentA as? C {
                self.component = safeComponent
            } else {
                return nil
            }
        }
    }