簡體   English   中英

Swift閉包為Dictionary中的值

[英]Swift closure as values in Dictionary

我正在嘗試使用一個Objective-C庫,它希望NSDictionary作為其返回類型。 NSDictionary ,我可以返回任何類型的值,包括塊。

我無法弄清楚是否有辦法編寫一個類似的swift方法,它返回一個帶有閉包或字符串作為可能的值類型的Dictionary。

我不能使用AnyObject作為字典的值類型,所以這不起作用:

Dictionary<String,AnyObject> = ["Key":{(value:AnyObject) -> String in return value.description]

我得到一個Does not conform to protocol error編譯器關於閉包和AnyObject Does not conform to protocol error

是否有更高級別的類型或協議,閉包和基本類型都遵循我可以用作詞典中的值類型?

你的基本問題是Objective-C閉包(aka塊)表示為NSObject(或更准確地說是透明地轉換為NSObjects),而在Swift中沒有這樣的映射。 這意味着閉包不能直接存儲在Dictionary中(不能使用objective-c glue)

我能想出的最接近的是將值包裝在枚舉中:

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

無論如何,這可能是一個更好的解決方案,因為通過這種方式,您可以使用與單個參數關聯的顯式類型,而不是使用某種變形隱式輸入。

或者,您只能包裝閉包並使用Dictionary<String,Any>類型的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. 一些字符串

Blocks類在Objective-C中定義如下(帶有相應的頭和橋接頭,我不會把它們放在這里):

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方法。 這很難看,但它確實有效。

還有另一種類型, Any ,該對象,結構和基元都符合但功能不符合。 沒有通用函數類型,但您可以將函數類型描述為其參數並返回值,如下所示:

Dictionary<String, (AnyObject) -> String>

功能類型

你能使用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 =“測試”

嗯,也許這個Swift-Code並沒有真正幫助,因為你想擁有異類詞典。

它似乎也不可能將閉包放入NSDictionary (因為閉包不符合AnyObject )。

您也可以使用enum滾動自己的更高類型。 您需要字典值為字符串或返回字符串的函數,因此定義一個類型來表示:

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):
    ...
}

一個更“通用”的解決方案,它應該與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"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM