Swift/iOS:如何在带有 AnyObject/Any 或指针的函数中使用 inout 参数
Swift/iOS: How to use inout parameters in functions with AnyObject/Any or Pointers
我正在尝试编写一个函数,它接受一个变量指针和一个 descriptor/key 并为该变量设置一个新值。理想情况下,指针应该是对象或原始指针,但我也可以使用单独的函数(或附加参数)。
在我的代码中,我也使用密钥从数据库中检索新值,但在下面的示例中,我使用虚拟值对其进行了简化,以便可以在操场上轻松使用它:
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)'"
我知道我在这里混合了对象和图元。我也试图将其分解并将它们分成两个函数,但即使这样也失败了:
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也不起作用,结果相同:
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)")
}
}
有人知道我在这里遗漏了什么吗?非常感谢任何帮助!
谢谢!
-使用 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"
正确的做法是使用重载,让编译器在编译时选择适当的代码位,而不是在运行时关闭字符串:
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
中包含什么类型时,这种方法不起作用......但在这种情况下,你遇到问题的原因是编译器 确实 知道类型是什么,因此您可以利用它。
你最好创建一个如下所示的通用方法:
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")
希望对您有所帮助!
inout 协议支持
当您将 class 转换为协议时,您最终会得到一个不可变的引用,它不能在 inout 函数参数中使用。所以你可以:
- 使用方法重载(这可能会复制您的代码并使其天生更难阅读,即使您进行重构也是如此)
- 不使用inout(这是你应该做的)
- 或者您可以这样做:
-
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 的 classes 使用一个 "inout method"
但我建议使用选项 2。(不使用 inout)
对象的类型要匹配参数的类型,包括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")
我正在尝试编写一个函数,它接受一个变量指针和一个 descriptor/key 并为该变量设置一个新值。理想情况下,指针应该是对象或原始指针,但我也可以使用单独的函数(或附加参数)。 在我的代码中,我也使用密钥从数据库中检索新值,但在下面的示例中,我使用虚拟值对其进行了简化,以便可以在操场上轻松使用它:
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)'"
我知道我在这里混合了对象和图元。我也试图将其分解并将它们分成两个函数,但即使这样也失败了:
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也不起作用,结果相同:
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)")
}
}
有人知道我在这里遗漏了什么吗?非常感谢任何帮助!
谢谢!
-使用 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"
正确的做法是使用重载,让编译器在编译时选择适当的代码位,而不是在运行时关闭字符串:
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
中包含什么类型时,这种方法不起作用......但在这种情况下,你遇到问题的原因是编译器 确实 知道类型是什么,因此您可以利用它。
你最好创建一个如下所示的通用方法:
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")
希望对您有所帮助!
inout 协议支持
当您将 class 转换为协议时,您最终会得到一个不可变的引用,它不能在 inout 函数参数中使用。所以你可以:
- 使用方法重载(这可能会复制您的代码并使其天生更难阅读,即使您进行重构也是如此)
- 不使用inout(这是你应该做的)
- 或者您可以这样做:
-
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 的 classes 使用一个 "inout method"
但我建议使用选项 2。(不使用 inout)
对象的类型要匹配参数的类型,包括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")