【问题标题】:Swift/iOS: How to use inout parameters in functions with AnyObject/Any or PointersSwift/iOS:如何在带有 AnyObject/Any 或指针的函数中使用 inout 参数
【发布时间】:2015-04-30 09:23:13
【问题描述】:

我正在尝试编写一个函数,该函数采用变量指针和描述符/键并为变量设置新值。理想情况下,指针应该是对象或原语,但我也可以使用单独的函数(或附加参数)。 在我的代码中,我也使用键从数据库中检索新值,但在以下示例中,我使用虚拟值对其进行了简化,以便可以在游乐场中轻松使用:

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

我收到以下错误:

"不能使用类型为 '(inout) 的参数列表调用 'setValue' 字符串,键 String)'"

我知道我在这里混合了对象和基元。我也尝试将其分解并将它们分成两个函数,但即使这样也失败了:

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

这也给出了同样的错误:

"不能使用类型为 '(inout) 的参数列表调用 'setValue' UIColor, key String)'"

如果我将“AnyObject”更改为“UIColor”,它可以工作,但函数的重点是,它需要任何变量类型或至少任何对象类型(我会使用“Any”为基元编写第二个函数然后或添加另一个参数)

在 Objective-C 中我使用指针,将方法转移到 Swift 也不起作用,结果相同:

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

有人知道我在这里缺少什么吗?非常感谢任何帮助!

谢谢!

【问题讨论】:

    标签: ios swift pointers object parameters


    【解决方案1】:

    你可以创建一个像下面这样的通用方法:

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

    调用会是这样的:

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

    希望对你有帮助!

    【讨论】:

    • 如果您要强制转换(请不要,有更好的解决方案),您可以使用value as! Thing 而不是(value as? Thing)!
    • 这就是我要找的!非常感谢!
    • 我一直在为与 OP 相同的错误消息而苦苦挣扎,所以感谢您的回答!不过,如果我们只是想将子类转换为超类,我仍然不太明白为什么需要使用泛型函数。
    【解决方案2】:

    正确的做法是使用重载,让编译器在编译时选择适当的代码位,而不是在运行时关闭字符串:

    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 中包含的类型时,此方法将不起作用...但在这种情况下,您遇到问题的原因是编译器 确实知道类型是什么,所以你可以利用它。

    【讨论】:

    • 非常感谢!对于简单的示例,这是一个很好的解决方案。在我的代码中,我宁愿使用一种方法,因为还有代码可以从数据库中检索值。
    • 将代码分解成一个单独的函数,然后让重载的调用调用它……
    【解决方案3】:

    -使用 Any 而不是 AnyObject 来覆盖值类型和结构。

    -在调用您的方法之前,您可能需要强制转换为 Any。

    例子:

    func swapAny( inout obj1: Any, inout obj2: Any )
    {
        let temp = obj1
        obj1 = obj2
        obj2 = temp
    }
    

    使用:

    var fooString: Any = "Foo"
    var barString: Any = "Bar"
    
    swapAny(&fooString, obj2: &barString)
    println(fooString)//prints "Bar"
    

    【讨论】:

    • 这不能与inout 结合使用(好吧,它可能会编译......但它可能不会达到预期的效果)
    • 添加了示例,该示例可以按预期进行编译和运行。您所说的“不会产生预期的效果”是什么意思?
    • 这不是强制转换(即someVar as Any),这是将值本身声明为Any类型。但是,大概提问者的值类型为String,并希望就地操作该字符串。您的建议要求他们将该类型声明为Any。在大多数情况下都有更好的方法(即重载或泛型)。 Any 很少是一个好的选择。
    • 感谢您的意见。我觉得 OP 本身实现的模式可能不是最合适的......
    【解决方案4】:

    inout 协议支持

    当你将一个类转换为一个协议时,你最终会得到一个不可变的引用,它不能在 inout 函数参数中使用。所以你可以:

    1. 使用方法重载(即使你重构,它也会重复你的代码并使其先天难以阅读)
    2. 不使用 inout(这是你应该做的)
    3. 或者你可以这样做:

    -

    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)

    【讨论】:

      【解决方案5】:

      对象的类型要与参数的类型相匹配,包括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")
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-28
        • 1970-01-01
        • 2014-12-04
        • 2020-09-17
        • 1970-01-01
        • 1970-01-01
        • 2021-06-29
        • 1970-01-01
        相关资源
        最近更新 更多