swift - Is there a way to use a Template, and In-Out Parameter and Optional together? -


i ran interesting behaviour other day. wrote helper function prevent errors while automatically typecasting json property. looked this:

func readdata<t>(inout output:t, _ input:anyobject?, _ throwerror:bool = true) throws {     if (input == nil) {         if (throwerror) {             throw converterror.missingparameter         }     }     else {         if let inputobject:t = input as? t {             output = inputobject         }         else if (throwerror) {             throw converterror.wrongtype         }     } }  var myproperty:string try readdata(&myproperty, myjson["data"], true) 

this checks property exists, , it's right type. if goes well, value inside myproperty changes.

a little while later, needed make changes. made class called properties , has list of properties inside of it. there 2 variables of type of class: originalproperties , modifiedproperties each of properties inside these classes optional variables now, keep track of properties user has changed. looks this:

class properties {     var x:int?     var y:int? } 

now when run this:

try readdata(&originalproperties.x, myjson["x"], false) 

it doesn't work anymore. looked @ another question , explained happening. while x still had value of nil (because it's optional), passing nil value readdata function, template type isn't set , that's why fails on input as? t code.

fortunately, don't have have such creative function anymore. can use this:

originalproperties.x= obj["x"] as? int 

but i'll lose thrown error functionality if needed it.

does have ideas how can make sure template type gets passed correctly while still has value of nil? read in thread might have use sort of default value closure, interesting see if there's way work around this.

the main problem here generic t can never itself know if of optional type or not, makes successful type conversion t tricky cases when t in fact of type optional<sometype>. could, ourselves, assert t optional type (checking mirror(reflecting: ...).displaystyle == .optional etc), still doesn't solve conversion t right off bat. instead, use approach, follows below.

we can work around problem creating 2 readdata(...) functions, 1 taking optional generic inout parameter, type u?, , other 1 taking implicitly non-optional generic inout parameter u (called if u? function cannot used, hence implicitly called non-optionals). these 2 functions, in turn, minimal , calls "core" datareader(..) function, we've made adjustment inout generic parameter explicitly optional, i.e., t?.

enum converterror: errortype {     case missingparameter     case wrongtype }  /* optional inout parameter */ func readdata<u>(inout output: u?, _ input: anyobject?, _ throwerror: bool = true) throws {     try readdatacore(&output, input, throwerror) }  /* non-optional inout parameter */ func readdata<u>(inout output: u, _ input: anyobject?, _ throwerror: bool = true) throws {     var outputopt : u? = output     try readdatacore(&outputopt, input, throwerror)     output = outputopt!     /* use guard-throw here unwrapping of 'outputopt',        note 'outputopt' initialized non-nil value, , can        never become 'nil' in readdatahelper; "safe" forced unwrapping here.    */ }  /* "core" function */ func readdatacore<t>(inout output: t?, _ input: anyobject?, _ throwerror: bool = true) throws {     if (input == nil) {         if (throwerror) {             throw converterror.missingparameter         }     }     else {         if let inputobject: t = input as? t {             output = inputobject         }         else if (throwerror) {             throw converterror.wrongtype         }     } } 

as try out, see behaviour we're looking for, if argument sent inout parameter nil or optional.


example 1: using optional inout param value nil

class properties {     var x:int?     var y:int? }  var myjson : [string:int] = ["data":10] var originalproperties = properties()  {     try readdata(&originalproperties.x, myjson["data"], true)     print("originalproperties.x = \(originalproperties.x ?? 0)") } catch converterror.missingparameter {     print("missing parameter") } catch converterror.wrongtype {     print("wrong type") } catch {     print("unknown error") } /* prints: 'originalproperties.x = 10', ok! */  // try non-existing key 'foo' {     try readdata(&originalproperties.x, myjson["foo"], true)     print("originalproperties.x = \(originalproperties.x ?? 0)") } catch converterror.missingparameter {     print("missing parameter") } catch converterror.wrongtype {     print("wrong type") } catch {     print("unknown error") } /* prints: 'missing parameter', ok! */ 

example 2: using optional inout param with, however, non-optional value

class properties {     var x:int? = 1     var y:int? = 1 }  var myjson : [string:int] = ["data":10] var originalproperties = properties()  // ...  /* same results example 1:     'originalproperties.x = 10' , 'missing parameter' */ 

example 3: using non-optional inout parameter

class properties {     var x:int = 1     var y:int = 1 }  var myjson : [string:int] = ["data":10] var originalproperties = properties()  // ...  /* same results example 1:     'originalproperties.x = 10' , 'missing parameter' */ 

Comments

Popular posts from this blog

get url and add instance to a model with prefilled foreign key :django admin -

css - Make div keyboard-scrollable in jQuery Mobile? -

ruby on rails - Seeing duplicate requests handled with Unicorn -