Charles Prado
06/02/2021, 1:27 PMSessionManagerCheckInResult<UserInfo>?
being SessionManagerCheckInResult
is the sealed class:
sealed class CheckInResult<out T : Any> {
data class Success(val data: UserInfo) : CheckInResult<UserInfo>()
data class Error(val exception: Throwable) : CheckInResult<Nothing>()
}
I'm trying to get the error when I receive one, but I'm not able to get the result or error separated here. What I get if I print the object is:
▿ Optional<SharedSessionManagerCheckInResult>
- some : Error(exception=ApiError(code=400112, message=Invalid or missing members in payload
...
How can I get this error in iOS side? Some way I can convert the data to a SharedSessionManagerCheckInResultError
here?Sam
06/02/2021, 3:50 PMSessionManagerCheckInResultError
then just try to cast it.
if let err = result as? SessionManagerCheckInResultError {
//Do error handling
}
// Or
guard let userInfo = result as? SessionManagerCheckInResultSuccess<UserInfo> {
//Error handling here
}
Charles Prado
06/02/2021, 3:51 PM// RESULT
__attribute__((swift_name("SessionManagerCheckInResult")))
@interface SharedSessionManagerCheckInResult<__covariant T> : SharedBase
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer));
+ (instancetype)new __attribute__((availability(swift, unavailable, message="use object initializers instead")));
@end;
// ERROR
__attribute__((objc_subclassing_restricted))
__attribute__((swift_name("SessionManagerCheckInResultError")))
@interface SharedSessionManagerCheckInResultError : SharedSessionManagerCheckInResult<SharedKotlinNothing *>
- (instancetype)initWithException:(SharedKotlinThrowable *)exception __attribute__((swift_name("init(exception:)"))) __attribute__((objc_designated_initializer));
- (instancetype)init __attribute__((swift_name("init()"))) __attribute__((objc_designated_initializer)) __attribute__((unavailable));
+ (instancetype)new __attribute__((unavailable));
- (SharedKotlinThrowable *)component1 __attribute__((swift_name("component1()")));
- (SharedSessionManagerCheckInResultError *)doCopyException:(SharedKotlinThrowable *)exception __attribute__((swift_name("doCopy(exception:)")));
- (BOOL)isEqual:(id _Nullable)other __attribute__((swift_name("isEqual(_:)")));
- (NSUInteger)hash __attribute__((swift_name("hash()")));
- (NSString *)description __attribute__((swift_name("description()")));
@property (readonly) SharedKotlinThrowable *exception __attribute__((swift_name("exception")));
@end;
Sam
06/02/2021, 4:07 PMsealed class RailResult<out V, out E> {
/**
* Represents a successful [RailResult], containing a [value].
*/
data class Success<out V>(val value: V) : RailResult<V, Nothing>()
/**
* Represents a failed [RailResult], containing an [error].
*/
data class Failure<out E>(val error: E) : RailResult<Nothing, E>()
fun valueOrNull(): V? = when (this) {
is Success -> this.value
else -> null
}
val isSuccess: Boolean
get() = when (this) {
is Success -> true
else -> false
}
fun failureOrNull(): E? = when (this) {
is Failure -> this.error
else -> null
}
val isFailure: Boolean
get() = when (this) {
is Failure -> true
else -> false
}
}
valueOrNull
and failureOrNull
methods with guard
and if let
statements.Charles Prado
06/02/2021, 4:22 PMSessionManagerCheckInResultSuccess
or SessionManagerCheckInResultError
, do you see anything that could be wrong in my sealed class ?Sam
06/02/2021, 4:34 PMswitch
statements done over enums with associated values rather than trying to cast it into something. Here’s an enum that wraps the result object I’m using.
enum RailResultEnum<T: AnyObject, E: KotlinError> {
case Success(result: T)
case Failure(error: Error)
static func fromResult(rail: RailResult<T, E>) -> RailResultEnum {
if let r = rail.valueOrNull(), rail.isSuccess {
return .Success(result: r)
} else {
return .Failure(error: rail.nserrorOrNull() ?? NSError(domain: "Kotlin", code: -1, userInfo: [NSLocalizedDescriptionKey: "Uknown error in converting to Cocoa Error"]))
}
}
}
You can then switch over it like this:
switch RailResultEnum.fromResult(rail: result) {
case .Success(let value):
print("success \(value)")
case .Failure(let error):
print("failed \(error)")
}
It has some limitations. A null in a nullable result will fall through to the error condition. T can’t be a primitive, it has to be a class type.Charles Prado
06/03/2021, 1:35 PMCheckInResult
with your RailResult
class. Now I'm able to intercept the error:
static func signIn(idToken: String, serverAuthCode: String) -> Future<UserInfo, Error> {
return Future() { promise in
signIn(idToken: idToken, serverAuthCode: serverAuthCode) { (data, _) in
if let userInfo = data?.valueOrNull() {
promise(Result.success(userInfo))
} else if let _ = data?.failureOrNull() {
// TODO: map the error
promise(Result.failure(AppError.unknown))
}
}
}
}
Thanks so much for this
I'm still a little bit curious why the other solution didn't work. Not so sure, I had seen some similar implementations in some other GitHub repos. My bg is in iOS programming, so there's some stuff that still doesn't make so much sense to me hehe.Sam
06/03/2021, 1:45 PM