2

I'm just starting Swift. Can someone please explain to me why I can pass array as an argument (byRoundingCorners:)

UIBezierPath(
        roundedRect: self.bounds,
        byRoundingCorners: [.topLeft, .bottomLeft],
        cornerRadii: CGSize(width: radius, height: radius))

But passing it in variable, produces error

var corners = [UIRectCorner.topLeft, UIRectCorner.bottomLeft]
let path = UIBezierPath(
        roundedRect: self.bounds,
        byRoundingCorners: corners,
        cornerRadii: CGSize(width: radius, height: radius))

"Cannot convert value of type '[UIRectCorner]' to expected argument type 'UIRectCorner'"

1
  • Enough answers already, but someone might add that OptionSet (indirectly) inherits from ExpressibleByArrayLiteral, and that is what allows to pass a literal array in the initialization. Commented Jan 10, 2018 at 20:12

3 Answers 3

5

It's not an array. It's an OptionSet. The byRoundingCorners parameter expects a type of UIRectCorner which extends OptionSet.

If you update your declaration of corners to:

var corners: UIRectCorner = [.topLeft, .bottomLeft]

then your code will work as expected.

The [ ] syntax is not really an array here, it's a list of options for the set.

Your first attempt works because the compiler can infer the data type (UIRectCorner) from the parameter.

But when you did:

var corners = [UIRectCorner.topLeft, UIRectCorner.bottomLeft]

the inferred type is an array of UIRectCorner, not UIRectCorner. By adding the : UIRectCorner to the line, you make it clear what the type is and the syntax using [ ] is properly interpreted as a list of options instead of as an array.

As mentioned by Martin R (thanks), OptionSet extends ExpressibleByArrayLiteral which is what allows the array-like literal syntax to be used to assign a value to UIRectCorner.

Sign up to request clarification or add additional context in comments.

Comments

3

UIRectCorner in an OptionSet, so when you write [.topLeft, .bottomLeft] in your function call, Swift automatically creates an instance of UIRectCorner from that array literal.

However, when you write

var corners = [UIRectCorner.topLeft, UIRectCorner.bottomLeft]

you create an array of UIRectCorner option sets, instead of a single option set containing all the different cases.

You can get around this by specifying the type of corners as UIRectCorner. This will also allow you to infer the type in the array literal:

var corners: UIRectCorner = [.topLeft, .topRight]

Comments

2

Swift 5 example for the ones who had problem tried append and finally found insert is the way to go for a variable situation.

    var cornersToRound: UIRectCorner = []
    if topLeftRounded { cornersToRound.insert(.topLeft) }
    if topRightRounded { cornersToRound.insert(.topRight) }
    if bottomRightRounded { cornersToRound.insert(.bottomRight) }
    if bottomLeftRounded { cornersToRound.insert(.bottomLeft) }

Comments

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.