As of April 12th, you must go to Progress SupportLink to create new support cases or to access existing cases. Please, bookmark the SupportLink URL and use the new portal to contact the support team.
At some point in the app, after I have a logged-in session, I am doing this -
guard let user = Client.sharedClient.activeUser as? CustomKinveyUser else {return}
The above line works and user is non-nil and is of type CustomKinveyUser
if and only if I have signed in during that particular launch of the app.
However, in subsequent app launches if I already have a signed-in session, Client.sharedClient.activeUser returns a non-nil object as expected, but the class type is the base user class (Kinvey.User) instead of CustomKinveyUser and so the downcast fails (i.e the as? CustomKinveyUser part returns nil)
captured from the xcode console:
(lldb) po Client.sharedClient.activeUser
▿ Optional<User>
▿ some : <__KNVUser: 0x7fdf34e829d0>
Best Answer
P
Pranav J
said
almost 7 years ago
Niraj,
Thanks for the detailed explanations. Engineering is looking at the
issue.
We'd like you to know that our SDK is open source and we are
happy to accept contributions. If you have a solution for this issue or
any others in the future, please feel free to submit a pull request to
our repo. Our team will gladly review it and accept your fix.
The culprit is this line in initialize( with all params ) func in Client.swift
let user = Mapper<User>().map(JSON: json)
It ignores the `userType` while unarchiving the saved user and always instantiates the saved JSON using Kinvey.User class.
Replacing it by what is done in the API-response parsing flow in (JsonResponseParser's parseUser function) fixes the problem:
let map = Map(mappingType: .fromJSON, JSON: json)
let user = userType.init(map: map)
user?.mapping(map: map)
S
Sagar Patel
said
over 6 years ago
Hi All,
The fix suggested I have found to not work when calling customUser.logout(), nothing happens.
P
Pranav J
said
almost 7 years ago
Sagar,
Can you try the fix that Niraj has mentioned above?
Thanks,
Pranav
Kinvey
M
Michael Garza
said
almost 7 years ago
Hey Pranav,
I noticed that Niraj's fix is not in the latest version released about a week ago, 3.3.7. Is a fix in the works for that or should one of us create a pull request?
P
Pranav J
said
almost 7 years ago
Michael,
We'd like you to know that our SDK is open source and we are
happy to accept contributions. If you have a solution for this issue or
any others in the future, please feel free to submit a pull request to
our repo. Our team will gladly review it and accept your fix.
Thanks, Pranav Kinvey
P
Pranav J
said
almost 7 years ago
Niraj,
I tried creating a CustomUser class and had an address field added to it.
class CustomUser: User {
var address: String?
override func mapping(map: ObjectMapper.Map) {
super.mapping(map: map)
address <- map["address"]
}
}
Just
tried the below code to reproduce the issue, but everytime I see the
address being printed properly after login. I am running it on the
simulator.
User.login(username: "mind1", password: "mind1") { user, error in
if let user = user as? CustomUser {
//the log-in was successful and the user is now the active user and credentials saved
//hide log-in view and show main app content
print("User: \(user)")
print(user.address)
guard let user1 = Client.sharedClient.activeUser as? CustomUser else {return}
print(user1.address)
Is there anything specific that you are doing? Are you able to reproduce it consistently?
Thanks, Pranav Kinvey
J
James Seils
said
almost 7 years ago
Any update on this issue? I am still unable to use CustomUser on the initial viewController if the user is not forced to login every time. Downcasting the User to a CustomUser only works when logging in.
Thanks,
James
N
Niraj Khatod
said
almost 7 years ago
Thanks for looking into it, Pranav.
The above code works because you are checking for the type returned by Client.sharedClient.activeUserright after logging in. It will return CustomUser if you call it any time in the future unless you kill the app.
What I am doing on every cold launch of the app is I am checking the value returned by Client.sharedClient.activeUser and only if activeUser is nil, I am showing the login screen and calling User.login().
This is a very common use case ( require users to login only if can't find saved credentials)
To reproduce the problem I am seeing, you'll have to check for activeUser before making your login call ( and skip the login call if activeUser is not nil) :
if let activeUser = Client.sharedClient.activeUser {
if let customUser = activeUser as? CustomUser {
print("Yeah! We have an activeUser: \(activeUser) and it is of type CustomUser. We can skip the call to Login")
} else {
fatalError("We have an activeUser: \(activeUser) but it's not of type CustomUser")
}
} else {
User.login(username: "mind1", password: "mind1") { user, error in
if let user = user as? CustomUser {
//the log-in was successful and the user is now the active user and credentials saved
//hide log-in view and show main app content
print("User: \(user)")
print(user.address)
guard let user1 = Client.sharedClient.activeUser as? CustomUser else {return}
print(user1.address)
}
If you do a clean install of you app with the above code, then it will call User.Login in the first run because activeUser will be nil.
However, if you kill the app and re-run it, you'd expect it to print "Yeah! We have an activeUser: ....", but instead it will go to the else part to abort your app with the fatalError.
I dived a bit into Kinvey SDK's implementation of custom User class and it seems this problem has to do with the difference between how the User object is retrieved from its in-memory version VS its archived version (version that is persisted and un-archived on app launch). After a successful User.login() call, the SDK respects the type set in sharedClient.userType and instantiates the correct sublcass to assign to activeUser. This is somehow not true when after you initialize the SDK on cold app launch. In that case, sharedClient.userType is not respected.
Can you try calling the User.get() using the Kinvey.sharedClient.activeUser.userId? This should get back the CustomUser.
Something like this:
User.get(userId: (Kinvey.sharedClient.activeUser?.userId)!, client: Kinvey.sharedClient, completionHandler: {activeUser, error in
if let customUser = activeUser as? CustomUser {
print("Yeah! We have an activeUser: \(activeUser) and it is of type CustomUser. We can skip the call to Login")
} else {
fatalError("We have an activeUser: \(activeUser) but it's not of type CustomUser")
}
})
Let me know if this helps.
Thanks,
Pranav
Kinvey
N
Niraj Khatod
said
almost 7 years ago
Thanks again for working on it.
I am pretty sure calling User.get( ) would work, but it's a workaround at best which isn't ideal.
Consider the practical use case - If users have logged in previously, I would like to give them the logged-in experience immediately on subsequent app launches instead of waiting for a network call to complete
IMO the class mismatch is clearly a bug. I request to forward it to the appropriate team/dev.
I would be glad to come up with a fix too!
P
Pranav J
said
almost 7 years ago
James,
Can you try the fix that Niraj has mentioned above?
Thanks,
Pranav
Kinvey
J
James Seils
said
almost 7 years ago
Niraj's fixed worked. Thank you!
P
Pranav J
said
over 6 years ago
Chris,
We are pleased to inform you that a new release of the iOS SDK v3.5.1 has been posted and is available for download at the following URL.
This update fixes the problem described in this ticket regarding CustomClass that you discovered in the 3.5.0 SDK.
At your convenience, please download and test the fix and let us know if it works to your satisfaction.
Thanks,
Pranav
Kinvey
P
Pranav J
said
almost 7 years ago
Answer
Niraj,
Thanks for the detailed explanations. Engineering is looking at the
issue.
We'd like you to know that our SDK is open source and we are
happy to accept contributions. If you have a solution for this issue or
any others in the future, please feel free to submit a pull request to
our repo. Our team will gladly review it and accept your fix.
Thanks,
Pranav
Kinvey
C
Chris D
said
over 6 years ago
It seems like Nirajs and Sagar Patel's solution no longer works with the latest 3.5.0 SDK.
Does anyone else have a solution?
Even with the latest iOS Kinvey SDK version 3.5.0, this problem still exists....that is, getting the Kinvey.sharedClient.activeUserstill doesn't return the custom User object if the app is killed (only works after a fresh login).
Niraj Khatod
I am using iOS sdk 3.0. I have created a custom user sublclass as explained in http://devcenter.kinvey.com/ios-v3.0/guides/users#CustomAttributesCustomUserObject
below is my SDK initializatin code in appDelegate:
aKinvey.sharedClient.userType = CustomKinveyUser.self
Kinvey.sharedClient.initialize(
appKey: "kid_xxxxx",
appSecret: "my-app-secret"
)
The CustomKinveyUser class looks like:
class CustomKinveyUser: Kinvey.User {
var profilePicURL: String?
override func mapping(map: Map) {
super.mapping(map: map)
profilePicURL <- map["profilePicURL"]
}
}
At some point in the app, after I have a logged-in session, I am doing this -
guard let user = Client.sharedClient.activeUser as? CustomKinveyUser else {return}
The above line works and user is non-nil and is of type CustomKinveyUser
if and only if I have signed in during that particular launch of the app.
However, in subsequent app launches if I already have a signed-in session, Client.sharedClient.activeUser returns a non-nil object as expected, but the class type is the base user class (Kinvey.User) instead of CustomKinveyUser and so the downcast fails (i.e the as? CustomKinveyUser part returns nil)
captured from the xcode console:
(lldb) po Client.sharedClient.activeUser
▿ Optional<User>
▿ some : <__KNVUser: 0x7fdf34e829d0>
Thanks for the detailed explanations. Engineering is looking at the issue.
We'd like you to know that our SDK is open source and we are happy to accept contributions. If you have a solution for this issue or any others in the future, please feel free to submit a pull request to our repo. Our team will gladly review it and accept your fix.
Thanks,
Pranav
Kinvey
- Oldest First
- Popular
- Newest First
Sorted by PopularNiraj Khatod
Hi Pravav,
If it helps, here is a fix:
The culprit is this line in initialize( with all params ) func in Client.swift
It ignores the `userType` while unarchiving the saved user and always instantiates the saved JSON using Kinvey.User class.
Replacing it by what is done in the API-response parsing flow in (JsonResponseParser's parseUser function) fixes the problem:
Sagar Patel
Hi All,
The fix suggested I have found to not work when calling customUser.logout(), nothing happens.
Pranav J
Sagar,
Can you try the fix that Niraj has mentioned above?
Thanks,
Pranav
Kinvey
Michael Garza
Hey Pranav,
I noticed that Niraj's fix is not in the latest version released about a week ago, 3.3.7. Is a fix in the works for that or should one of us create a pull request?
Pranav J
We'd like you to know that our SDK is open source and we are happy to accept contributions. If you have a solution for this issue or any others in the future, please feel free to submit a pull request to our repo. Our team will gladly review it and accept your fix.
Thanks,
Pranav
Kinvey
Pranav J
I tried creating a CustomUser class and had an address field added to it.
Just tried the below code to reproduce the issue, but everytime I see the address being printed properly after login. I am running it on the simulator.
Thanks,
Pranav
Kinvey
James Seils
Any update on this issue? I am still unable to use CustomUser on the initial viewController if the user is not forced to login every time. Downcasting the User to a CustomUser only works when logging in.
Thanks,
James
Niraj Khatod
Thanks for looking into it, Pranav.
The above code works because you are checking for the type returned by Client.sharedClient.activeUser right after logging in. It will return CustomUser if you call it any time in the future unless you kill the app.
What I am doing on every cold launch of the app is I am checking the value returned by Client.sharedClient.activeUser and only if activeUser is nil, I am showing the login screen and calling User.login().
This is a very common use case ( require users to login only if can't find saved credentials)
To reproduce the problem I am seeing, you'll have to check for activeUser before making your login call ( and skip the login call if activeUser is not nil) :
If you do a clean install of you app with the above code, then it will call User.Login in the first run because activeUser will be nil.
However, if you kill the app and re-run it, you'd expect it to print "Yeah! We have an activeUser: ....", but instead it will go to the else part to abort your app with the fatalError.
I dived a bit into Kinvey SDK's implementation of custom User class and it seems this problem has to do with the difference between how the User object is retrieved from its in-memory version VS its archived version (version that is persisted and un-archived on app launch). After a successful User.login() call, the SDK respects the type set in sharedClient.userType and instantiates the correct sublcass to assign to activeUser. This is somehow not true when after you initialize the SDK on cold app launch. In that case, sharedClient.userType is not respected.
I hope this explains the problem.
Pranav J
Niraj,
The active user object can be refreshed from the server using the User.get(client.activeUser)method. (http://devcenter.kinvey.com/ios/guides/users#usermanagement)
Can you try calling the User.get() using the Kinvey.sharedClient.activeUser.userId? This should get back the CustomUser.
Something like this:
Let me know if this helps.
Thanks,
Pranav
Kinvey
Niraj Khatod
Thanks again for working on it.
I am pretty sure calling User.get( ) would work, but it's a workaround at best which isn't ideal.
Consider the practical use case - If users have logged in previously, I would like to give them the logged-in experience immediately on subsequent app launches instead of waiting for a network call to complete
IMO the class mismatch is clearly a bug. I request to forward it to the appropriate team/dev.
I would be glad to come up with a fix too!
Pranav J
Can you try the fix that Niraj has mentioned above?
Thanks,
Pranav
Kinvey
James Seils
Niraj's fixed worked. Thank you!
Pranav J
Chris,
We are pleased to inform you that a new release of the iOS SDK v3.5.1 has been posted and is available for download at the following URL.
http://devcenter.kinvey.com/ios/downloads
This update fixes the problem described in this ticket regarding CustomClass that you discovered in the 3.5.0 SDK.
At your convenience, please download and test the fix and let us know if it works to your satisfaction.
Thanks,
Pranav
Kinvey
Pranav J
Thanks for the detailed explanations. Engineering is looking at the issue.
We'd like you to know that our SDK is open source and we are happy to accept contributions. If you have a solution for this issue or any others in the future, please feel free to submit a pull request to our repo. Our team will gladly review it and accept your fix.
Thanks,
Pranav
Kinvey
Chris D
It seems like Nirajs and Sagar Patel's solution no longer works with the latest 3.5.0 SDK.
Does anyone else have a solution?
Even with the latest iOS Kinvey SDK version 3.5.0, this problem still exists....that is, getting the Kinvey.sharedClient.activeUser still doesn't return the custom User object if the app is killed (only works after a fresh login).
-
Why do I get "Undefined symbols" errors when building with KinveyKit?
-
How do I register push tokens?
-
When using social login, to perform a log-out, do I need to log out of the social network, Kinvey, o
-
How can I assign additional properties to users?
-
Does KinveyKit support 64-bit ARM devices, such as iPhone 5s?
-
Authorization Token Invalid or Expired
-
BOOL and how it is stored in the database.
-
Offline saving throwing errors
-
Custom endpoint not able to form request object
-
Security through business logic
See all 437 topics