How do I check if an object is a collection? (Swift)

前端 未结 3 1119
走了就别回头了
走了就别回头了 2021-01-05 11:51

I\'m extensively using KVC to build unified interface for the needs of an app. For instance, one of my functions gets an object, which undergoes several checks based solely

相关标签:
3条回答
  • 2021-01-05 12:32

    Collection can no longer be used for type-checking, hence Ahmad F's solution would no longer compile.

    I did some investigation. Some people advice to bridge to obj-c collections and use isKindOfClass, others try to employ reflection (by using Mirror). Neither is satisfactory.

    There's a pretty straight-forward, a bit rough yet efficient way to accomplish the task via splitting object type if our concern is Array, Dictionary or Set (list can be updated):

    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
    }
    

    Usage:

    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
    

    Hard-code is the drawback but it does the job.

    0 讨论(0)
  • 2021-01-05 12:45

    You could create another protocol

    protocol CountableCollection {
        var count: Int { get }
    }
    
    extension Array: CountableCollection where Element: Any {
    }
    
    extension Dictionary: CountableCollection where Key == String, Value == Any {
    }
    

    Add all the methods that you need from Collection to the new protocol that has been created (I have added just count getter for demonstration).


    After this you could simply do

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

    someVar would be true if it is an Array or Dictionary. You can also make it conform to Set if required.

    0 讨论(0)
  • 2021-01-05 12:48

    NOTE: This solution does NOT work with Swift 5+.

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

    Calling:

    // 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
    
    0 讨论(0)
提交回复
热议问题