Differences between Playground and Project

1.1k views Asked by At

In the course of answering another question, I came across a weird bug in Playground. I have the following code to test if an object is an Array, Dictionary or a Set:

import Foundation

func isCollectionType(value : AnyObject) -> Bool {
    let object = value as! NSObject

    return object.isKindOfClass(NSArray)
        || object.isKindOfClass(NSDictionary)
        || object.isKindOfClass(NSSet)
}

var arrayOfInt = [1, 2, 3]
var dictionary = ["name": "john", "age": "30"]
var anInt      = 42
var aString    = "Hello world"

println(isCollectionType(arrayOfInt)) // true
println(isCollectionType(dictionary)) // true
println(isCollectionType(anInt))      // false
println(isCollectionType(aString))    // false

The code worked as expected when I put it into a Swift project or running it from the command line. However Playground wouldn't compile and give me the following error on the downcast to NSObject:

Playground execution failed: Execution was interrupted, reason: EXC_BAD_ACCESS (code=2, address=0x7fb1d0f77fe8).
* thread #1: tid = 0x298023, 0x00007fb1d0f77fe8, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7fb1d0f77fe8)
  * frame #0: 0x00007fb1d0f77fe8
    frame #1: 0x000000010ba46e12 libswiftCore.dylib`Swift._EmptyArrayStorage._withVerbatimBridgedUnsafeBuffer (Swift._EmptyArrayStorage)<A>((Swift.UnsafeBufferPointer<Swift.AnyObject>) -> A) -> Swift.Optional<A> + 50

The build platform was OS X in all three cases. Does anyone know how to get Playground to play along?

Xcode 6.3.2. Swift 1.2. OS X 10.10.3 Yosemite

1

There are 1 answers

0
Paul Ardeleanu On

Not really the cause of that bug (it does look weird) but... You will need to use optional chaining since value can be AnyObject:

import Foundation

func isCollectionType(value : AnyObject) -> Bool {
    if let object = value as? NSObject {
        return object.isKindOfClass(NSArray)
            || object.isKindOfClass(NSDictionary)
            || object.isKindOfClass(NSSet)
        }
    return false
}

var arrayOfInt = [1, 2, 3]
var dictionary = ["name": "john", "age": "30"]
var anInt      = 42
var aString    = "Hello world"

isCollectionType(arrayOfInt)
isCollectionType(dictionary)
isCollectionType(anInt)
isCollectionType(aString)

Playground

Also worth noting, NSArray and Array are different things:

  • NSArray is an immutable class:

    @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>

  • whilst Array is a struct:

    struct Array<T> : MutableCollectionType, Sliceable, _DestructorSafeContainer

With this in mind it might be surprising that isCollectionType(arrayOfInt) returns true - but there is a conversion happening.