Swift:使用不同对象实例的默认值创建数组

Fra*_*ini 13 arrays initialization instantiation instance swift

创建具有默认值的数组时,我注意到有点奇怪(和危险的恕我直言)行为.如Swift 2.1中所述:集合类型

Swift的Array类型还提供了一个初始化器,用于创建一个特定大小的数组,并将其所有值设置为相同的默认值.您将此初始值设定项传递给要添加到新数组的项目数(称为计数)和相应类型的默认值(称为repeatedValue):

重点是:相同的默认值 ; 为了理解它是如何工作的,我试图创建这个示例类的元素数组

class User {
  private struct Shared {
    static var sequence: Int = 0
  }

  var id: Int
  var thinkTime: NSTimeInterval // typealias di Double

  init (thinkTime: NSTimeInterval) {
    User.Shared.sequence = User.Shared.sequence+1
    id = User.Shared.sequence
    self.thinkTime = thinkTime
  }
}
Run Code Online (Sandbox Code Playgroud)

和这个测试代码:

let  howManyUsers: Int = 3
var users = [User](count: howManyUsers, repeatedValue:User(thinkTime: 10.0))
let u2: User = User(thinkTime: 10)
let u3: User = User(thinkTime: 10)
users.append(u2)
users.append(u3)
users[1].thinkTime = 20
users[3].thinkTime = 30

for u in users {
  print("User id:\(u.id) thinktime:\(u.thinkTime)")
}
Run Code Online (Sandbox Code Playgroud)

得到:

User id:1 thinktime:20.0     
User id:1 thinktime:20.0
User id:1 thinktime:20.0
User id:2 thinktime:30.0
User id:3 thinktime:10.0
Run Code Online (Sandbox Code Playgroud)

最终证明初始化程序具有要添加到新数组的项目数,并且相应类型的默认值为:相同的对象实例

为了获得一组不同的对象实例,使用相同的默认值(不是相同的实例,但是使用相同的默认值初始化的实例数)实例化,尽可能简洁明智的方式是什么?

Mar*_*n R 28

类是引用类型,因此 - 正如您所注意到的 - 所有数组元素

var users = [User](count: howManyUsers, repeatedValue:User(thinkTime: 10.0))
Run Code Online (Sandbox Code Playgroud)

引用相同的对象实例(首先创建,然后作为参数传递给数组初始值设定项).

对于某种struct类型,您会得到不同的结果.

可能的解决方案:

var users = (0 ..< howManyUsers).map { _ in User(thinkTime: 10.0) }
Run Code Online (Sandbox Code Playgroud)

这里,User为每个数组索引创建一个实例.

如果您经常需要,那么您可以定义一个数组init方法,该方法采用"autoclosure"参数:

extension Array {
    public init(count: Int, @autoclosure elementCreator: () -> Element) {
        self = (0 ..< count).map { _ in elementCreator() }
    }
}

var users = Array(count: howManyUsers, elementCreator: User(thinkTime: 10.0) )
Run Code Online (Sandbox Code Playgroud)

现在第二个参数User(thinkTime: 10.0)被编译器包装到一个闭包中,并且为每个数组索引执行闭包.


Swift 3更新:

extension Array {
    public init(count: Int, elementCreator: @autoclosure () -> Element) {
        self = (0 ..< count).map { _ in elementCreator() }
    }
}
Run Code Online (Sandbox Code Playgroud)