3

How can I check in Swift if a value is an Array. The problem is that an array of type Int can apparently not be casted to an array of type Any. Suppose I have an array myArray of type Int and execute the following:

if let array = myArray as? [Any] { return true }

it doesn't return true (which surprises me actually). The same thing appears with dictionaries. I want a dictionary of type String, Any (meaning that Any can be any type). How can I check if it is?

Thanks in advance.

borchero
  • 5,562
  • 8
  • 46
  • 72
  • Interesting, I cannot get it to work as well – Kametrixom Aug 16 '15 at 11:07
  • Can you give an example of how such a downcast would be useful? _Every_ type implicitly conforms to `Any`, so what your statement is effectively saying is "If this array is an array, return true"... the compiler is already well aware that it is an array. – Stuart Aug 16 '15 at 12:42
  • @Stuart I want to parse JSON -- in fact I don't return true but do something with the array then. Anyway, the question has been resolved, see below – borchero Aug 16 '15 at 12:44
  • Ah, so in your code `myArray` would be an object that is _not_ of type `Array`. `NSJSONSerialization` produces object types, so a scalar integer would be a `NSNumber` - this allows you to use `AnyObject` regardless of the value in the JSON array/dictionary. – Stuart Aug 16 '15 at 12:54
  • No, sorry for the confusion but I want to be able to convert simple dictionaries to JSON, too. This is why I can't use AnyObject – borchero Aug 16 '15 at 12:56
  • possible duplicate of [How to check if a variable is an array, but not a specific type array in Swift?](http://stackoverflow.com/questions/27309071/how-to-check-if-a-variable-is-an-array-but-not-a-specific-type-array-in-swift) – Maic López Sáenz Sep 25 '15 at 12:50

4 Answers4

5

Got it working like this, although it's not as beautiful as I would've hoped:

protocol ArrayType {}
extension Array : ArrayType {}

let intArray : Any = [1, 2, 3]
let stringArray : Any = ["hi", "hello", "world"]

intArray is ArrayType       // true
stringArray is ArrayType    // true

EDIT: I think I misunderstood your question before, now I got it though:

let intArray = [1, 2, 3]

let anyArray = intArray.map{ $0 as Any }

This is the only way to my knowledge.

Kametrixom
  • 14,673
  • 7
  • 45
  • 62
  • That's actually a good idea however I would like to use the values of the array (as values of type Any). And since I have to support both Swift's and Objective C's collection types, it's impossible to accomplish this with your approach, no offense btw :P – borchero Aug 16 '15 at 12:12
  • Yes, I used a mix of your two now, the reason I have to do it the way I did in my answer (I think) is that I want to parse JSON both with NSJSONSerialization and from Swift Dictionaries/Arrays – borchero Aug 16 '15 at 12:36
2

You can simply

array is Array<Any>
Farshid
  • 17
  • 2
0

Got it now, with the idea of @Kametrixom. It's extraordinary ugly but at least it works.

private protocol CJSONArrayType {
    func toAny() -> [Any]
}
extension Array: CJSONArrayType {
    private func toAny() -> [Any] {
        return self.map { $0 as Any }
    }
}
extension NSMutableArray: CJSONArrayType { }
extension NSArray: CJSONArrayType {
    private func toAny() -> [Any] {
        var result = [Any]()
        for item in self {
            result.append(item as Any)
        }
        return result
    }
}

private protocol CJSONDictionaryType {
    func toStringAny() -> [String: Any]
}
extension Dictionary: CJSONDictionaryType {
    private func toStringAny() -> [String : Any] {
        var result = [String: Any]()
        for item in self {
            result[item.0 as! String] = item.1 as Any
        }
        return result
    }
}
extension NSMutableDictionary: CJSONDictionaryType { }
extension NSDictionary: CJSONDictionaryType {
    private func toStringAny() -> [String : Any] {
        var result = [String: Any]()
        for item in self {
            result[item.0 as! String] = item.1 as Any
        }
        return result
    }
}
borchero
  • 5,562
  • 8
  • 46
  • 72
  • Here in Swift 2.0 it says that the extensions on `NSMutable...` are redundant. Also I think `Dictionary` gets automatically bridged to `NSDictionary` to you may not even need the `NS...` stuff. Whatever works best and easiest for you ;) – Kametrixom Aug 16 '15 at 12:40
  • Thanks for this piece of information, however I'm still using Swift 1.2 and it does _not_ bridge NSDictionary to Dictionary in all cases unfortunately... – borchero Aug 16 '15 at 12:41
  • I see, didn't know that :D – Kametrixom Aug 16 '15 at 12:42
0

If you want to parse JSON, there are only a few supported types which are at least AnyObject rather than Any.

Then it's very easy to check for Array

func checkArray(item : AnyObject) -> Bool {
  return item is Array<AnyObject>
}

let integer = 1
let string = "one"
let array = ["one", "two", "three"]
let dictionary = ["one" : 1, "two" : 2]

checkArray(integer) // false
checkArray(string) // false
checkArray(array) // true
checkArray(dictionary) // false

Apple highly recommends to constrain the types at compile time as much as possible

vadian
  • 274,689
  • 30
  • 353
  • 361
  • Yeah, but I want to set up JSON by myself, too using simple dictionaries, arrays, structs (not any object), and so on... – borchero Aug 16 '15 at 12:54
  • Nevertheless I'd start with the lowest common denominator, not with the most possible abstraction. – vadian Aug 16 '15 at 12:57