【问题标题】:How do I check if an object is a collection? (Swift)如何检查一个对象是否是一个集合? (迅速)
【发布时间】:2017-05-05 07:08:35
【问题描述】:

我广泛使用 KVC 来构建统一界面以满足应用程序的需求。例如,我的一个函数获取一个对象,该对象仅根据字符串键的字典进行多次检查。

因此我需要一种方法来通过键检查对象是否属于集合类型。

我希望能够进行一些协议检查(如 C# 中的 IEnumerable 以检查它是否可以枚举),但没有成功:

if let refCollection = kvcEntity.value(forKey: refListLocalKey) as? AnySequence<CKEntity> { ... }

我也试过 AnyCollection。

我知道我可以迭代所有主要的集合类型,只需键入:

if let a = b as? Set { ...} // (or: if a is Set {...})
if let a = b as? Array { ...}
if let a = b as? Dictionary { ...}

但从继承/多态的角度来看,这似乎并不合适。

【问题讨论】:

  • 我在发帖前使用了搜索。从 isKindOfClass 开始,它意味着对硬编码类型的迭代。我想要一个适当的协议检查或类似的东西。
  • @AnniS 这不适用于Collection。这会导致错误。
  • @AnniS,conformsToProtocol 来自 objc,仅适用于 NSObject 派生的类型。 Swift 集合不是。

标签: swift generics collections


【解决方案1】:

Collection 不能再用于类型检查,因此 Ahmad F 的解决方案将不再编译。

我做了一些调查。有些人建议桥接到 obj-c 集合并使用 isKindOfClass,其他人则尝试使用反射(使用 Mirror)。两者都不令人满意。

如果我们关心的是Array、Dictionary 或Set(列表可以更新),那么通过拆分对象类型来完成任务是一种非常直接、有点粗略但有效的方法:

func isCollection<T>(_ object: T) -> Bool {
    let collectionsTypes = ["Set", "Array", "Dictionary"]
    let typeString = String(describing: type(of: object))

    for type in collectionsTypes {
        if typeString.contains(type) { return true }
    }
    return false
}

用法:

var set : Set! = Set<String>()
var dictionary : [String:String]! = ["key" : "value"]
var array = ["a", "b"]
var int = 3
isCollection(int) // false
isCollection(set) // true
isCollection(array) // true
isCollection(dictionary) // true

硬编码是缺点,但它可以完成工作。

【讨论】:

  • 这会给struct MyNonSet { }之类的东西带来误报
  • 此方案不支持符合Collection的自定义类型
【解决方案2】:

注意:此解决方案不适用于 Swift 5+。

func isCollection<T>(object: T) -> Bool {
    switch object {
    case _ as Collection:
        return true
    default:
        return false
    }
}

调用:

// COLLECTION TESTING //

let arrayOfInts = [1, 2, 3, 4, 5]
isCollection(object: arrayOfInts) // true

let setOfStrings:Set<String> = ["a", "b", "c"]
isCollection(object: setOfStrings) // true

// [String : String]
let dictionaryOfStrings = ["1": "one", "2": "two", "3": "three"]
isCollection(object: dictionaryOfStrings) // true


// NON-COLLECTION TESTING //

let int = 101
isCollection(object: int) // false

let string = "string" // false

let date = Date()
isCollection(object: date) // false

【讨论】:

  • 在 swift 5 中:错误“协议‘集合’只能用作通用约束,因为它具有 Self 或关联的类型要求”
【解决方案3】:

你可以创建另一个协议

protocol CountableCollection {
    var count: Int { get }
}

extension Array: CountableCollection where Element: Any {
}

extension Dictionary: CountableCollection where Key == String, Value == Any {
}

将您需要的所有方法从Collection 添加到已创建的新协议中(我刚刚添加了count getter 用于演示)。


在这之后你可以简单地做

if someVar is CountableCollection {
    print(someVar.count)
}

如果它是Array 或Dictionary,someVar 将为真。如果需要,您还可以使其符合Set。

【讨论】:

  • 这不适用于在 3rd 方库中定义的自定义集合,甚至在自己的代码中,例如struct MyAwesomeCollection: Collection
猜你喜欢
  • 2023-01-13
  • 2019-07-18
  • 2021-04-05
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 2021-08-17
  • 1970-01-01
相关资源
最近更新 更多