ios - Xcode Forcing Swift Optional Unwraps Twice (!!) -
i subclassing uistoryboardsegue , every time try use 1 of 2 uiviews, xcode making me add 2 optional unwraps (!!) such as:
let sourceview = self.sourceviewcontroller.view sourceview!!.frame = cgrect(x: 0, y: 0, width: screenwidth, height: screenheight or
let sourceview = self.sourceviewcontroller.view! sourceview!.frame = cgrect(x: 0, y: 0, width: screenwidth, height: screenheight or
self.sourceviewcontroller.view!!.frame = cgrect(x: 0, y: 0, width: screenwidth, height: screenheight i'm wondering if explain why is.
the sourceviewcontroller property of uistoryboardsegue typed anyobject, , objective-c compatibility feature, once import foundation, things little weird anyobject.
instead of looking methods on anyobject type, swift looks objective-c selectors instead, objective-c id type. selector class fair game: if wanted, try invoke activeprocessorcount on object, though that's nsprocessinfo selector, , compiler let it. (it fail @ runtime obvious reasons.) called dynamic dispatch, in opposition static dispatch (the normal calling mechanism in swift).
one thing dynamic dispatch, though, adds layer of implicit wrapping. if have objective-c property returns string, dynamic dispatch have return string!.
things hairy when multiple classes declare selectors same name different return types (or different parameters, we're not interested in case here). don't know how compiler chooses selector out of many identically-named ones knows about. either way, picks one, , you're stuck unless cast object more precise type, in case swift compiler let use static dispatch.
using swiftc's -dump-ast argument, can see lisp-like representation of how compiler parsed expression:
(pattern_binding_decl (pattern_named type='uiview?!' 'sourceview') (dynamic_member_ref_expr type='uiview?!' location=mysegue.swift:15:46 range=[mysegue.swift:15:25 - line:15:46] decl=uikit.(file).uigesturerecognizer.view (member_ref_expr type='anyobject' location=mysegue.swift:15:25 range=[mysegue.swift:15:25 - line:15:25] decl=uikit.(file).uistoryboardsegue.sourceviewcontroller (derived_to_base_expr implicit type='uistoryboardsegue' location=mysegue.swift:15:20 range=[mysegue.swift:15:20 - line:15:20] (declref_expr type='segue' location=mysegue.swift:15:20 range=[mysegue.swift:15:20 - line:15:20] decl=xxx.(file).segue.func decl.self@mysegue.swift:14:7 specialized=no))))) there's lot of cruft, can see generated dynamic_member_ref_expr instead of member_ref_expr. if scroll way right decl "attribute", you'll see using uigesturerecognizer's view property (declared uiview?), expression returns uiview?!.
in contrast, uiviewcontroller's view property declared uiview!. if compiler picked selector instead, have ended uiview!!, , need 1 level of explicit unwrapping.
you can (and must, in instances one) explicitly unwrap implicitly-unwrapped values. sourceview uiview?!, first ! unwraps uiview?! uiview?, , second 1 unwraps uiview? usable uiview. why need 2 exclamation marks.
the class declares selector used dynamic dispatch irrelevant, long target object implements it, accepts compatible arguments, , returns compatible type. uiview? , uiview! compatible @ binary level, in end, program still runs. however, if somehow expecting string or unrelated type, in surprise. in opinion, should avoid dynamic dispatch as can.
tl;dr: if cast sourceviewcontroller uiviewcontroller, correct view property definition , won't need unwrap @ all.
Comments
Post a Comment