1

I have a function with this signature (its funcionality is pretty straightforward I think), the implementation isn't important for us:

extension View {
    func border(edge: Edge, color: Color, width: CGFloat = 1, cornerRadius: CGFloat = 0) -> some View
}

Then I want to extend the functionality of the View, and add an extra function that would call the previous function:

extension View {
    func border(edges: [Edge], color: Color, width: CGFloat = 1, cornerRadius: CGFloat = 0) -> some View
}

But the first idea I have didn't work. In UIKit there wouldn't be a problem, but here I cannot figure it out how can I apply multiple (variable quantity) modifier in a single function.

I tried this:

extension View {
   func border(edges: [Edge], color: Color, width: CGFloat = 1, cornerRadius: CGFloat = 0) -> some View {
        var view = self
        edges.forEach { edge in
            view = view.border(edge: edge, color: color, width: width, cornerRadius: cornerRadius)
        }
        return view
    }
}

It shows me 2 errors:

Cannot assign value of type 'some View' to type 'Self'

Return type of instance method 'border(edges:color:width:cornerRadius:)' requires that 'Self' conform to 'View'

I understand the errors, but I cannot say that let the view variable be a some View (var view: View = self cannot be compiled). How (with what syntax / idea) can I solve this issue?

Edit: here is a full code, which shows the issue:

extension SwiftUI.View {
    // not completed implementation, doesn't matter
    public func border(edge: Edge, color: SwiftUI.Color, width: CGFloat = 1, cornerRadius: CGFloat = 0) -> some SwiftUI.View {
        self
    }

    public func border(edges: [Edge], color: SwiftUI.Color, width: CGFloat = 1, cornerRadius: CGFloat = 0) -> some View {
        var view: SwiftUI.View = self
        edges.forEach { edge in
            view = view.border(edge: edge, color: color, width: width, cornerRadius: cornerRadius)
        }
        return view
    }
}
4
  • I am unable to reproduce this. Commented Dec 2, 2021 at 18:05
  • You can build the function that has a forEach in? Edit: I add a full code that reproduces the problem. Commented Dec 2, 2021 at 18:07
  • remove the view = view... and just use view.border(...) SwiftUI auto-sets modifiers. The way that you're doing it is akin to replacing a view each time you add a modifier. Commented Dec 2, 2021 at 18:11
  • Doesn't work, it gives me this error: Result of call to 'border(edge:color:width:cornerRadius:)' is unused on the line in the forEach. Commented Dec 2, 2021 at 21:59

1 Answer 1

1

I would solve this task in reverse order - generic implementation for array and single use as array with one element, like:

extension SwiftUI.View {
    public func border(edge: Edge, color: SwiftUI.Color, width: CGFloat = 1, cornerRadius: CGFloat = 0) -> some SwiftUI.View {
        self.border(edges: [edge], color: color, width: width, cornerRadius: cornerRadius)
    }

    public func border(edges: [Edge], color: SwiftUI.Color, width: CGFloat = 1, cornerRadius: CGFloat = 0) -> some View {
        self  // generic implementation here
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Good approach, but in reality we just shifted the problem to the other function. In this case the function with an array should deal with all possible states of the edges (e.g. leading; leading + trailing; leading + trailing + top; ...), which isn't feasible, but I wrote it (around 170 lines). However Xcode now complains about return type: Function declares an opaque return type, but the return statements in its body do not have matching underlying types (I returned in every path a .overlay(...) which returns a some View. I don't have more ideas.)
Such cases are usually fixed either by making function ViewBuilder or using Group inside to wrap top-most conditions or cases. Like in stackoverflow.com/a/64587601/12299030 or stackoverflow.com/a/60450204/12299030.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.