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) { var string: String =”Default String” setValue(&string,”String”) |
我收到以下错误:
“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() |
这也给出了同样的错误:
“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”) |
希望对你有帮助!
- 如果您要强制转换(请不要,有更好的解决方案),您可以使用 value as! Thing 而不是 (value as? Thing)!。
- 这就是我要找的!非常感谢!
- 我一直在为与 OP 相同的错误消息而苦苦挣扎,所以谢谢你的回答!不过,我仍然不太明白为什么我们需要使用泛型函数,如果只是试图将一个子类转换为它的超类。
正确的做法是使用重载,让编译器在编译时选择合适的代码,而不是在运行时关闭字符串:
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) { func setValue(inout object: Bool) { func setValue(inout object: Any) { |
当你有一个 Any 并且你想向函数指示 Any 中包含什么类型时,这种方法不起作用……但在这种情况下,你遇到问题的原因是编译器确实知道类型是什么,所以你可以利用它。
- 非常感谢!对于简单的示例,这是一个很好的解决方案。在我的代码中,我宁愿在一种方法中使用它,因为还有代码可以从数据库中检索值。
- 将该代码分解为一个单独的函数,然后让重载调用调用它……
对象的类型要与参数的类型相匹配,包括AnyObject:
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” setValue(&string, key:”String”) |
对 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) |
- 这不能与 inout 结合使用(好吧,它可能会编译……但它可能不会产生预期的效果)
- 添加了示例,该示例按预期编译和运行。你的意思是不会有预期的效果?
- 这不是强制转换(即 someVar as Any),而是将值本身声明为 Any 类型。但是,大概提问者具有 String 类型的值,并希望就地操作该字符串。您的建议要求他们将该类型声明为 Any。在大多数情况下都有更好的方法(即重载或泛型)。 Any 很少是一个好的选择。
- 感谢您的输入。我觉得 OP 本身实施的模式可能不是最合适的……
来源:https://www.codenong.com/29963848/