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.
- Updating the logged in user updates data on the server and local instance of currentUser
Actual Behavior
- Updating user properties works as expected and updates the data without error
- When calling getProperty of the currently logged in user it returns the old data and not the updates values
- 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
- I’ve added some logs before updating and after updating.
- I’ve changed the completion closure a little.
- 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 way 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
Did you set the
Backendless.shared.userService.stayLoggedIn = true
or this property is false?
Regards,
Olha
Hey Olha,
No stay logged in is currently set to on, as it is a requirement for our app to keep users logged in.
but the method i described above is working really well so far, and we have been testing it extensively.
According to our logic currentUser is saved on the device (to UserDefaults) only when
Backendless.shared.userService.stayLoggedIn = true
that’s why I asked about it. Already working on Swift-SDK fix and assume it will be available tomorrow.
Regards,
Olha
Thank you for the update Olha.
Yes this issue is only evident when the
Backendless.shared.userService.stayLoggedIn = true
And if we logout the user and then log them back in the new data is pulled from the server and the currentUser is updated in the user defaults.
Could you please try with v5.6.1 and verify whether it’s ok now?
Regards,
Olha
Hey Olha,
just updates to v5.6.1 and its working as expected now.
Thank you for your cooperation.
Regards,
Omar