UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Day 60: Cannot change the value of struct properties

Forums > 100 Days of SwiftUI

Hi, I have added a property to the Friend struct to indicate whether the friend is also a user so that I can disable the NavigationLink if they are not. I’m trying to set this property in a function (setFriendUserStatus()) after decoding the JSON but I get an error “Cannot assign to property: 'friend' is a 'let' constant” - any help would be much appreciated!

struct User: Identifiable {

    let id: String
    let isActive: Bool
    let name: String
    let age: Int
    let company: String
    let tags: [String]
    var friends: [Friend]

    enum CodingKeys: CodingKey {
        case id, isActive, name, age, company, tags, friends
    }

}

extension User: Decodable {

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(String.self, forKey: .id)
        isActive = try container.decode(Bool.self, forKey: .isActive)
        name = try container.decode(String.self, forKey: .name)
        age = try container.decode(Int.self, forKey: .age)
        company = try container.decode(String.self, forKey: .company)
        tags = try container.decode([String].self, forKey: .tags)
        friends = try container.decode([Friend].self, forKey: .friends)
    }

}
struct Friend: Identifiable {
    let id: String
    let name: String
    var isUser: Bool = false

    enum CodingKeys: CodingKey {
        case id, name
    }
}

extension Friend: Decodable {

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(String.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
    }

}
class NetworkManager: ObservableObject {

    @Published var users = [User]()

    func loadUsersFromURL() {
        guard let url = URL(string: "https://www.hackingwithswift.com/samples/friendface.json") else {
            print("Invalid URL")
            return
        }

        let request = URLRequest(url: url)

        URLSession.shared.dataTask(with: request) { (data, response, error) in

            guard let data = data else {
                print("No data in response: \(error?.localizedDescription ?? "Unknown error").")
                return
            }

            let decoder = JSONDecoder()

            do {
                let decodedResponse = try decoder.decode([User].self, from: data)
                    DispatchQueue.main.async {
                        self.users = decodedResponse
                        self.setFriendUserStatus()
                    }

            } catch let jsonError as NSError {
                print("JSON decode failed: \(jsonError.localizedDescription)")
            }
        }.resume()
    }

    func setFriendUserStatus() {
        for user in users {
            for friend in user.friends {
                if let match = users.first(where: {$0.name == friend.name}) {
                    friend.isUser = true
                } else {
                    friend.isUser = false
                }
            }
        }
    }

}

3      

When I've had this issue, it's usually been because one of two things:

  1. I was passing in a let (and trying to modify it), sometimes a level or two later,
  2. I was passing it through something immutable.

In this case, and I just did a quick read, your problem may ultimately stem from this line:

let decodedResponse = try decoder.decode([User].self, from: data)

3      

Thanks @deirdresm, I didn't think my function was trying to modify the contents of decodedResponse - my intention was that it was modifying the contents of the @Published "users" property. I included the call to the function in that block of code just to ensure it ran after the "users" property had been populated on the background thread. Any thoughts on how I could change the code so that I can modify the freind.isUser property from my NetworkManager class?

3      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.