Devin
Devin

Reputation: 900

Updating SwiftyJSON object created from an Alamofire request

I'm trying to display some JSON data pulled from a website in a table view. Initially, everything works great. I declare my JSON data as an instance varable:

var tableData:JSON!
{
    didSet
    {
        tableView.reloadData()
    }
}

And then I make my request somewhere-- viewDidLoad or viewWillAppear or via the user pulling down on the tableView to refresh or whatever, doesn't really matter-- set the data, and the table gets reloaded. Everything works great.

request(method, url, parameters: parameters, encoding: ParameterEncoding.URL).responseJSON(options: NSJSONReadingOptions.AllowFragments) { (request, response, json, error) -> Void in
            self.tableData = JSON(json!)
        }

However, sometimes I don't just want to display the data, but I want to let the user update the data, for example, in a textField. And here's where I'm running into problems.

So I've created a table view cell with a text field, filled it with some text pulled from my tableData JSON, so far so good. My user can then change the text field, and I want to update the tableData via the text field's delegate methods. This is not working for me.

func textFieldDidEndEditing(textField: UITextField)
{
    let key = "anExampleKey"
    tableData[key] = JSON(textField.text)
    println(tableData[key]) // the original value, not textField.text
}

Nothing seems to happen, the tableData value for "anExampleKey" remains unchanged. So, if that cell scrolls off the screen for example and then comes back into view, any changes my user has made are lost and it reverts back to the original value.

This seems to be an issue solely with a JSON value created from an Alamofire request however. For example, if I do this:

func textFieldDidEndEditing(textField: UITextField)
{
    let key = "anExampleKey"
    var json = JSON([key:tableData[key].stringValue])
    tableData[key] = JSON(textField.text)
    json[key] = JSON(textField.text)
    println(tableData[key]) // the original value, not textField.text
    println(json[key]) // textField.text
}

The json variable will be updated to reflect the textField, while the tableData will still have its original value, not what's in the textField. Does anyone know why the JSON object made via the Alamofire request is immutable, whereas one created directly from a dictionary is not?

Upvotes: 0

Views: 577

Answers (1)

Devin
Devin

Reputation: 900

Ok, I figured it out. It has nothing to do with SwiftyJSON or Alamofire, but rather the fact that I declared my instance variable as optionally unwrapped. I'm still not entirely sure about all the rules for optional and implicitly unwrapped variables, but using regular JSON variable instead of JSON! allowed me to update it.

var tableData:JSON! /* won't update */
var tableData:JSON = JSON([:]) /* will update */ 

I have no idea why this is the case. I thought I had my head around the Swift optional and implicitly unwrapped rules by now, but I guess not. It's almost like every time I implicitly unwrap a JSON! variable, it creates a new copy and updates that, leaving the instance variable unchanged. I fired up a playground to see if that was true for all implicitly unwrapped structs, and it's not, I can update the instance values for an implicitly unwrapped struct just fine in there. Interesting, optional JSON? values do update.

struct Test
{
    var myVar = 0
}

var myTest:Test!

myTest = Test() /* myVar = 0 */
myTest.myVar = 7 /* myVar = 7 */
myTest.myVar /* myVar = 7 still */

var implicitlyUnwrappedJSON:JSON!
implicitlyUnwrappedJSON = JSON(["Test":"This is one"])
implicitlyUnwrappedJSON["Test"] = "This is another one"
implicitlyUnwrappedJSON["Test"].string /* This is one */
implicitlyUnwrappedJSON?["Test"] = "This is another one"
implicitlyUnwrappedJSON["Test"].string /* This is another one */
implicitlyUnwrappedJSON!["Test"] = "This is another one yet"
implicitlyUnwrappedJSON["Test"].string /* This is another one yet */

var optionalJSON:JSON?
optionalJSON = JSON(["Test":"This is one"])
optionalJSON?["Test"] = "This is another one"
optionalJSON?["Test"].string /* This is another one */
optionalJSON!["Test"] = "This is another one yet"
optionalJSON!["Test"].string /* This is another one yet */

var json:JSON = JSON(["Test":"This is one"])
json["Test"] = "This is another one"
json["Test"].string /* This is another one */

So I don't have the slightest clue what is going on here, but I have it working.

Upvotes: 1

Related Questions