Best way to dynamically store and access data in Swift

538 views Asked by At

I have an app where every time it starts up (within the splash screen) it gets the currently logged in users' data from my database via an API endpoint. The type of JSON expected to be sent back to the app when it asks for data is as shown:

{
"username": "test",
"email": "[email protected]",
"uid": "5f661ffe1a80160027a6cb0c",
"isVerified": true,
"hub": {
    "hubID": "npnDsZegiSL5",
    "isSetup": true,
    "hubSWVersion": 0.11,
    "_id": "5f661ffe1a80160027a6cb0d",
    "cameraService": {
        "isSetup": true,
        "bridgeIP": "192.168.0.12",
        "username": "JesCGSr6HrWoKbKnnNOHSayVKdb1"
    },
    "servicesSetup": {
        "1": "cameraService",
        "2": "TPLinkPlug"
    }
},
    "code": "100",
    "message": "Success. User details have been provided"
}

As the user adds services/updates values, this database structure will constantly change. Which is my problem. There are tonnes of questions like this out there with all the same answer, to use the JSONDecoder and push the values to an observable object which can be accessed throughout the app via creating an instance of it or just to simply assign the values to the object when it has been fetched. Which I have done and am currently using:

The class userData object:

class userData: NSObject, ObservableObject {
    var userdata = userData.self
    @Published var uid: String = ""
    @Published var isVerified: Bool = false
    @Published var username: String = ""
    @Published var email: String = ""
}

The code where I assign the values to the object when I receive the above json in my app:

...
@EnvironmentObject var user: userData
print("Successfully got user data. Code: \(code ?? "0"). UID: \(response?["uid"] as! String). Username: \(response?["username"] as! String)")
DispatchQueue.main.async {
user.email = response?["email"] as! String
user.uid = response?["uid"] as! String
user.username = response?["username"] as! String
...

Then I can access it anywhere in my via:

@EnvironmentObject var user: userData
username = self.user.username

But this would require hard-coded code to assign each value from my database, is there a better, more dynamic way to assign the whole json response from my API (no matter what values/embedded jsons there is) to an object and access these data values throughout my app via that object?

Thanks

1

There are 1 answers

4
Mohammad Rahchamani On BEST ANSWER

Because you'll have new key value pairs in your response, I think you should store the response as a Dictionary and get desired values from that dictionary instead of parsing the response and storing separate variables. here is an example:

    let jsonStr = """
        {\"username\": \"test\",
        \"email\": \"[email protected]\",
        \"uid\": \"5f661ffe1a80160027a6cb0c\",
        \"isVerified\": true,
        \"hub\": {
            \"hubID\": \"npnDsZegiSL5\",
            \"isSetup\": true,
            \"hubSWVersion\": 0.11,
            \"_id\": \"5f661ffe1a80160027a6cb0d\",
            \"cameraService\": {
                \"isSetup\": true,
                \"bridgeIP\": \"192.168.0.12\",
                \"username\": \"JesCGSr6HrWoKbKnnNOHSayVKdb1\"
            },
            \"servicesSetup\": {
                \"1\": \"cameraService\",
                \"2\": \"TPLinkPlug\"
            }
        },
            \"code\": \"100\",
            \"message\": \"Success. User details have been provided\"
        }
    """
    
    let data = jsonStr.data(using: .utf8)
    
    do {
        // store this variable
        let dict =  try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
        
        for (k,v) in dict! {
            // example access to values
            print("key: \(k), value: \(v)")
        }
        
    } catch {
        print(error.localizedDescription)
    }