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 ) ?
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 .
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] .
There is no default value.
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() }
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With