I'm trying to write a function that takes a variable pointer and a descriptor/key and sets a new value for the variable. Ideally the pointer should be either of an object or a primitive, but I could also live with separate functions (or an additional parameter). In my code I retrieve the new value from a database also using the key, but in the following example I simplified it with dummy values so that it can be used easily in a playground:
我正在编写一个函数,它接受一个变量指针和一个描述符/键,并为变量设置一个新值。理想情况下,指针应该是对象或原语,但我也可以使用单独的函数(或附加的参数)。在我的代码中,我也使用密钥从数据库中检索新值,但是在下面的示例中,我使用假值对其进行了简化,以便在操场上轻松使用:
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")
I get the following error:
我得到以下错误:
"Cannot invoke 'setValue' with an argument list of type '(inout String, key String)'"
"不能用类型的参数列表调用'setValue' (inout String, key String)'"
I understand that I'm mixing Objects and Primitives here. I also tried to break it down and separate these into two functions, but even that fails:
我知道我在这里混合了对象和原语。我也试着把它分解成两个函数,但即使这样也不行
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")
This also gives the same error:
这也会产生相同的错误:
"Cannot invoke 'setValue' with an argument list of type '(inout UIColor, key String)'"
"不能用类型的参数列表调用'setValue' (inout UIColor, key String) "
If I change 'AnyObject' to 'UIColor' it works, but the point of the function is, that it takes any variable type or at least any object type (I'd write a second function using "Any" for primitives then or add another parameter)
如果我将'AnyObject'改为'UIColor'它是有效的,但函数的要点是,它接受任何变量类型或至少任何对象类型(我将使用“any”为原语编写第二个函数,然后添加另一个参数)
In Objective-C I was using pointers, transferring the approach to Swift also doesn't work, same result:
在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)")
}
}
Does anybody have an idea what I'm missing here? Any help is much appreciated!
有人知道我漏掉了什么吗?非常感谢您的帮助!
Thanks!
谢谢!
5 个解决方案
#1
8
Better you can create a generic method like below:
您可以更好地创建如下的泛型方法:
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)")
}
}
And calling will be like this:
打电话会是这样的:
setValue(&string, key: "String")
setValue(&color, key: "UIColor")
setValue(&bool, key: "Bool")
Hope it helps!
希望它可以帮助!
#2
7
The right way to do this is to use overloading, and letting the compiler choose the appropriate bit of code at compile time, instead of switching off a string at runtime:
正确的做法是使用重载,让编译器在编译时选择适当的代码位,而不是在运行时关闭字符串:
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)")
}
This approach wouldn’t work when you have an Any
and you want to indicate to the function what type is contained in the Any
… but in this case, the reason you have problems is that the compiler does know what the types are, so you can take advantage of that.
当你有一个Any的时候,这种方法是行不通的,你想要告诉函数Any中包含了什么类型,但是在这种情况下,你遇到问题的原因是编译器知道类型是什么,所以你可以利用它。
#3
0
-Use Any instead of AnyObject to cover value types and structs.
-使用Any而不是AnyObject来覆盖值类型和结构。
-You may need to cast to Any before calling your method.
-在调用方法之前,您可能需要对任何方法进行强制转换。
Example:
例子:
func swapAny( inout obj1: Any, inout obj2: Any )
{
let temp = obj1
obj1 = obj2
obj2 = temp
}
use:
使用:
var fooString: Any = "Foo"
var barString: Any = "Bar"
swapAny(&fooString, obj2: &barString)
println(fooString)//prints "Bar"
#4
0
Protocol support for inout
When you cast a class to a protocol you end up with an immutable reference, which cant be used in inout function parameters. So you can:
当您将类强制转换为协议时,您将得到一个不可变引用,这在inout函数参数中不能使用。所以你可以:
- Use Method overloading (which can duplicate your code and make it congenitally harder to read, even if you refactor)
- 使用方法重载(它可以复制您的代码,并使其更难于阅读,即使您重构)
- Not use inout (this is what you should do)
- 不使用inout(这是您应该做的)
- Or you can do this:
- 或者你可以这样做:
-
- - - - - -
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)
Conclusion:
The benefit of doing it this way: Is that you can now have one "inout method" for all classes that implements IPositional But I recommend going with option 2. (Not using inout)
结论:这样做的好处是:对于实现iposition的所有类,现在都可以有一个“inout方法”,但我建议使用选项2。(不使用inout)
#5
0
The type of object should match the type of parameter, including AnyObject
:
对象的类型应该匹配参数的类型,包括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")
#1
8
Better you can create a generic method like below:
您可以更好地创建如下的泛型方法:
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)")
}
}
And calling will be like this:
打电话会是这样的:
setValue(&string, key: "String")
setValue(&color, key: "UIColor")
setValue(&bool, key: "Bool")
Hope it helps!
希望它可以帮助!
#2
7
The right way to do this is to use overloading, and letting the compiler choose the appropriate bit of code at compile time, instead of switching off a string at runtime:
正确的做法是使用重载,让编译器在编译时选择适当的代码位,而不是在运行时关闭字符串:
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)")
}
This approach wouldn’t work when you have an Any
and you want to indicate to the function what type is contained in the Any
… but in this case, the reason you have problems is that the compiler does know what the types are, so you can take advantage of that.
当你有一个Any的时候,这种方法是行不通的,你想要告诉函数Any中包含了什么类型,但是在这种情况下,你遇到问题的原因是编译器知道类型是什么,所以你可以利用它。
#3
0
-Use Any instead of AnyObject to cover value types and structs.
-使用Any而不是AnyObject来覆盖值类型和结构。
-You may need to cast to Any before calling your method.
-在调用方法之前,您可能需要对任何方法进行强制转换。
Example:
例子:
func swapAny( inout obj1: Any, inout obj2: Any )
{
let temp = obj1
obj1 = obj2
obj2 = temp
}
use:
使用:
var fooString: Any = "Foo"
var barString: Any = "Bar"
swapAny(&fooString, obj2: &barString)
println(fooString)//prints "Bar"
#4
0
Protocol support for inout
When you cast a class to a protocol you end up with an immutable reference, which cant be used in inout function parameters. So you can:
当您将类强制转换为协议时,您将得到一个不可变引用,这在inout函数参数中不能使用。所以你可以:
- Use Method overloading (which can duplicate your code and make it congenitally harder to read, even if you refactor)
- 使用方法重载(它可以复制您的代码,并使其更难于阅读,即使您重构)
- Not use inout (this is what you should do)
- 不使用inout(这是您应该做的)
- Or you can do this:
- 或者你可以这样做:
-
- - - - - -
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)
Conclusion:
The benefit of doing it this way: Is that you can now have one "inout method" for all classes that implements IPositional But I recommend going with option 2. (Not using inout)
结论:这样做的好处是:对于实现iposition的所有类,现在都可以有一个“inout方法”,但我建议使用选项2。(不使用inout)
#5
0
The type of object should match the type of parameter, including AnyObject
:
对象的类型应该匹配参数的类型,包括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")