Fluidity Fluidity - 3 months ago 7
Swift Question

Function to safely assign an optional to a var, or assign default if nil: Could not cast value of type 'Swift.Int' to 'Swift.String'

SOLVED



. . See bottom for functional code. Thanks @Sweeper!



Hey there!

. . I'm breaking bad once again asking for help--hopefully this code + any possible answers will help the community.

. . So I'm trying to make a method that allows me to safely assign optionals to the lhs, such as:

var cool_variable = risky_optional!
,

without necessarily interrupting the flow of whichever scope it's in.. the point of this is to cut down on control statements, and to not crash the program immediately on a forced unwrap (which I spend much time trying to design good code that doesn't do this naturally).

. . At first, I thought I had succeeded, because everything was working perfect... then on my fourth round of tests, I got a


Could not cast value of type 'Swift.Int' (0x105c52190) to 'Swift.String' (0x105c584d8).


. . I spent a good bit of time trying to refactor and rework, but I'm realizing that my understanding on generics, Any, and optionals just isn't concrete yet--though I do study and practice, every now and then I try to do something that just won't work.

Here's the code:






>> Here's a screenshot of the func, all nice and pretty in XCODE if that's your thing <<


>> And here is the implementation in XCODE <<

/**
Safely assign the lhs to this call--the value of $0?, or a default.
- Don't include ? or ! in the parameter
*/
func safeAssign <ReturnType> (value_to_return: ReturnType?)
-> ReturnType {

// Ensure safety
guard value_to_return != nil
else {

// Entry: found nil
print ("SA() -> 1 : SR: $0 was nil! Can't assign to lhs")

// -Value is irrelevant at this point
// -switch (value_to_return) would be confusing
let type = value_to_return

switch ( type ) {

case is Int?:
print("SA() -> 2.1: assigning lhs to default Int >0<")
return 0 as! ReturnType

case is String?:
print("SA() -> 2.2: assigning lhs to default String")
return "" as! ReturnType

default:
// In case our switch breaks, we will know why it crashes
print("SA() -> 2.0: No cases found--RTE incoming")

}//switch/>

// Should force crash, but at least I'll know exactly why
return type!

}//guard/>

// Let's get out of here safely ;)
print("SA() -> Exit: Successfully Assigned lhs to \(value_to_return!)")
return value_to_return!

}//safeAssign/>

//---------
// Testing:
//--------

// Optional for test 1-2
var int_opty : Int? = 5

// Soon to be safe-assigned
var zizzle = 0

// Safe assign to 5
print ("\n SA Test 1:")
zizzle = safeAssign(int_opty)

// Will cause a non-safe-assignment to force unwrap nil
int_opty = nil

// Safely assign to default value, instead of unwrapping nil
print ("\n SA Test2:")
zizzle = safeAssign(int_opty)
print(">>>>>>>>>> Zizzle is \(zizzle)")

// Optional for test 3-4
var str_opty : String? = "five"

// Soon to be safe-assigned
var zazzle = "zero"

// Safe assign to 5
print ("\n SA Test 3:")
zazzle = safeAssign(str_opty)

// Will cause a non-safe-assignment to force unwrap nil
str_opty = nil

// Safely assign to default value, instead of unwrapping nil
print ("\n SA Test 4:")
zazzle = safeAssign(str_opty)
print ("3: Zazzle is \(zazzle)")


The output:



SA Test 1:
SR -> Exit: Successfully Assigned lhs to 5

SA Test2:
SR -> 1 : SR: $0 was nil! Can't assign to lhs
SR -> 2.1: assigning lhs to default Int >0<
>>>>>>>>>> Zizzle is 0

SA Test 3:
SR -> Exit: Successfully Assigned lhs to five

SA Test 4:
SR -> 1 : SR: $0 was nil! Can't assign to lhs
SR -> 2.1: assigning lhs to default Int >0<
Could not cast value of type 'Swift.Int' (0x105c52190) to 'Swift.String' (0x105c584d8).





. . So I see where it's hanging up, tried replacing switch with If / Guard statements, tried it with Any, Optional<>, and a couple other approaches that got nowhere... I can't get it to work, and feel that I'd just be beating my head on the keyboard at this point in my knowledge of Swift

. . I don't really need this method, (because I try to be a good designer, haha), but it's always good to save a bit of whitespace, and if I use this for most of my assignments, then should a small bug pop up later, it's possible it could correct itself (say in a while loop or update cycle) instead of crashing the program.

. . That, and even though I'm sure something with Try/Catch could work...I want to figure out why this won't run so I can learn and be a better coder.

Thanks much.

Peace and blessings!
-Fluid




The Fix:



/**
Safely assign the lhs to this call--the value of $0?, or a default.
- Don't include ? or ! in the parameter
*/
func safeAssign <ReturnType> (value_to_return: ReturnType?) -> ReturnType {

// Ensure safety
guard value_to_return != nil else {

// Entry: found nil
print ("SR -> 1 : SR: $0 was nil! Can't assign to lhs")

// Value is irrelevant at this point--
// --switching value_to_return would be confusing
let type = value_to_return

switch ReturnType.self {

case is Int.Type:
print("SR -> 2.1: assigning lhs to default Int >0<")
return 0 as! ReturnType

case is String.Type:
print("SR -> 2.2: assigning lhs to default String")
return "" as! ReturnType

default:
// In case our switch breaks, we will know why it crashes
print("SR -> 2.0: No cases found--RTE incoming")

}//switch/>


// Should force crash, but at least I'll know exactly why
return type!

}//guard/>

// Let's get out of here safely ;)
print("SR -> Exit: Successfully Assigned lhs to \(value_to_return!)")
return value_to_return!

}//safeAssign/>


//---------
// Testing:
//--------

// Optional for test 1-2
var int_opty : Int? = 5

// Soon to be safe-assigned
var zizzle = 0

// Safe assign to 5
print("\n SA Test 1:")
zizzle = safeAssign(int_opty)

// Will cause a non-safe-assignment to force unwrap nil
int_opty = nil

// Safely assign to default value, instead of unwrapping nil
print("\n SA Test2:")
zizzle = safeAssign(int_opty)
print(">>>>>>>>>> Zizzle is \(zizzle)")

// Optional for test 3-4
var str_opty : String? = "five"

// Soon to be safe-assigned
var zazzle = "zero"

// Safe assign to 5
print("\n SA Test 3:")
zazzle = safeAssign(str_opty)

// Will cause a non-safe-assignment to force unwrap nil
str_opty = nil

// Safely assign to default value, instead of unwrapping nil
print("\n SA Test 4:")
zazzle = safeAssign(str_opty)
print("3: Zazzle is \(zazzle)")

Answer

Actually you don't need a method for this, just do:

zazzle = str_opty ?? ""

Easy!

I don't really know why your method fails to do the job. But I think it's better to switch ReturnType.self:

switch ReturnType.self {

case is Int.Type:
    print("SR -> 2.1: assigning lhs to default Int >0<")
    return 0 as! ReturnType

case is String.Type:
    print("SR -> 2.2: assigning lhs to default String")
    return "" as! ReturnType

default:
    // In case our switch breaks, we will know why it crashes
    print("SR -> 2.0: No cases found--RTE incoming")

}
Comments