When is an outline not an outline?

It sounds like the start of a joke but, actually, it’s one of the reasons why SwiftUI is difficult to code.

Take, for example, the simple wish to create a Rectangle() with an outline. In SwiftUI, you use the .stroke modifier, thus:

Rectangle()
    .stroke(.black, lineWidth: 2)
    .frame(height: 40)
    .padding(.horizontal)

Great, huh? A nice outline around your Rectangle().

Today, we’re styling buttons. So we’re starting with a Rectangle that’s outlined. Today, Xcode throws up an error:

Value of type 'some View' has no member 'stroke'

Why is this? No indication of why this error turns up this time around.

Turns out that we now have to use:

Rectangle()
    .fill(...)
    .frame(height: 50)
    .border(...)

Why is it now a .border() and not a .stroke() as before? The only difference is that we’re using it inside a method inside a struct. Why should that make a difference? No idea.

Okay, let’s put that aside for a moment. So we create a “border” instead of a “stroke”, thus:

Rectangle()
    .fill(...)
    .frame(height: 50)
    .border(.black, lineWidth: 2)

Okay?

Urm, no. Now Xcode protests with:

Extra argument 'lineWidth' in call

It turns out that now we’ve been forced to use .border() instead of .stroke(), we can’t use “lineWidth” to specify the border thickness as we did before. Now we have to call it just “width”, thus:

Rectangle()
    .fill(...)
    .frame(height: 50)
    .border(.black, width: 2)

Two different modifiers to do the same thing, and they need different parameters to do the same thing? Either SwiftUI’s programmers don’t talk to each other or else they’re purposefully putting up hurdles to trip people up.

Another example of how helpful Xcode is crops up when you use RoundedRectangle(). If you just code similar to a regular Rectangle(), thus:

RoundedRectangle()
    .frame(height: 50)
    .padding()

Xcode will complain with:

Missing argument for parameter 'cornerSize' in call

You need something to “round” the corder of the RoundedRectangle(), of course. Xcode will, helpfully, insert the cornerSize in your code for you:

RoundedRectangle(cornerSize: CGSize)

But this is of limited use, because you can’t just drop a number in there where it says “CGSize” because Xcode will complain with:

Cannot convert value of type 'Int' to expected argument type 'CGSize'

Feels like it’s sending you down a rabbit hole and laughing the deeper you get. Your solution is to go hunting around trying to figure out just what “CGSize” is, and how to use it, or Xcode could have been a little more helpful and offer to use cornerRadius instead. This will work:

RoundedRectangle(cornerRadius: 10)
    .frame(height: 50)
    .padding()

Xcode‘s error messages and “helpful” fixes are certainly not “user-friendly”. I don’t expect either Apple or Xcode to hold my hand whilst I’m learning to code, but being contradictory one minute and then offering unhelpful solutions the next is being the exact opposite to that.