Subtle Cast Warning When Using SQLite.Swift ... Binding? to Any

Subtle cast warning when using SQLite.Swift ... Binding? to Any

You're using Array's sequence initialiser, which has the signature:

init<S>(_ s: S) where S : Sequence, Element == S.Iterator.Element

Because you typed r as [[Any]], Element is [Any]. However, the sequence you're passing in has an Iterator.Element type of [Binding?]. Therefore, you're implicitly coercing Binding? to Any, and as per SE-0140, this will invoke a warning – as you're losing the optionality of the inner elements, which is potentially undesirable.

As the proposal says, one way to silence this warning is to add an explicit as Any cast. In your case, this can be achieved by using a nested map(_:):

r = stmt.map { $0.map { $0 as Any } }

Sample Image

This shouldn't be any more costly than using Array's sequence initialiser due to the fact that a walk over all the inner elements will have to be done in either case, due to the difference in how Swift stores abstract-typed values (see this Q&A for more info).

However, really you should be asking yourself whether r should be of type [[Any]]. I see no reason why you shouldn't just type it as [[Binding?]]. Doing so will both get rid of the warning and give you better type-safety.

How to insert into Sqlite with optional parameters using Swift 3

Make all your class properties constants (declare with let) and make them non optional adding a required init() with all your Address properties parameters. BTW it is Swift convention to start your vars naming with a lowercase letter. Note: You should use Int instead of Int64 unless it is a requirement. Regarding the optionality of your properties you can just assign a default value for them at initialization time. Btw It is better to use a struct unless you need to make your object persist (NSCoding compliant):

struct Address {
let id: Int
let addressType: Int
let addressStatus: Int
let address1: String
let address2: String
let city: String
let state: String
let zip: String
let country: String
let latitude: Double?
let longitude: Double?
init(id: Int, addressType: Int, addressStatus: Int, address1: String = "", address2: String = "", city: String = "", state: String = "", zip: String = "", country: String = "", latitude: Double = nil, longitude: Double = nil) {
self.id = id
self.addressType = addressStatus
self.addressStatus = addressStatus
self.address1 = address1
self.address2 = address2
self.city = city
self.state = state
self.zip = zip
self.country = country
self.latitude = latitude
self.longitude = longitude
}
}

So you can create your new object Address as follow:

let address1 = Address(id: 1, addressType: 2, addressStatus: 3)
let address2 = Address(id: 2, addressType: 3, addressStatus: 4, address1: "Any Address", latitude: 22.0, longitude: 43.0) // You don't need to add all parameters as long as you keep them in the same order as your initializer

address2.latitude // 22.0

SWIFT: warnings upon compilation but good behaviour

findIndex() returns Int?, and then print() coerces it to Any.

To since the warning, apply one of the suggested fixes:

print(findIndex(valueToFind: my_int(value: 2), array: ints) ?? -1) // one option
print(findIndex(valueToFind: my_int(value: 2), array: ints)!) // another option, may crash
print(findIndex(valueToFind: my_int(value: 2), array: ints) as Any) // third option

Type conversion when using protocol in Swift

Code Different's answer is right, but it's also important to understand why you can't just reinterpret the data without something doing an O(n) conversion to walk though and wrap each element in a box.

[A] is an array with elements the size of A. So, more or less, A[1] is at memory location A[0] + sizeof(A) (this isn't exactly true, but pretend it is; it'll make things simpler).

[Test] has to be able to hold anything that conforms to the protocol. It might be the size of A, it might be the size of B, which is larger. To achieve that, it creates a box that holds "something that conforms to Test". The box is of a known size, and it may have to heap-allocate the thing it points to (or maybe not; depends), but it ain't going to be the same size as both A and B, so the layout of [Test] in memory has to be different than the layout of [A] or [B].

Now as [Test] could do that O(n) walk for you and force a copy right then. Or it delay the copy until the first time you modified something, but it would be much more complicated and it would bury an O(n) (possibly expensive, possibly memory allocating) event inside an as which feels like it should be O(1) and allocate no memory. So there's reasons not to do that.

Some day they may do it anyway to make things simpler on the caller, but there's a cost in both performance and complexity, and so it doesn't do it today and you need to do the map yourself.

If you want a much deeper dive into this stuff, with more details on how this box works (and less "pretend it's simpler than it is"), see Understanding Swift Performance from WWDC 2016.



Related Topics



Leave a reply



Submit