Swift/iOS: How to use inout parameters in functions with AnyObject/Any or Pointers
我正在尝试编写一个函数,该函数采用变量指针和描述符/键并为变量设置新值。理想情况下,指针应该是对象或原语,但我也可以使用单独的函数(或附加参数)。
在我的代码中,我也使用键从数据库中检索新值,但在以下示例中,我使用虚拟值对其进行了简化,以便可以在游乐场中轻松使用它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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") |
我收到以下错误:
"Cannot invoke 'setValue' with an argument list of type '(inout
String, key String)'"
我知道我在这里混合了对象和基元。我还尝试将其分解并将它们分成两个函数,但即使这样也失败了:
1 2 3 4 5 6 7 8 9 10 11 | 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") |
这也给出了同样的错误:
"Cannot invoke 'setValue' with an argument list of type '(inout
UIColor, key String)'"
如果我将 'AnyObject' 更改为 'UIColor' 它可以工作,但函数的重点是,它需要任何变量类型或至少任何对象类型(我会使用"Any"为基元编写第二个函数然后或添加另一个参数)
在 Objective-C 中我使用指针,将方法转移到 Swift 也不起作用,结果相同:
1 2 3 4 5 6 7 8 9 10 11 12 | 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)") } } |
有人知道我在这里缺少什么吗?非常感谢任何帮助!
谢谢!
你可以创建一个像下面这样的通用方法:
1 2 3 4 5 6 7 8 9 10 11 12 | 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)") } } |
调用会是这样的:
1 2 3 | setValue(&string, key:"String") setValue(&color, key:"UIColor") setValue(&bool, key:"Bool") |
希望对你有帮助!
正确的做法是使用重载,让编译器在编译时选择合适的代码,而不是在运行时关闭字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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)") } |
当你有一个
对象的类型要与参数的类型相匹配,包括
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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") |
对 inout 的协议支持
当你将一个类转换为一个协议时,你最终会得到一个不可变的引用,它不能用于 inout 函数参数。所以你可以:
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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) |
结论:
这样做的好处是:您现在可以为所有实现 IPositional 的类提供一个"inout 方法"
但我建议使用选项 2。(不使用 inout)
-使用 Any 而不是 AnyObject 来覆盖值类型和结构。
-在调用方法之前,您可能需要强制转换为 Any。
示例:
1 2 3 4 5 6 | func swapAny( inout obj1: Any, inout obj2: Any ) { let temp = obj1 obj1 = obj2 obj2 = temp } |
使用:
1 2 3 4 5 | var fooString: Any ="Foo" var barString: Any ="Bar" swapAny(&fooString, obj2: &barString) println(fooString)//prints"Bar" |