What I discovered
This question is about something I noticed a bit strange in the Swift language. I came across this behaviour, as it was a bug in my code.
If I created an array for a grid as an implicitly unwrapped optional, then map behaves strangely. Have a look at this code:
let grid: [[Int]]! = [ // May be defined like this if set later on
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(grid.map { $0[0] }!)
// Prints "[1, 2, 3]" (not what I wanted)
print(grid!.map { $0[0] })
// Prints "[1, 4, 7]" (what I wanted)
I know the row can be obtained simply by doing grid[0]. However, I am trying to get a column.
I tried the first method above, which only gives the row instead of the column. The second method worked and gave the column.
What is the cause?
I defined grid as [[Int]]!, which is an implicitly unwrapped optional.
Why do I need to force unwrap grid to use map properly?
Why does the first method act the same as returning a row using grid[0]?
There are two versions of map: one that operates on the array and one that operates on optionals.
Your grid is an optional, and even though it is an implicitly unwrapped optional (IUO) it is still an optional. Swift will treat an IUO as an optional whenever possible and only force unwraps the value when the unwrapped type is needed.
Because of this, the optional version of map is used instead of the one you expect. By explicitly unwrapping grid with !, you then allow the desired version of map to be used.
How does map work on an optional?
When map is applied to an optional, it applies the closure to the unwrapped value. If the optional is nil, nothing happens.
So, grid is unwrapped and becomes $0, and the closure returns $0[0] which is the first row of the grid.
Note: In Xcode, if you option-click on map in each statement you will see that the first says:
Evaluates the given closure when this Optional instance is not nil,
passing the unwrapped value as a parameter.
and the second one:
Returns an array containing the results of mapping the given closure
over the sequence’s elements.
Related
Please explain to a beginner how the function of finding a maximum in the dictionary works.
I know there are more concise solutions, but I want to understand step by step what is going on here.
var someDictionary = ["One": 41, "Two": 17, "Three": 23]
func maxValue() {
let maxValueOfSomeDictionary = someDictionary.max { a, b in a.value < b.value }
print(maxValueOfSomeDictionary!.value)
}
maxValue()
someDictionary is a Dictionary. A Dictionary is a kind of Sequence (see the "Default Implementations" section of Dictionary to know that it's a Sequence). Sequences provide the method max(by:), which:
Returns the maximum element in the sequence, using the given predicate as the comparison between elements.
Swift has trailing-closure syntax, so you can write .max {...} instead of .max(by: { ... }). The two syntaxes are identical, but most developers use trailing-closure syntax when possible.
The parameter is defined as:
areInIncreasingOrder
A predicate that returns true if its first argument should be ordered before its second argument; otherwise, false.
The Element of Dictionary as a Sequence is a tuple (key: Key, value: Value), so this is the type that is passed to areInIncreasingOrder.
The closure defines two parameters, a and b, each of type (key: Key, value: Value). It returns whether a.value is less than b.value. Swift allows 1-statement closures to omit the return.
This paragraph is somewhat technical and you may want to skip it. The TL;DR is that max returns the maximum element according to your closure. Provided the closure obeys the rules defined in the docs, the max algorithm will return the maximum element, for a specific definition of "maximum," which is that there is no element in the sequence that is ordered after this one according to areInIncreasingOrder. This pedantic definition especially matters when there are incomparables in the list. Equal elements are (somewhat strangely IMO) defined as "incomparable" in that neither is before the other. This also matters for values like NaN.
This will return a maximum element, or nil if the Sequence is empty. (The docs say "the" maximum element, but in the case of incomparable elements, it is not promised which one will be returned.)
maxValueOfSomeDictionary is of type (key: String, value: Int)?, an optional version of the Element of the Dictionary, since it may be a value or it may be nil.
maxValueOfSomeDictionary! converts an Optional into its wrapped value, or crashes if the Optional is nil. This then prints the .value of that.
To see precisely how max operates, you can read the default implementation in stdlib.
I'm wondering about the reversed() method on a swift Array:
var items = ["a", "b", "c"]
items = items.reversed()
the signature of the reversed method from the Apple doc says that it returns a
ReversedRandomAccessCollection<Array<Element>>
could that be assigned back to items without doing what the apple doc say which is
For example, to get the reversed version of an array, initialize a new Array instance from the result of this reversed() method.
or would it give problem in the future? (since the compiler doesn't complain)
There are 3 overloads of reversed() for an Array in Swift 3:
Treating the Array as a RandomAccessCollection,func reversed() -> ReversedRandomAccessCollection<Self> (O(1))
Treating the Array as a BidirectionalCollection,func reversed() -> ReversedCollection<Self> (O(1))
Treating the Array as a Sequence,func reversed() -> [Self.Iterator.Element] (O(n))
By default, reversed() pick the RandomAccessCollection's overload and return a ReversedRandomAccessCollection. However, when you write
items = items.reversed()
you are forcing the RHS to return a type convertible to the LHS ([String]). Thus, only the 3rd overload that returns an array will be chosen.
That overload will copy the whole sequence (thus O(n)), so there is no problem overwriting the original array.
Instead of items = items.reversed(), which creates a copy of the array, reverse that and copy it back, you could reach the same effect using the mutating function items.reverse(), which does the reversion in-place without copying the array twice.
Document said:
An in-out expression that contains a mutable variable, property, or subscript reference of type Type, which is passed as a pointer to the address of the left-hand side identifier.
A [Type] value, which is passed as a pointer to the start of the array.
But when I run the following code :
func print<Type>(unsafePointer pointer: UnsafePointer<Type>) {
print("\(pointer) ==> \(pointer.pointee) : \(Type.self)")
}
var array = [1, 2, 3, 4]
print(unsafePointer: array)
print(unsafePointer: &array[0])
I get
0x0000000104204240 ==> 1 : Int
0x00007ffeefbff440 ==> 1 : Int
Why their addresses are different?
Here
print(unsafePointer: array)
a pointer to the first element of the array storage is passed to the function. And here
print(unsafePointer: &array[0])
the subscript operator is called on the array (returning an Int) and the address of that (temporary) integer is passed to the function, not the address where the original array element is stored.
That becomes more obvious if you call the functions twice:
var array = [1, 2, 3, 4]
print(unsafePointer: array) // 0x00007ffeefbff2e0
print(unsafePointer: array) // 0x00007ffeefbff2e0, same as previous address
print(unsafePointer: &array[0]) // 0x00007ffeefbff320
print(unsafePointer: &array[0]) // 0x00007ffeefbff340, different from previous address
In addition, passing an in-out expression to a function can make a temporary copy, see for example Swift: always copies on inout?.
Arrays in Swift have value semantics, not the reference semantics of arrays in C or Objective-C. The reason you're seeing different addresses (and addresses at all) is that every time you pass the array as a parameter, you're actually telling Swift to bridge your Array struct to an instance of NSArray.
var bigNum = [2,34,5].remove(at: 2)
Error:
Playground execution failed: error: CalculatorPlayGround.playground:35:14: error: cannot use mutating member on immutable value of type '[Int]'
var bigNum = [2,34,5].remove(at: 2)
But
var bigNum = [2,34,5]
var b = bigNum.remove(at: 2)
is ok.
What is the difference? Why does it work in the second case?
.remove(at:) tries to mutate the array you call it on.
When you create the array like you did in your first example ([1,2,3].whatever), it creates an immutable constant, as if you were to create it like this:
let array = [2, 34, 5] //not mutable
If you force it to create the array as a variable, it is mutable:
var array = [2, 34, 5] //mutable
Note
I don't know exactly what you are trying to do, but bigNum makes me assume you're trying to get a number from the array? Because right now, bigNum would become this array: [2, 34] instead of just a number.
[2,34,5] in itself is a literal, and as such is immutable in Swift (i.e. you can't write [2,34,5].remove(at: 2)). To apply a mutating function, you first need to store your array in a mutable container, using the var keyword:
var bigNum = [2,34,5]
Only after doing so, you can use mutating func .remove(at:) on mutable bigNum.
I met with this code, and I could not figure out what does this two question marks mean?
the Definition of this variable looks like following:
var featureImageSizeOptional: CGSize?
The code that makes me confused is:
let featureImageSize = featureImageSizeOptional ?? CGSizeZero
It's the coalescing operator. It returns the first expression (featureImageSizeOptional) if it's non-nil. If the first expression is nil, the operator returns the second expression (CGSizeZero).
See the Language Guide for more info.
The operator does not 'return the first expression' - it returns the unwrapped value of the first expression (if it is not nil). From the Apple documentation (emphasis mine):
The nil coalescing operator (a ?? b) unwraps an optional a if it
contains a value, or returns a default value b if a is nil. The
expression a is always of an optional type. The expression b must
match the type that is stored inside a.
The nil coalescing operator is shorthand for the code below:
a != nil ? a! : b
The code above uses the ternary conditional operator and *forced
unwrapping (a!) to access the value wrapped inside a when a is not
nil*, and to return b otherwise. The nil coalescing operator provides a
more elegant way to encapsulate this conditional checking and
unwrapping in a concise and readable form.