NicolasMiari NicolasMiari - 4 years ago 88
Swift Question

Call function that throws and attempt to cast the returned value, abort silently if either fails

I'm

guard
ing the call to a method that may throw (a CoreData fetch request), and at the same time I'm casting the returned value to a specific type of array:

guard let results = try? managedContext.executeFetchRequest(fetchRequest) as? [MyManagedObjectClass] else {

// Bail out if fetch or cast fails:
return
}


The way I understand it is that, because I'm using
guard/try?/else
(instead of
do/try/catch
), the
else
block (i.e.
return
statement) above will be executed if either of the following occurs:


  1. The fetch request fails (and
    throw
    s)

  2. The fetch request succeeds but casting of the returned value to
    [MyManagedObjectClass]
    fails.



The code above works, but the after control successfully passes the
guard
check, the variable
results
ends up as being of type
[MyManagedObjectClass]?
("optional array of
MyManagedObjectClass
").

So if I want to -say- loop through the array elements I have to first unwrap it:

if let results = results {
// now, 'results' is of type:
// "(non-optional) Array of MyManagedObjectClass"

for element in results {
// (process each element...)
}
}


I could use
as!
instead of
as?
when casting after the
guard
statement; that makes
results
a non-optional array.

But then, if the fetch succeeds but the cast fails, It will still trigger a runtime error (crash) instead of control flowing to the
else
block, right?.

Is there a smarter way? (catch both errors, end up with a non-optional array)




Note: I understand that lumping both failure causes (fetch and cast) together into one
else
block is not the best design, and perhaps I should check for both separately (perhaps I should use the more traditional
do/try/catch
), but I would like to better grasp the details of this complex construct.

Answer Source

You need to wrap the try call into parentheses:

let results = (try? managedContext.executeFetchRequest(fetchRequest)) as? [MyManagedObjectClass]

otherwise try? will apply to the whole expression, generating an optional value that gets assigned to results.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download