1

Essentially, I have correctly parsed my data. However, when I'm trying to access the data. It claims that I'm attempting to insert non-propert list object into a UserDefaults Array. How would I be able to convert this somehow to a property list object? Or how would I be able to store the JSON array as a string?

var status = UserDefaults.standard.array(forKey: "status") ?? []
struct Response: Codable {
        let weather: [MyResult]
    }
    struct MyResult: Codable {
        let main: String
    }
func getData(from url:String) {
        
        URLSession.shared.dataTask(with: URL(string:url)!, completionHandler: {
            data, response, error in
            guard let data = data, error == nil else {
                print("Something went wrong")
                return
            }
            // have data
            var result: Response?
            do {
                result = try JSONDecoder().decode(Response.self, from: data)
            } catch {
                print(error.localizedDescription)
            }
            guard let json = result else {
                return
            }
            print(type(of: json.weather)) // Array
            
            UserDefaults.standard.set(json.weather, forKey: "status") // Here is the error
            print(status)
            }).resume()
    }

EDIT: When I print status, nothing is there.

func getData(from url:String) {
        
        URLSession.shared.dataTask(with: URL(string:url)!, completionHandler: {
            data, response, error in
            guard let data = data, error == nil else {
                print("Something went wrong")
                return
            }
            // have data
            var result: Response?
            do {
                result = try JSONDecoder().decode(Response.self, from: data)
            } catch {
                print(error.localizedDescription)
            }
            guard let json = result else {
                return
            }
            print(type(of: json.weather)) // Array
            do {
                 // Store it with
                let data = try JSONEncoder().encode(json.weather)
                UserDefaults.standard.set(data, forKey: "status")
                

                //  Read it
                if let data = UserDefaults.standard.data(forKey:"status") {
                  let res = try JSONDecoder().decode([MyResult].self,from:data)
                }
            }
            catch {
               print(error)
            }
            print(status)
            }).resume()
    }
1
  • You are storing an array of MyResult. This is not JSON. You need to encode it back. And never print meaningless literal strings like "Something went wrong" instead of the actual error. And in a Codable catch block print always error rather than error.localizedDescription. Commented Jul 17, 2020 at 5:05

2 Answers 2

1

You need

do {
     // Store it with  
    let data = try JSONEncoder().encode(json.weather)
    UserDefaults.standard.set(data, forKey: "status")

    //  Read it 
    if let data = UserDefaults.standard.data(forKey:"status") {
      let res = try JSONDecoder().decode([MyResult].self,from:data)
    }  
}
catch {
   print(error)
}
Sign up to request clarification or add additional context in comments.

1 Comment

I've tried this code and keep getting the same console "Attempt to insert non property list object" response.
0

Keep the naming of variables unique so that they don't get confused or mixed up. Here's the cleaned-up code for you.

func getData(from url: String) {
    URLSession.shared.dataTask(with: URL(string: url)!) { data, _, error in
        guard let data = data else {
            if let error = error { print(error) }
            return
        }
        do {
            let response = try JSONDecoder().decode(Response.self, from: data)
            print("got response: \(response)")
            let dataToStore = try JSONEncoder().encode(response.weather)
            UserDefaults.standard.set(dataToStore, forKey: "status") // set data to userdefaults
            guard let dataRetrieved = UserDefaults.standard.data(forKey: "status") else { return } // retrieve back weather
            let weather = try JSONDecoder().decode([MyResult].self, from: dataRetrieved)
            print("got weather from user defaults: \(weather)")
        } catch {
            print(error.localizedDescription)
        }
    }.resume()
}

4 Comments

This did not set anything for key "status" I tried printing it out the next line and for some reason it just says nil. I am only trying to return cloudy, rainy, etc. It shouldn't be this complicated.
Show what you tried? If you tried the above code exactly it should have worked. What did you get while printing response and weather from the above code?
so I tried the exact code above and when I print out the UserDefualts for status I keep getting the default value which I provided. In your print statement "got weather from user..." It prints out the array just fine. However, its setting my userdefaults to a different value that is giving me trouble. When I print out response I get the array of weather and within it "main" which is either sunny etc. I just do not understand why my UserDefault isn't being set properly here.
I think you're not setting the UserDefaults in the correct format, it needs to be Data type and for printing, you've to do exactly what I've done in the above code at the last 3 lines in the do block. If you correct the format of setting and retrieving you should be fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.