在Dictionary中作为值的Swift闭包
我试图使用一个Objective-C库,它期望一个NSDictionary
作为它的返回types。 在NSDictionary
,我可以返回任何types的值,包括块。
我不知道是否有办法编写一个类似的swift方法返回一个封闭或string作为一个可能的值types的字典。
我不能使用AnyObject
作为字典的值types,所以这是行不通的:
Dictionary<String,AnyObject> = ["Key":{(value:AnyObject) -> String in return value.description]
我得到一个Does not conform to protocol error
编译器有closures包和AnyObject
Does not conform to protocol error
。
有一个更高级别的types或协议,闭包和基本types坚持,我可以使用作为一个字典中的值types?
你的基本问题是,在Objective-C闭包(又名块)被表示为NSObject(或更确切地说是透明地转换成NSObject),而在Swift中没有这样的映射。 这意味着闭包不能直接存储在Dictionary中(使用objective-c胶水不足)
我能拿出的最接近的东西是沿着enum中的值包装的东西:
enum DataType { case AsString(String) case AsClosure((AnyObject)->String) } var dict:Dictionary<String,DataType> = [ "string":DataType.AsString("value"), "closure":DataType.AsClosure({(argument:AnyObject) -> String in return "value" } ) ]
无论如何,这可能是一个更好的解决scheme,因为这样你就有了一个与单个参数相关联的显式types,而不是使用某种变形隐式的。
或者,您只能包装闭包,并使用Dictionary<String,Any>
types的Dictionary<String,Any>
。
如果你仍然需要一个解决方法,这里是一个; 用法如下所示:
var d : [String : AnyObject] = [:] d["a"] = Blocks.voidBlockToId({ println("Doing something") }) d["b"] = "Some string" d["c"] = Blocks.intBlockToId({ i in println("Called with integer: \(i)") }) Blocks.toIntBlock(d["c"])(1) Blocks.toVoidBlock(d["a"])() println(d["b"])
输出是:
- 用整数调用:1
- 做点什么
- 一些string
在类Objective-C中定义了Blocks
类(带有相应的头文件和桥接头文件,我不会在这里):
typedef void(^VoidBlock)(void); typedef void(^IntBlock)(int); @implementation Blocks + (id) voidBlockToId: (VoidBlock) block { return block; } + (VoidBlock) toVoidBlock: (id) block { return (VoidBlock)block; } + (id) intBlockToId: (IntBlock) block { return block; } + (IntBlock) toIntBlock:(id)block { return (IntBlock)block; } @end
您还需要为每个要使用的新闭包添加新的xyzBlockToId
和toXyzBlock
方法。 这是非常丑陋的,但它的作品。
还有另外一种types, Any
,物体,结构和原始都符合,但function不符合。 没有通用的函数types,但可以将函数types描述为参数并返回如下所示的值:
Dictionary<String, (AnyObject) -> String>
函数types
你可以使用一个NSMutableDictionary
?
或者,这似乎适用于我使用你的例子:
1> import Foundation 2> var myDict: [String: (NSObject) -> String] = ["Key":{(value:NSObject) -> String in return value.description}] myDict: [String : (NSObject) -> String] = { [0] = { key = "Key" value = } } 3> myDict["Key"]!("Testing")
$ R2:String =“testing”
嗯,也许这个Swift-Code并没有真正的帮助,因为你想要有不同的字典。
它也不可能把闭包放入一个NSDictionary
,看起来(因为闭包不符合AnyObject
)。
你也可以使用enum
来滚动你自己的高级types。 您需要字典值是string或返回string的函数,所以定义一个types来表示:
enum MyDictVal { case ValString(String) case ValFunc(AnyObject -> String) }
那么,你可以把它放在一个字典中:
let d: Dictionary<String, MyDictVal> = [ "a": .ValString("a") , "b": .ValFunc({ (value) in value.description }) ]
那么你需要使用模式匹配来处理字典值:
switch d["b"] { case .ValString(let s): ... case .ValFunc(let f): ... }
一个更“通用”的解决scheme应该与Any
对象,但与闭包和函数引用显示。 把它放到操场上试试看!
// Wrapper for sticking non-objects in NSDictionary instances class ObjectWrapper { let value: T init(_ value: T) { self.value = value } } // convenience to downcast `as! ObjectWrapper` and return its value func getValueFromObjectWrapper(a: AnyObject) -> T { return (a as! ObjectWrapper).value } func wrappedObjectsInDictionary() -> NSDictionary { var dict = NSMutableDictionary() let appendToFoo: (String) -> String = NSString.stringByAppendingString("foo") let firstChar: (String) -> Character = { $0[$0.startIndex] } dict.setObject(ObjectWrapper(firstChar), forKey: "stringToChar") dict.setObject(ObjectWrapper(appendToFoo), forKey: "stringTransformer") return dict.copy() as! NSDictionary } let dict = wrappedObjectsInDictionary() let appendToFoo: (String) -> String = getValueFromObjectWrapper(dict["stringTransformer"]!) let strToChar: (String) -> Character = getValueFromObjectWrapper(dict["stringToChar"]!) appendToFoo("bar") // "foobar" strToChar("bar") // "b"