borchero
borchero

Reputation: 6022

Swift1.2 compiler error in initialization function of structure

I have the following code for handling JSON easier. However I get an compiler error in debug as well as release mode: Command failed due to signal: Segmentation fault 11. The line where the compiler apparently fails compiling is the first line of the initialization method. I also tried several different ways (nested function, assigning the closure to another variable first and so on) but the compiler wasn't able to get it to work. Is there any way to fix this? Thanks for your help

enum JSONValue {
case JSONString(String)
case JSONNumber(Double)
case NIL(NilLiteralConvertible)
case JSONArray(Array<JSON>)
case JSONDictionary(Dictionary<String, JSON>)
}

struct JSON {
private let value: JSONValue

init(_ object: AnyObject?) {
    value = { () -> JSONValue in
        switch object {
        case _ where object is String:
            return .JSONString(object as! String)
        case _ where object is NSNumber:
            return .JSONNumber((object as! NSNumber).doubleValue)
        case _ where object is Array<AnyObject>:
            var array = [JSON]()
            let original = object as! [AnyObject]
            for item in original {
                array += [JSON(item)]
            }
            return .JSONArray(array)
        case _ where object is [String: AnyObject]:
            var dictionary = [String: JSON]()
            let original = object as! [String: AnyObject]
            for item in original {
                dictionary[item.0] = JSON(item.1)
            }
            return .JSONDictionary(dictionary)
        default:
            return .NIL(nil)
        }
    }()
}

var dictionaryKeyArray: [String] {
    switch self.value {
    case .JSONDictionary(let dictionary):
        var result = [String]()
        for item in dictionary.keys {
            result.append(item)
        }
        return result
    default:
        fatalError("no dictionary")
    }
}

var jsonArray: [JSON] {
    switch self.value {
    case .JSONArray(let array):
        return array
    default:
        fatalError("no array")
    }
}

var stringArray: [String] {
    switch self.value {
    case .JSONArray(let array):
        var result = [String]()
        for item in array {
            result.append(item.stringValue)
        }
        return result
    default:
        fatalError("no string array")
    }
}

var doubleValue: Double {
    switch self.value {
    case .JSONNumber(let double):
        return double
    default:
        fatalError("no double value")
    }
}

var intValue: Int {
    switch self.value {
    case .JSONNumber(let int):
        return Int(int)
    default:
        fatalError("no integer value")
    }
}

var stringValue: String {
    switch self.value {
    case .JSONString(let string):
        return string
    default:
        fatalError("no string value")
    }
}

var isNil: Bool {
    switch self.value {
    case .NIL(_):
        return true
    default:
        return false
    }
}

subscript(index: Int) -> JSON {
    switch self.value {
    case .JSONArray(let array) where array.count < index:
        return array[index]
    default:
        return JSON(nil)
    }
}

subscript(key: String) -> JSON {
    switch self.value {
    case .JSONDictionary(let dictionary) where dictionary[key] != nil:
        return dictionary[key]!
    default:
        return JSON(nil)
    }
}
}

Upvotes: 1

Views: 93

Answers (1)

Martin R
Martin R

Reputation: 539975

The compiler should not segfault, no matter how wrong the source code is, so you could write a bug report to Apple in any case.

But the problem is that defining

enum JSONValue {
    // ...
    case NIL(NilLiteralConvertible)
    // ...
}

does not mean that JSONValue.NIL(nil) is a valid enumeration value.

Types conforming to NilLiteralConvertible are those which can be initialized with nil, for example optionals:

let opt : Int? = nil

So JSONValue.NIL(Optional<Int>(0)) would be a valid enumeration value. But that is probably not what you wanted.

I think you should just define the enumeration as

enum JSONValue {
    case JSONString(String)
    case JSONNumber(Double)
    case NIL     // <- instead of NIL(NilLiteralConvertible)
    case JSONArray(Array<JSON>)
    case JSONDictionary(Dictionary<String, JSON>)
}

and then replace .NIL(nil) by .NIL in your code. At least it does compile with this change.

Upvotes: 1

Related Questions