János János - 9 days ago 5
iOS Question

Convert generic array to NSOrderedSet?

I need to assign return value of a

fetch
:

try! c.fetch(fr)


to a to-many relationship (
itemsWithoutRatingOfLoggedInUser
):

Utility.app(c: c).itemsWithoutRatingOfLoggedInUser = try! c.fetch(fr2)


And got following error. What can I do? I tried to cast with
as!
operator, did not help.

enter image description here

Answer

Casting (with as) is for cases where a value of one type can be interpreted as a value of some other, explicitly related type. This interpretation is defined in terms of language features: either type relationships (like inheritance or protocol conformance), or the handful of special cases where Swift can bridge Foundation or CF types to/from their Swift Standard Library equivalents.

When you cast, you're asking the Swift compiler/runtime to squint its eyes a little and pretend that one type is another. (Maybe even do a little twiddling behind the scenes so that pretending works.) Most often, casting happens when you have a value where you know more about its type than Swift (in the context of the function you're writing) does.

When you have types that aren't explicitly related though language features — that is, one isn't a subclass of the other, or one isn't a protocol adopted by the other, or they aren't one of the special sets of equivalent types from Foundation/CF that Swift knows how to bridge — you have to convert, not cast. (Swift also makes you convert instead of casting when types are semantically different enough that you need to think about the consequences of conversion, like when going between signed and unsigned integers.)

Array and NSOrderedSet are semantically different enough types that you have to convert, not cast.

Conversion between types requires that the type being converted to know about the type being converted from, so to perform a conversion you use an initializer of the target type.

let stuff = managedObjectContext.fetch(request)
let orderedSet = NSOrderedSet(array: stuff)

Note that NSOrderedSet is not a generic type in Swift 3, so even if you create it from a typed array ([MyObject]), the elements come out as Any. That's a use case for casting:

let item = orderedSet as! MyObject