swiftescapingclosures

Allow Multiple optional parameter in @escaping in swift


I have this method :

    func getdata(someString: String, onComplete: @escaping ((_ someArrayData: [String], _ error: Error?) -> Void)) {
            var result: [BanPhone] = []
            // Some Actions
            if(someaction is successful) 
           { 
                                onComplete(result)
    
           }
           else {
                                onComplete(result, Error)
            }
}

Error is optional i want to pass this parameter only when i get error. else i wanted to send back result. How can i do that over here


Solution

  • In answer to your question, you call it with a result when successful, passing nil for the error parameter, e.g. in success scenario:

    onComplete(result, nil)
    

    And if there was some error, you’d call it supplying the error code, but no value:

    onComplete(nil, error)
    

    Better, we would prefer to use Result type. See https://www.swiftbysundell.com/basics/result/ for practical discussion.

    We favor Result over the “two optional parameters” pattern because it makes it explicit to the caller that either it will be successful with a value or a failure with an error, one or the other, but not both.

    func fetchData(with someString: String, completion: @escaping (Result<[String], Error>) -> Void)) {
        …
    
        doingSomethingAsynchronous {
            …
    
            // if failed
        
            if let error {
                completion(.failure(error))
                return
            }
        
            // if successful
        
            completion(.success(value))
        }
    }
    

    And use it like so:

    fetchData(with: string) { result in
        switch result {
        case .failure(let error):
            print(error)
    
        case .success(let value):
            // do something with `value`
        }
    }
    

    Now, this is how the two optional parameter pattern tends to work in practice (it is one or the other), but Result formalizes the contract, saves you from unwrapping optionals, etc.


    Nowadays, we would use Swift concurrency, which is far simpler:

    func fetchData(with someString: String) async throws -> [String] {
        …
    
        return try await doingSomethingAsynchronous()
    }
    

    So, you would either return a value or throw an error.