Fred
Fred

Reputation: 397

Pass anonymous array as paramter in Swift

I have a simple class in my application:

class MyClass{
    var Name: String
    var Foo1: Bar
    var Foo2: Bar?
    //var Foos: [Bar]
}

Foo1 is never nil, and Foo2 is optional, so it might be nil.

Instead of having an init like the one below, I'd like to rather have a list property Foos: [Bar], that might contain 1 or 2 elements.

init(_ Name: String, _ Foo1: Bar, _ Foo2: Bar?){
    self.Name = Name
    self.Foo1 = Foo1
    self.Foo2 = Foo2
}

In C# I'd write something like MyClass m = new MyClass("m", New List<Bar>{Bar1, Bar2}) or MyClass m = new MyClass("m", New List<Bar>{Bar1, null}). I'd prefer to rather have one property in MyClass as a List, instead of two separate fields where one might be nil.

I've tried this initializer:

init(_ Name: String, _ Foos: [Bar]) {
    self.Name = Name
    self.Foos = Foos
}

But when I try to pass an anonymous List to the initializer, I get this warning:

let m = MyClass("m", [Bar]().append(B1))

Cannot use mutating member on immutable value: function call returns immutable value

How can I pass a populated anonymous list to the initializer in Swift, like I would've done in C#?

Upvotes: 0

Views: 294

Answers (2)

vikingosegundo
vikingosegundo

Reputation: 52227

The most challenging requirement, which is also not met by the accepted answer:

Instead of having an init like the one below, I'd like to rather have a list property Foos: [Bar], that might contain 1 or 2 elements.

One way of dealing with this could be a custom runtime error.

enum BarWrapperError: Error {
    case emptyList
}

To pass the list and check if it at least contains one element, you can introduce another type

struct BarWrapper {
    init(bars: [Bar]) throws {
        guard bars.count > 0 else {
            throw BarWrapperError.emptyList
        }
        self.bars = bars
    }

    let bars: [Bar]
    var firstBar: Bar {
        return bars[0]
    }
    var otherBars:[Bar] {
        return Array(bars[1 ..< bars.count])
    }
}

BarWrapper is initialised with a list of bars. If this list is empty, it will throw an error.

your MyClass would now look like:

class MyClass {
    let name: String
    let firstBar: Bar
    let otherBars: [Bar]

    init(name: String, barWrapper: BarWrapper) {
        self.name = name
        self.firstBar = barWrapper.firstBar
        self.otherBars = barWrapper.otherBars
    }
}

If you care for the error and want to continue the execution, you can use this like

do {
    let bar0 = Bar()
    let bar1 = Bar()
    let barWrapper = try BarWrapper(bars: [bar0, bar1])
    let object = MyClass(name: "String", barWrapper: barWrapper)
    print(object.otherBars)
} catch BarWrapperError.emptyList {
    print("empty bar list")
}

If you rather want to crash the app if the list is empty, you can shorten it to

let bar0 = Bar()
let bar1 = Bar()
let barWrapper = try! BarWrapper(bars: [bar0, bar1])
let object = MyClass(name: "String", barWrapper: barWrapper)
print(object.otherBars)

by using try!

You can also do

let bar0 = Bar()
let bar1 = Bar()
if let barWrapper = try? BarWrapper(bars: [bar0, bar1]) {
    let object = MyClass(name: "String", barWrapper: barWrapper)
    print(object.otherBars)
}

if you don't need error handling and your app would be still operational if the MyClass instance isn't created.

Upvotes: 0

nslllava
nslllava

Reputation: 599

Try this code

struct Bar { }

class MyClass {
    var name: String
    var foos: [Bar?]

    init(name: String, foos: [Bar?]) {
        self.name = name
        self.foos = foos
    }
}

let bar0 = Bar()
let bar1: Bar? = nil
let object = MyClass(name: "String", foos: [bar0, bar1])

Hope you got the idea. And read more about how it works in Swift

Upvotes: 1

Related Questions