Search code examples
swiftfunctionautolayoutargumentsvariadic-functions

How to accept either a CGFloat or an Array of CGFloats as a function argument?


I have an auto layout convenience function which stacks views on top of each other. For my spacing parameter, I would like to allow:

  • zero spacing between views
  • or a single CGFloat (all views spaced evenly)
  • or an array of CGFloats (different spaces between views)

However, I'm not sure how to define this argument.

// Ambiguous
func myconstrainer(_ views : [UIView], spacing : CGFloat = 0){}
func myconstrainer(_ views : [UIView], spacing : [CGFloat]? = nil){}

// Messy
func myconstrainer(_ views : [UIView], spacingA : CGFloat = 0, spacingB: [CGFloat]? = nil){}

Solution

  • You can also try variable number of arguments like this:

    func myconstrainer(_ views: [UIView], spacing: CGFloat...) {
        myconstrainer(views, spacing: spacing)
    }
    

    and provide a simple overload to work with arrays as well:

    func myconstrainer(_ views: [UIView], spacing: [CGFloat]) {
        // Implementation...
    }
    

    As such, you won't need to put a single element in brackets when using even spacing.

    Call sites:

    myconstrainer([view1, view2, view3])
    myconstrainer([view1, view2, view3], spacing: 123)
    myconstrainer([view1, view2, view3], spacings: 1, 2, 3)
    myconstrainer([view1, view2, view3], spacings: [1, 2, 3])
    

    Some non-obvious notes:

    • the default case is nicely covered by calling CGFloat... with zero arguments;
    • and, since this argument is actually an array, we can forward it to the other method without brackets.