Thanos
Thanos

Reputation: 854

How to pass function to another function that sets its completion closure?

Assuming we have the following method:

func searchLocation(keyword: String, completion: @escaping RequestResult<[Location])>)

where RequestResult is a typealias to public typealias RequestResult<T> = (Result<T>) -> ()

and another method:

func throttleRequest<T>(request: PLACEHOLDER, completion: @escaping RequestResult<[T]> {
    request { result in 
        print("Capturing some data") // do some stuff with the result in this scope
        completion(result)           // tell the caller the network function finsihed with `result`
    }
}

How should I modify the method signatures so I can do something like this:

throttleRequest(request: {
    searchLocation(keyword: "New York", completion: PLACEHOLDER)
}, 
completion: { result in
    if case .success(let found) = result {
       print("location found")
    }
})

so that the following gets printed:

$ Location found
$ Capturing some data

I've entered PLACEHOLDER above on some type definitions, since I can't really figure out what's proper.

Upvotes: 0

Views: 39

Answers (1)

Brandon
Brandon

Reputation: 23485

First, let's use a proper return type instead of () which is the same as Void. It's easier to read when you explicitly specify you're returning void instead of writing (). In any case, what you want is a lambda function parameter.

IE: You want a function that takes a lambda as an argument. Therefore:

public typealias RequestResult<T> = (Result<T, Error>) -> Void

func searchLocation(keyword: String, completion: RequestResult<[Location]>) {
    completion(.success([Location()]))
}

func throttleRequest<T>(request: (RequestResult<[T]>) -> Void, completion: @escaping RequestResult<[T]>) {
    request {
        print("Capturing some data")
        completion($0)
    }
}

So the syntax for a function/lambda as a parameter is: (ArgumentType...) -> ReturnType

  • (Int) -> Void is a function that takes an int, returns Void/nothing.
  • (T) -> U is a function that takes a T argument and returns a U.

Likewise, if you want the parameter to be optional, then it is defined as:

((Arguments...) -> ReturnType)?

Usages:

throttleRequest(request: { result in
        self.searchLocation(keyword: "New York", completion: result)
    }, completion: { result in
        switch result {
        case .success(let locations):
            print(locations)

        case .failure(let error):
            print(error)
        }
    })

Or easier to read (imo you make _ request the parameter):

throttleRequest({ self.searchLocation(keyword: "New York", completion: $0) }) {
        switch $0 {
        case .success(let locations):
            print(locations)

        case .failure(let error):
            print(error)
        }
    }

Upvotes: 0

Related Questions