Reputation: 8029
I am wanting to return a function which will in turn call back itself. Is it possible to do through returning a closure calling itself?
My problem is that I'm unsure of the correct syntax to use here, as well as I'm not sure if it is even possible due to having a cyclic reference to itself (and swift being heavy on compiler type checking)
I am currying my functions so that the models and presenters do not need to know about the dataGateway further decoupling my code
Some background information about the problem, the API expects a page number to be passed into itself, I do not want to store this state. I want the function to pass something back so that the model can just call the next function when it needs to.
I know the curried function definition looks like this:
function (completion: ([Example.Product], UInt) -> Void) -> Example.Task?
look for __function_defined_here__
in my code samples
func fetch(dataGateway: DataGateway, category: String)(page: UInt)(completion: [Product] -> Void) -> Task? {
return dataGateway.productMap(category, page: page) { products in
completion(products.map { $0.build })
}
}
func fetch(dataGateway: DataGateway, category: String)(page: UInt)(completion: [Product] -> Void) -> (Task?, __function_defined_here__) {
return (dataGateway.productMap(category, page: page) { products in
completion(products.map { $0.build })
}, fetch(dataGateway, category: category)(page: page + 1))
}
func fetch(dataGateway: DataGateway, category: String)(page: UInt)(completion: ([Product], __function_defined_here__) -> Void) -> Task? {
return dataGateway.productMap(category, page: page) { products in
completion(products.map { $0.build }, fetch(dataGateway, category: category)(page: page + 1))
}
}
Upvotes: 1
Views: 634
Reputation: 8029
I ended up solving it with something like the following, what it does is create a class reference to store the next function in. I pass a reference to this object in the completion of the asynchronous operation.
extension Product {
class Next {
typealias FunctionType = (([Product], Next) -> Void) -> Task?
let fetch: FunctionType
init(_ fetch: FunctionType) {
self.fetch = fetch
}
}
func fetch(dataGateway: DataGateway, inCategory category: String)(page: UInt)(completion: ([Product], Next) -> Void) -> Task? {
return dataGateway.products(inCategory: category, page: page)() { products in
completion(products.map { $0.build }, Next(fetch(dataGateway, inCategory: category)(page: page + 1)))
}
}
}
let initial = Product.fetch(dataGateway, inCategory: "1")(page: 0)
pass the function in to a data model
data() { [weak self] products, next in
self?.data = products
self?.setNeedsUpdate()
self?.next = next
}
scrolling down to bottom of table view triggers the above again, using the next
function instead of data
Upvotes: 1