Skip to content

Instantly share code, notes, and snippets.

@rnapier
Last active August 29, 2015 14:26
Show Gist options
  • Save rnapier/9217d1870504fc9641df to your computer and use it in GitHub Desktop.
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 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