Reputation: 397
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
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
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