Last active
August 29, 2015 14:26
-
-
Save rnapier/9217d1870504fc9641df to your computer and use it in GitHub Desktop.
Protocol-based implementation of "Swift currying in practice" (https://medium.com/@NSomar/swift-currying-in-practice-85d3f1064b56)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// This is copied from Omar's original | |
// | |
// Stub post | |
class Post {} | |
enum ResponseError: ErrorType { | |
// The server error has expired, please refresh it | |
case SessionExpired | |
// Any other error | |
case OtherKindOfError | |
} | |
// Function to refresh the session | |
// This function connects to the server and perform a refresh token | |
func refreshSession(completion: () -> () ) { | |
completion() | |
} | |
typealias CompletionClousure = ([Post]?, ResponseError?) -> () | |
// Fetch the posts | |
func fetchPosts(userId: String, completion: CompletionClousure) { | |
// This is a hack to try out the session expiry | |
// If post = "123" then session is expired | |
if userId == "123" { | |
completion(nil, .SessionExpired) | |
return | |
} | |
let posts = [Post(), Post()] | |
completion(posts, nil) | |
} | |
// | |
// End copying | |
// | |
// | |
//: ## Protocol implementation | |
// Simple protocol for all Fetchers | |
protocol Fetcher { | |
typealias ResponseType | |
func fetch(completion: (ResponseType?, ResponseError?) -> ()) | |
} | |
// A specific fetcher. We'll reuse fetchPosts, but of course that normally would be encoded here instead. | |
struct PostFetcher: Fetcher { | |
let userId: String | |
func fetch(completion: ([Post]?, ResponseError?) -> ()) { | |
fetchPosts(userId, completion: completion) | |
} | |
} | |
// This takes a fetcher and returns a fetcher. This composes identically to curried functions. | |
struct RefreshFetcher<F: Fetcher>: Fetcher { | |
let base: F | |
func fetch(completion: (F.ResponseType?, ResponseError?) -> ()) { | |
// All of this is copied exactly from Omar's work. I just changed "request" to "base.fetch" | |
base.fetch { (response, error) in | |
if let error = error where error == .SessionExpired { | |
refreshSession { | |
print("Refresshing Session") | |
self.base.fetch { (response, error) in | |
// Display the posts | |
completion(response, error) | |
} | |
} | |
return | |
} | |
// Display the posts | |
completion(response, error) | |
} | |
} | |
init(_ base: F) { self.base = base } | |
} | |
// And now we can use it: | |
PostFetcher(userId: "123").fetch{ posts, error in | |
print("Use posts to fill UI") | |
} | |
// And we can compose with it easily, just like currying. | |
RefreshFetcher(PostFetcher(userId: "123")).fetch{ posts, error in | |
print("Use posts to fill UI") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment