Search code examples
iosjsonswift

API doesn't contain any value for some objects and Xcode gives a fatal error when running the app


My app takes some data from this API: https://api.jqestate.ru/v1/properties/country

GitHub link to my project: https://github.com/armansharvel/JQ-Estate.git (download branch "Refreshing")

There are no compiler errors but when I run my app in the simulator Xcode prints in console:

"Fatal error: Index out of range".

In the ObjectModel.swift I created a class of the object with some data types. One of them is the variable mainPic (URL of picture for TableVeiw that I want to get from the API also). But the problem is not every object in the API contains value of URL of the picture.

So Xcode (when I try to run the app) marks the second line of code block that initialises mainPic variable and the error is:

"Thread 7: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0)"

Here is the whole class in code:

import Foundation

class Houses {

// Data Encapsulation

private var _mainPic: String
private var _localityName: String
private var _routeName: String
private var _mkadDistance: String
private var _rentOffer: String
private var _saleOffer: String

// Make a getted

var mainPic: String {
    return _mainPic
}

var localityName: String {
    return _localityName
}

var routeName: String {
    return _routeName
}

var mkadDistance: String {
    return _mkadDistance
}

var rentOffer: String {
    return _rentOffer
}

var saleOffer: String {
    return _saleOffer
}

// Initialization

init(data: JSONDictionary) {
    
    // Main Picture
    
    if let images = data["images"] as? JSONArray,
        pic0 = images[0] as? JSONDictionary, // THIS LINE IS WITH ERROR
        mainPic = pic0["url"] as? String {
        self._mainPic = mainPic
    } else {
        _mainPic = ""
    }
    
    // Locality Name
    
    if let location = data["location"] as? JSONDictionary,
        localityName = location["localityName"] as? String {
        self._localityName = localityName
    } else {
        _localityName = ""
    }
    
    // Route Name
    
    if let location = data["location"] as? JSONDictionary,
        routeName = location["routeName"] as? String {
        self._routeName = routeName
    } else {
        _routeName = ""
    }
    
    // MKAD Distance
    
    if let location = data["location"] as? JSONDictionary,
        mkadDistance = location["mkadDistance"] as? String {
        self._mkadDistance = mkadDistance
    } else {
        _mkadDistance = ""
    }
    
    // Rent Offer
    
    if let rentDict = data["rentOffer"] as? JSONDictionary,
        rentOffer = rentDict["price"] as? String {
        self._rentOffer = rentOffer
    } else {
        _rentOffer = ""
    }
    
    // Sale Offer
    
    if let saleDict = data["saleOffer"] as? JSONDictionary,
        saleOffer = saleDict["price"] as? String {
        self._saleOffer = saleOffer
    } else {
        _saleOffer = ""
    }
}
}

Just in case, JSONDictionary and JSONArray are just typealiases:

typealias JSONDictionary = [String : AnyObject]

typealias JSONArray = Array<AnyObject>

Solution

  • images[0] will crash with "Fatal error: Index out of range" if the images array is empty.

    Since you're using optional binding, use first instead of [0]:

    if let images = data["images"] as? JSONArray,
        pic0 = images.first as? JSONDictionary,
        mainPic = pic0["url"] as? String {
        self._mainPic = mainPic
    } else {
        _mainPic = ""
    }