以协议类型为键的Swift字典

时间:2015-06-17 20:00:04

标签: ios macos swift dictionary protocols

这里的简短问题:

我得到了一个协议protocol SCResourceModel {..}和一个字典,它将该协议类型用作密钥:[SCResourceModel : String]。 这显然不起作用,因为字典中的键必须符合协议Hashable。将SCResourceModel继承自Hashable或尝试使用[protocol<SCResourceModel, Hashable> : String]这样的内容显然不起作用,因为HashableEquatable只能用作通用约束而不是类型本身。

我观看了WWDC 2015,在Swift 2.0中可以为协议添加约束,例如:protocol SCResourceModel where Self: Hashable {..}直接解决了这个问题(非常好)。

无论如何,我的问题是:我可以用当前的Swift 1.2版本做类似的事情,并以某种方式使用这个协议作为字典的关键吗?或者任何人都可以提出一个很好的解决方法或其他我可能忽略的东西?

我目前在Swift 1.2中看到的唯一解决方案是将协议转换为继承自例如Swift 1.2的类。 NSObject并且必须在我的API中进一步使用子类。

感谢您的帮助!

3 个答案:

答案 0 :(得分:5)

我可能会想到:

protocol SCResourceModel {
    var hashValue: Int { get }
    func isEqualTo(another: SCResourceModel) -> Bool

    // ...
}

struct SCResourceModelWrapper: Equatable, Hashable {
    let model: SCResourceModel

    var hashValue: Int {
        return model.hashValue ^ "\(model.dynamicType)".hashValue
    }
}

func == (lhs: SCResourceModelWrapper, rhs: SCResourceModelWrapper) -> Bool {
    return lhs.model.isEqualTo(rhs.model)
}

struct SCResourceModelDictionary<T> {
    private var storage = [SCResourceModelWrapper: T]()

    subscript(key: SCResourceModel) -> T? {
        get {
            return storage[SCResourceModelWrapper(model: key)]
        }
        set {
            storage[SCResourceModelWrapper(model: key)] = newValue
        }
    }
}

答案 1 :(得分:2)

好吧,据我所知,将协议本身作为密钥并不是一个非常好的方法。但我非常确定协议名称的字符串版本可以很好地满足您的需要。作为奖励,您还可以将协议对象作为字典中的值(如果在您的情况下有用)

事情是,我无法在Swift中找到一个很好的方法来做到这一点,但这是我在Objective-C中提出的,也许你会比我更好找到一个在Swift中这样做的方法:

// With a protocol declared...
@protocol TestProtocol <NSObject>
@end

@implementation

// Inside the implementation you can use NSStringFromProtocol()
Protocol *proto = @protocol(TestProtocol);
NSLog(@"Protocol: %@", NSStringFromProtocol(proto));

@end

输出:

Protocol: TestProtocol

该代码的@protocol部分是我不确定如何在Swift中执行的部分,如果情况更糟,您可以始终桥接到Objective-C文件。希望这会给你一些想法!

答案 2 :(得分:0)

为什么不使用AnyHashable

  protocol SCResourceModel: Hashable {}
  extension SCResourceModel { // Implement the hashable required methods }

  struct SCResource: SCResourceModel {}

现在声明像这样的字典:

 var container = Dictionary<AnyHashable, String>
 contianer[SCResource] = "My first resource"