Surafel
Surafel

Reputation: 835

Unwrapping a value using SwiftJSON results in an error on iOS13

I have an external api providing the data, which I need to decode and assign to a label in my view.

I am using the following in a collectionView so don't mind the collectionView.tag and indexPath.row

I am also using SwiftyJson to parse json values .string providing and optional value

let value = servicesResponse["data"][collectionView.tag]["subcategories"][indexPath.row]["name"].string

Now when I try to assign this value to a label

cell.serviceName.text = value

I get an error:

'NSInvalidArgumentException', reason: '*** -[NSPlaceholderString initWithString:]: nil argument'

I had to put the value inside something like this when assigning:

`"\(value)"`

This works fine but it has the Optional text around the values.

I also tried to:

if let value = servicesResponse["data"][collectionView.tag] 
   ["subcategories"][indexPath.row]["name"].string {
        cell.serviceName.text = value
}

same error

i just tried to check all the response on by one like this:

if servicesResponse["data"] != JSON.null{
            if servicesResponse["data"][collectionView.tag] != JSON.null{
                if servicesResponse["data"][collectionView.tag]["subcategories"] != JSON.null{
                    if servicesResponse["data"][collectionView.tag]["subcategories"][indexPath.row] != JSON.null{
                        if servicesResponse["data"][collectionView.tag]["subcategories"][indexPath.row]["name"] != JSON.null{
                            print("ALL PASS=========================")
                        }
                    }
                }
            }
        }

and all of the pass

I'd like to know if there is a way to remove the text Optional while the value is still optional or if anyone knows what this error means and why it happens.

The error only occurs on iOS13. works fine on earlier versions

Thanks.

Upvotes: 0

Views: 241

Answers (3)

EarlGrey
EarlGrey

Reputation: 2543

The error shows a string being initialized with a nil argument so there something not quite right with the json data, or the way it's being decoded.

Why don't you do the unwrapping in stages, rather than a one liner. When you're dealing with an unknown error it is always better to breakdown the process into small chunks and then examine each individually. When you discover where your problem is, you can always go back to the one liner, applying what you've learned.

This is what I came up with (and tested) to illustrate a one way to debug in a gradual JSON decoding process.

Given a raw json string:

let rawString = """
{"statusCode":200,"message":"Success","data":[{"_id":"someid","isActive":true,"subcategories":[{"_id":"id","photo":"image/url/30973327066756228460065.png","services":[{"_id":"id","properties":[{"_id":"id","isMultiSelect":false,"responses":["1","2","3","4","5"],"other_name":"የክፍሎች ቁጥር","name":"Number of rooms"}],"other_name":"ጽዳት","name":"Cleaning"}],"other_name":"ጽዳት","name":"Cleaning","other_subcategory_label":"ጽዳት","subcategory_label":"Cleaning"}],"name":"Home Cleaning","__v":0,"other_name":"የቤት ጽዳት"}]}
"""

We can gradually decode, validate and then unwrap the name value at the end.

let parsedJson = JSON.init(parseJSON: rawString)

let verifiedDataJson = parsedJson["data"]
guard verifiedDataJson != JSON.null else {
    return
}

let verifiedCollectionViewTagJson = verifiedDataJson[0]
guard verifiedCollectionViewTagJson != JSON.null else {
    return
}

let verifiedSubCategoriesJson = verifiedCollectionViewTagJson["subcategories"]
guard verifiedSubCategoriesJson != JSON.null else {
    return
}

let verifiedIndexPathRowJson = verifiedSubCategoriesJson[0]
guard verifiedIndexPathRowJson != JSON.null else {
    return
}

guard let unwrappedNameValue = verifiedIndexPathRowJson["name"].string as String? else {
    return
}

Upvotes: 0

NikLoy
NikLoy

Reputation: 448

It's because your value is an optional.

Try through this way

if let value = servicesResponse["data"][collectionView.tag]["subcategories"][indexPath.row]["name"] {
    cell.serviceName.text = value.stringValue
}

Upvotes: 0

Martin Victory
Martin Victory

Reputation: 11

The value variable is an Optional string, that's why it shows the Optional() when you print it.

To unwrap the optional you can do something like this:

if let unwrappedValue = value {
    cell.serviceName.text = unwrappedValue
}

Or if you prefer, you can do it in one line with the nil coalescing operator:

cell.serviceName.text = value ?? "Text in case of nil"

Upvotes: 1

Related Questions