在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. 用整数调用:1
  2. 做点什么
  3. 一些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 

您还需要为每个要使用的新闭包添加新的xyzBlockToIdtoXyzBlock方法。 这是非常丑陋的,但它的作品。

还有另外一种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"