Swift/iOS:如何在带有 AnyObject/Any 或指针的函数中使用 inout 参数

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)")
}

当你有一个 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"
var color: AnyObject = UIColor.blackColor()
var bool: AnyObject = false

setValue(&string, key:"String")
setValue(&color, key:"UIColor")
setValue(&bool, key:"Bool")

对 inout 的协议支持

当你将一个类转换为一个协议时,你最终会得到一个不可变的引用,它不能用于 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"