Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Swift- How to accept multiple (union) types as argument

Here is the playground to get the idea

import SwiftUI
import PlaygroundSupport

struct RectangleStyle {
    public var color: Color? = nil
    public var gradient: LinearGradient? = nil
}


struct DemoView: View {
    var body: some View {
        Rectangle()
            .fill(
                RectangleStyle(
                    gradient: LinearGradient(
                        gradient: Gradient(colors: [.red, .blue]), 
                        startPoint: .top, 
                        endPoint: .bottom
                    )
                ).gradient!
            )
            .frame(width: 200, height: 200)
    }
}

PlaygroundPage.current.setLiveView(DemoView())

As you can see, it’s quite ugly. What I would like, is the ability to construct my RectangleStyle with whatever object that implement ShapeStyle (the protocol required by the fill() method on Rectangle) and be able to retrieve this ShapeStyle (A Color or a Gradient, etc…) with a single method.

If I add a init(style: ShapeStyle) on my RectangleStyle, I get the error Protocol "ShapeStyle" can only be used as a generic constraint because it has Self or associated type requirements.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

And I get the same error if I try to add a func getStyle() -> ShapeStyle on my RectangleStyle.

How can I properly handle this case? The idea is just to be able to construct my RectangleStyle with any object of type compatible with the required type of Rectangle.fill() and have a method to return this object.
Is is possible to let Swift know that if the argument was of type A, the return of a method will be the same type (like in Typescript)?

Thanks!

>Solution :

It can be done with generics, like

struct RectangleStyle<S: ShapeStyle> {
    private let style: S

    init(_ style: S) {      // << your init !!
        self.style = style
    }

    func getStyle() -> some ShapeStyle { // << your func !!
        self.style
    }
}

and now your test:

let myStyle = RectangleStyle(LinearGradient(
                    gradient: Gradient(colors: [.red, .blue]),
                    startPoint: .top,
                    endPoint: .bottom
                ))

var body: some View {
    Rectangle()
        .fill(myStyle.getStyle())         // << here !!
        .frame(width: 200, height: 200)
}

Tested with Xcode 13.4 / iOS 15.5

demo

Test code is here

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading