Skip to content

Instantly share code, notes, and snippets.

@dodikk
Last active December 15, 2016 10:30
Show Gist options
  • Select an option

  • Save dodikk/b547701f0dbad794d33f2ad1c198e1e5 to your computer and use it in GitHub Desktop.

Select an option

Save dodikk/b547701f0dbad794d33f2ad1c198e1e5 to your computer and use it in GitHub Desktop.
Swift compiler error related to FutureKit callbacks
PKLoginModelPromise.swift:62:22: error: enum element 'main' cannot be referenced as an instance member
.onFail(.main, block:
^
github "FutureKit/FutureKit" "v3"
github "ReSwift/ReSwift" == 3.0.0
github "ReSwift/ReSwiftRouter" == 0.5.1
public class PKLoginModelPromise : PKLoginModel
{
private let reduxStore: PKAppStateStore
private let networkLoader: PKLoginService
private let tokenRepo: PKAccessTokenRepo
public init(withReduxStore reduxStore: PKAppStateStore,
networkLoader: PKLoginService,
tokenRepo: PKAccessTokenRepo)
{
self.reduxStore = reduxStore
self.networkLoader = networkLoader
self.tokenRepo = tokenRepo
}
public func loginAsync(
_ email: String,
password: String)
{
let loginFromNetFuture: FetchAccessTokenFuture =
LoginFutures.login(
withService: self.networkLoader,
email: email,
password: password)
let tokenRepo = self.tokenRepo
let reduxStore = self.reduxStore
loginFromNetFuture.onSuccess(.background, block:
{
tokenFromNet in
let storeLoginFuture = PKAccessTokenRepoFutures.storeToken(tokenFromNet, inRepo: tokenRepo)
return storeLoginFuture
})
.onSuccess(.main, block:
{
tokenFromDisk in
let action = UpdateAccessTokenAction(accessToken: tokenFromDisk)
reduxStore.dispatch(action)
return tokenFromDisk
})
.onFail(.main, block:
{
diskError in
let action = LoginErrorAction(error: diskError)
self.reduxStore.dispatch(action)
return diskError
})
}
}
@mishagray

Copy link
Copy Markdown

So the latest version of the onFail() handler typically does NOT return any values.
It doesn't 're-map' the future into a new Future (unlike onSuccess or onComplete).
This is different than javascript Promises 'catch' which by default 'eats' the error. And then leads to confusion and complexity.

So in FutureKit onFail() will let you handle errors, but it still always returns the same 'Failed' Future. Which will usually lead to more reliable error handling.

onFail() allows you to add 'side' effects when a Future fails, but it always returns the same failed 'Future'. So you usually just return Void.

If you want to 'eat' or modify the Failed Future, use 'onComplete' or 'mapError'.

So try removing the return diskError

.onFail(.main, block:
            {
                diskError in
                
                let action = LoginErrorAction(error: diskError)
                self.reduxStore.dispatch(action)


            })

The Swift type inference machine can be fickle, and when it gets confused it can lead to confusing errors.

if that doesn't help... sometimes it can help to formally declare the return values for onSuccess, since it uses helps the compiler figure out 'which' onSuccess or onComplete method to bind to.

public class PKLoginModelPromise : PKLoginModel
{
    private let reduxStore: PKAppStateStore
    private let networkLoader: PKLoginService
    private let tokenRepo: PKAccessTokenRepo
    
    public init(withReduxStore reduxStore: PKAppStateStore,
                networkLoader: PKLoginService,
                tokenRepo: PKAccessTokenRepo)
    {
        self.reduxStore = reduxStore
        self.networkLoader = networkLoader
        self.tokenRepo = tokenRepo
    }
    
    
    public func loginAsync(
                     _ email: String,
                    password: String)
    {
        let loginFromNetFuture: FetchAccessTokenFuture =
            LoginFutures.login(
                        withService: self.networkLoader,
                              email: email,
                           password: password)
        
        let tokenRepo = self.tokenRepo
        let reduxStore = self.reduxStore
        
        loginFromNetFuture.onSuccess(.background)
            {
                tokenFromNet -> Future<Token> in  // idk what type PKAccessTokenRepoFutures.storeToken returns so I'm guessing it's something.
                
                return PKAccessTokenRepoFutures.storeToken(tokenFromNet, inRepo: tokenRepo)
            }
            .onSuccess(.main) {
                tokenFromDisk -> Token in  // adding return type again
                
                let action = UpdateAccessTokenAction(accessToken: tokenFromDisk)
                reduxStore.dispatch(action)
                
                return tokenFromDisk
            }
            .onFail(.main)
            {
                diskError -> Void in  // onFail works better as Void!
                
                let action = LoginErrorAction(error: diskError)
                self.reduxStore.dispatch(action)
            }

    }
}

@dodikk

dodikk commented Dec 15, 2016

Copy link
Copy Markdown
Author

So try removing the return diskError

I still had similar errors even without a return statement.

if that doesn't help... sometimes it can help to formally declare the return values for onSuccess

And this has solved my issue. Thanks a lot for responding so quickly.

tokenFromNet -> Future<Token> in
tokenFromDisk -> Token in  // adding return type again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment