I'm trying to write a function that takes a variable pointer and a descriptor/key and sets a new value for the variable. Ideally the pointer should be either of an object or a primitive, but I could also live with separate functions (or an additional parameter). In my code I retrieve the new value from a database also using the key, but in the following example I simplified it with dummy values so that it can be used easily in a playground:
import UIKit
func setValue(inout object: AnyObject, key: String) {
switch key {
case "String":
object = "A String"
case "UIColor":
object = UIColor.whiteColor()
case "Bool":
object = true
default:
println("Unhandled key: \(key)")
}
}
var string: String = "Default String"
var color: UIColor = UIColor.blackColor()
var bool: Bool = false
setValue(&string, "String")
setValue(&color, "UIColor")
setValue(&bool, "Bool")
I get the following error:
"Cannot invoke 'setValue' with an argument list of type '(inout String, key String)'"
I understand that I'm mixing Objects and Primitives here. I also tried to break it down and separate these into two functions, but even that fails:
func setValue(inout object: AnyObject, key: String) {
switch key {
case "UIColor":
object = UIColor.whiteColor()
default:
println("Unhandled key: \(key)")
}
}
var color: UIColor = UIColor.blackColor()
setValue(&color, "UIColor")
This also gives the same error:
"Cannot invoke 'setValue' with an argument list of type '(inout UIColor, key String)'"
If I change 'AnyObject' to 'UIColor' it works, but the point of the function is, that it takes any variable type or at least any object type (I'd write a second function using "Any" for primitives then or add another parameter)
In Objective-C I was using pointers, transferring the approach to Swift also doesn't work, same result:
func setValue(object: UnsafeMutablePointer<AnyObject>, key: String) {
switch key {
case "String":
object.memory = "A String"
case "UIColor":
object.memory = UIColor.whiteColor()
case "Bool":
object.memory = true
default:
println("Unhandled key: \(key)")
}
}
Does anybody have an idea what I'm missing here? Any help is much appreciated!
Thanks!
Better you can create a generic method like below:
func setValue<T>(inout object:T, key: String) {
switch key {
case "String":
object = ("A String" as? T)!
case "UIColor":
object = (UIColor.whiteColor() as? T)!
case "Bool":
object = (true as? T)!
default:
println("Unhandled key: \(key)")
}
}
And calling will be like this:
setValue(&string, key: "String")
setValue(&color, key: "UIColor")
setValue(&bool, key: "Bool")
Hope it helps!
The right way to do this is to use overloading, and letting the compiler choose the appropriate bit of code at compile time, instead of switching off a string at runtime:
func setValue(inout object: String) {
object = "A String"
}
func setValue(inout object: UIColor) {
object = UIColor.whiteColor()
}
func setValue(inout object: Bool) {
object = true
}
func setValue(inout object: Any) {
println("Unhandled key: \(key)")
}
This approach wouldn't work when you have an Any
and you want to indicate to the function what type is contained in the Any
… but in this case, the reason you have problems is that the compiler does know what the types are, so you can take advantage of that.
-Use Any instead of AnyObject to cover value types and structs.
-You may need to cast to Any before calling your method.
Example:
func swapAny( inout obj1: Any, inout obj2: Any )
{
let temp = obj1
obj1 = obj2
obj2 = temp
}
use:
var fooString: Any = "Foo"
var barString: Any = "Bar"
swapAny(&fooString, obj2: &barString)
println(fooString)//prints "Bar"
When you cast a class to a protocol you end up with an immutable reference, which cant be used in inout function parameters. So you can:
-
protocol IPositional{
func setPosition(position:CGPoint)
}
extension IPositional{
var positional:IPositional {get{return self as IPositional}set{}}
}
class A:IPositional{
var position:CGPoint = CGPoint()
func setPosition(position:CGPoint){
self.position = position
}
}
func test(inout positional:IPositional){
positional.setPosition(CGPointMake(10,10))
}
var a = A()
test(&a.positional)
a.position//output: (10.0, 10.0)
Conclusion:
The benefit of doing it this way: Is that you can now have one "inout method" for all classes that implements IPositional But I recommend going with option 2. (Not using inout)
The type of object should match the type of parameter, including AnyObject
:
func setValue(inout object: AnyObject, key: String) {
switch key {
case "String":
object = "A String"
case "UIColor":
object = UIColor.whiteColor()
case "Bool":
object = true
default:
print("Unhandled key: \(key)")
}
}
var string: AnyObject = "Default String"
var color: AnyObject = UIColor.blackColor()
var bool: AnyObject = false
setValue(&string, key: "String")
setValue(&color, key: "UIColor")
setValue(&bool, key: "Bool")
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.