Support Topics Documentation Slack YouTube Blog

User Update issue

We are working on an app with a simple profile page where users can edit their name/profile image.
the update works perfectly however the Backendless User instance on the device is not being updated until the user logs out then logs back in.

I don’t know if it has any relevance but we have the stay logged in option set to true

Backendless Version (3.x / 5.x)

Client SDK ( Swift )

Application ID 2E6E6142-3600-6FA9-FF2E-462B0F504F00

Expected Behavior

Please describe the expected behavior of the issue, starting from the first action.

  1. Updating the logged in user updates data on the server and local instance of currentUser

Actual Behavior

  1. Updating user properties works as expected and updates the data without error
  2. When calling getProperty of the currently logged in user it returns the old data and not the updates values
  3. The old data is being persisted until the user logs out then logs in again

Hello @Omar_Darwish,

The internal ticket BKNDLSS-19950 created and we’ll investigate it as soon as possible.
Also please provide the updating method info:

  • do you update the BackendlessUser object using the function from the UserService class
func update(user: BackendlessUser, responseHandler: ((BackendlessUser) -> Void)!, errorHandler: ((Fault) -> Void)!)
  • or you updating the BackendlessUser object using the function from the DataService class:
func save(entity: CustomType, responseHandler: ((Any) -> Void)!, errorHandler: ((Fault) -> Void)!)
or
func update(entity: CustomType, responseHandler: ((Any) -> Void)!, errorHandler: ((Fault) -> Void)!)

Also it would be appreciated if you provide some code sample of your updating method that reproduces this issue.

UPD: for now ticket is closed because we cannot reproduce this issue. Topic is also closed and will be reopened if necessary.

Regards,
Olha

Hey Olha,

sorry for that late response, was away for a couple of days (coding detox)

i have actually tried all all the methods in the documentation and all of them have the same outcome.
the data on the dashboard gets updated but the persisted user instance never get updated until the user logs out then logs back in.

this a code sample that we are using, in swift

func updateUserDetails(name : String?, profileImageUrl: String?, completion: @escaping(APIError?) -> Void) {

guard let user = Backendless.shared.userService.getCurrentUser() else {return}

if let userName = name {
    user.setProperty(propertyName: "name", propertyValue: userName)
}

if let url = profileImageUrl {
    user.setProperty(propertyName: "profileImageUrl", propertyValue: url )
}


//        Backendless.shared.data.of(BackendlessUser.self).update(entity: user, responseHandler: { updatedUser in
//            print("User has been updated")
//
//            if let updatedUser = updatedUser as? BackendlessUser, let name = updatedUser.getProperty(propertyName: "name") as? String {
//                print(name)
//            }
//
//        }) { fault in
//            print(fault)
//        }
//



Backendless.shared.userService.update(user: user, responseHandler: { (response) in
    
    print("User has been updated")
    
}) { (error) in
    completion(APIError.userProfileUpdateIssue)
}

}

if you try the code i provide you will notice both methods we tried render the same result.

we have not tried to update the user instance from the DataService class yet but will give it a try.

Hello,
Thank you for your response. We’ll check it as soon as possible.

Regards,
Olha

Thank you Olha,
highly appreciated

Well, I’ve tested your code and that’s what I’ve got:
https://monosnap.com/file/WZDD1jSE8xUe5o027tVJumfBoMrWpG

  1. I’ve added some logs before updating and after updating.
  2. I’ve changed the completion closure a little.
  3. Everything works fine I think. I’ve tested with Swift-SDK v 5.5.11

Regards,
Olha

Dear Olha,

thank you for the response, i think you where unable to re-create the issue because on your viewDidload you are logging in the user. Anytime we reLogin the user the data gets pulled by the server and its accurate…however if you keep the user logged in the current user does not get updated.

i have updated my method with some print functions and unlike the video you sent the current user does not update, but the response received from the server has the updated data and does not update the persisted user object.

func updateUserDetails(name : String?, profileImageUrl: String?, completion: @escaping(ApiError?) -> Void) {
    guard let user = Backendless.shared.userService.getCurrentUser() else {return}
    
    print("user name before update: \(user.name)")
    
    if let userName = name {
        user.setProperty(propertyName: "name", propertyValue: userName)
    }
    
    if let url = profileImageUrl {
        user.setProperty(propertyName: "profileImageUrl", propertyValue: url )
    }
   
    print("Updating...")
    Backendless.shared.userService.update(user: user, responseHandler: { (response) in
          guard let updatedUser = Backendless.shared.userService.getCurrentUser() else {return}

            print("User name after update: \(updatedUser.name)") //printing the old persisted data
        
        guard let nameFromResponse = response as? BackendlessUser else {return}
        
        print("user name from response \(nameFromResponse.name)") // printing correct updated data,     but dosent update the presisted user object
        completion(nil)
    }) { (error) in
        completion(ApiError.userProfileUpdateIssue)
    }
    
}

I have updated all my pod files to the latest SDK, but still the issue persists… i hope we can find a solution soon.

Hey Ohla,

I finally managed to get things working but i have to tweak the UserService.swift file in the Backendless SDK files

public func update(user: BackendlessUser, responseHandler: ((BackendlessUser) -> Void)!, errorHandler: ((Fault) -> Void)!) {
    let headers = ["Content-Type": "application/json"]
    var parameters = user.getProperties()
    parameters["password"] = user._password
    var userId = String()        
    if let userObjectId = user.objectId {
        userId = userObjectId
    }
    else if let userObjectId = user.getProperty(propertyName: "objectId") as? String {
        userId = userObjectId
    }
    if !userId.isEmpty {
        BackendlessRequestManager(restMethod: "users/\(userId)", httpMethod: .put, headers: headers, parameters: parameters).makeRequest(getResponse: { response in
            if let result = self.processResponse.adapt(response: response, to: BackendlessUser.self) {
                if result is Fault {
                    errorHandler(result as! Fault)
                }
                else {
                 // force the userdefaults to update the current user instance
                  UserDefaultsHelper.shared.saveCurrentUser(currentUser: result as! BackendlessUser) 
                    responseHandler(result as! BackendlessUser)
         
                }
            }
        })
    }
}

i know this solution is not a proper solution to but its the only way i managed to get things working. u usually avoid tampering with the SDK files and leave things to the experts however this issue was causing us delays on delivering our app. I hope you can reproduce this or suggest and alternative fix but until then this seems to work.

Hello,

We’ll add the fix in the nearest update.
But your current fix will save every updated user as current user event if the updated user was not current before the update.

Regards,
Olha

Hey,

Yes I am aware…but for the timer being it suits our needs because the only time we are calling the update user method is when the logged in user updates their profile image and name.

Regards,

Omar

Unfortunately we can’t release the fix right now because this code will also remove user-token from current user and it’s totally incorrect.

UserDefaultsHelper.shared.saveCurrentUser(currentUser: result as! BackendlessUser) 

We’ll investigate this issue as soon as possible.

Regards,
Olha

Hey Olha,

Quick update we managed to sort the issue out in a more elegant was with retaining the user token and all

From the UserService.swift file we exposed setPersistentUser(currentUser : BackendlessUser) {} as a public method so we can get access to that method from our project.

public func setPersistentUser(currentUser: BackendlessUser) {
        self.currentUser = currentUser
        savePersistentUser(currentUser: self.currentUser!)
    }

and from our project files we changed the update method to save the persisted user after we get a response from the server that the user has been updated as follows.

func updateUserDetails(name : String?, profileImageUrl: String?, completion: @escaping(ApiError?) -> Void) {
    guard let user = Backendless.shared.userService.getCurrentUser() else {return}
    
    if let userName = name {
        user.setProperty(propertyName: "name", propertyValue: userName)
    }
    
    if let url = profileImageUrl {
        user.setProperty(propertyName: "profileImageUrl", propertyValue: url )
    }
   

    Backendless.shared.userService.update(user: user, responseHandler: { _ in

        Backendless.shared.userService.setPersistentUser(currentUser: user) // notice we are saving the user instance we used to invoke the update method and not the user instance from the user response
        completion(nil)
    }) { (error) in
        completion(ApiError.userProfileUpdateIssue)
    }
    
}

The ultimate solution which i am working on now is to add new public update method to the UserService.swift file to updated the currently logged in user, and keep the current update method for updating any user instance.

Regards,

Omar