在Swift中将匿名数组作为参数传递

时间:2018-12-02 23:57:36

标签: swift initialization optional-parameters

我的应用程序中有一个简单的类:

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

Foo1从不为零,而Foo2是可选的,因此它可能为零。

与其希望像下面这样的初始化,不如说拥有一个列表属性Foos: [Bar],它可能包含1或2个元素。

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

在C#中,我将编写类似MyClass m = new MyClass("m", New List<Bar>{Bar1, Bar2})MyClass m = new MyClass("m", New List<Bar>{Bar1, null})的文字。我宁愿在MyClass中将一个属性作为列表,而不是两个单独的字段(其中一个可能为nil)。

我已经尝试过该初始化程序:

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

但是当我尝试将匿名列表传递给初始化程序时,出现以下警告:

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

  

不能对不可变值使用变异成员:函数调用返回不可变值

如何像在C#中那样将已填充的匿名列表传递给Swift中的初始化程序?

2 个答案:

答案 0 :(得分:1)

尝试此代码

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])

希望您有这个主意。并详细了解它在Swift中的工作方式

答案 1 :(得分:0)

最具挑战性的要求,accepted answer也无法满足:

  

我不想像下面那样拥有一个初始化,而是希望拥有一个列表属性Foos:[Bar],它可能包含1或2个元素。

一种解决方法可能是自定义运行时错误。

enum BarWrapperError: Error {
    case emptyList
}

要传递列表并检查其是否至少包含一个元素,可以引入另一种类型

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用小节列表初始化。如果此列表为空,将引发错误。

您的MyClass现在看起来像:

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
    }
}

如果您关心错误并希望继续执行,可以这样使用

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")
}

如果您希望在列表为空时使应用程序崩溃,则可以将其缩短为

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

通过使用try!

您也可以

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

如果您不需要错误处理,并且如果未创建MyClass实例,则您的应用仍然可以运行。