Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Creating an Array with a Default Value of distinct object instances

Tags:

I noticed a bit weird (and dangerous IMHO) behavoir in Creating an Array with a Default Value. As stated in Swift 2.1: Collection Types

Swift’s Array type also provides an initializer for creating an array of a certain size with all of its values set to the same default value. You pass this initializer the number of items to be added to the new array (called count) and a default value of the appropriate type (called repeatedValue):

The point is: same default value; in order to understand how it work, I tried to create an array of elements of this example class

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

and this testing code:

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

gives:

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

that definitively proof the initializer with the number of items to be added to the new array and a default value of the appropriate type are: the same object instance

Which is the way, as concise and smart as possible, to obtain a array of distinct object instances , instatiated with the same default value ( not the same instance but a number of instances initialized with the same default value ) ?

like image 960
Franco Rondini Avatar asked Oct 03 '15 10:10

Franco Rondini


People also ask

What is the default value for an array of objects?

The default values of numeric array elements are set to zero, and reference elements are set to null . A jagged array is an array of arrays, and therefore its elements are reference types and are initialized to null . Arrays are zero indexed: an array with n elements is indexed from 0 to n-1 .

How do I initialize an array in Swift?

To initialize a set with predefined list of unique elements, Swift allows to use the array literal for sets. The initial elements are comma separated and enclosed in square brackets: [element1, element2, ..., elementN] .

What is the default value of elements of an Uninitialised array?

There is no default value.


1 Answers

Classes are reference types, therefore – as you noticed – all array elements in

var users = [User](count: howManyUsers, repeatedValue:User(thinkTime: 10.0))

reference the same object instance (which is created first and then passed as an argument to the array initializer).

For a struct type you would get a different result.

A possible solution:

var users = (0 ..< howManyUsers).map { _ in User(thinkTime: 10.0) }

Here, a User instance is created for each of the array indices.

If you need that frequently then you could define an array init method which takes an "autoclosure" parameter:

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

Now the second argument User(thinkTime: 10.0) is wrapped by the compiler into a closure, and the closure is executed for each array index.


Update for Swift 3:

extension Array {
    public init(count: Int, elementCreator: @autoclosure () -> Element) {
        self = (0 ..< count).map { _ in elementCreator() }
    }
}
like image 112
Martin R Avatar answered Oct 18 '22 17:10

Martin R