Swift函数返回多种类型

时间:2020-07-03 17:05:59

标签: ios swift

我正在尝试构建一个名为makePostBuilder的实用函数,它看起来像这样。

fileprivate func makePostRequest(apiUrl: String, params: [String: String]) -> URLRequest? {
        // build url
        let urlString = "\(apiUrl)"
        guard let serviceUrl = URL(string: urlString) else { return nil }
        
        // build url request
        var request = URLRequest(url: serviceUrl)
        request.httpMethod = "POST"
        request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
        
        //set http body for url request with incoming params
        guard let httpBody = try? JSONSerialization.data(withJSONObject: params, options: []) else {
            return nil 
        }
        request.httpBody = httpBody
        return request
    }

此函数的返回类型显然不正确。我希望它返回一个URLRequest实例或一个Error实例。错误实例主要是因为可选的解包操作可以返回有价值的消息,而不仅仅是返回nil(根据当前实现。

我一直在思考typealias的思路,但是我不确定这是否是正确的方法。

//not sure if this is right
typealias CustomRequestType = (URLRequest, Error) 

在适当的类型定义的最后,我希望函数看起来像这样


fileprivate func makePostRequest(apiUrl: String, params: [String:String]) -> CustomType {
  let urlString = apiUrl
  guard let serviceUrl = URL(string: urlString) else { return //error based on customtype? }

  // build url request
  var request = URLRequest(url: serviceUrl)
  request.httpMethod = "POST"
  request.setValue("Application/json", forHTTPHeaderField: "Content-Type")

  //set http body for url request with incoming params
  guard let httpBody = try? JSONSerialization.data(withJSONObject: params, options: []) else {
    return //error type 
  }

  //return success type
  request.httpBody = httpBody
  return request
}

我想我已经接近了,但还没到那儿。如果社区可以为我提供一些文档,我也很喜欢!

更新:可能的解决方案?

//does this seem plausible?

enum DCError: String, Error {
    case invalidUrl = "the url seems to be invalid"
}

typealias DCUrlRequestType = Result<URLRequest, Error>

fileprivate func makePostRequest(apiUrl: String, params: Dictionary<String, String>) -> DCUrlRequestType {
    let urlString = apiUrl
    guard let serviceUrl = URL(string: urlString) else {
        return DCUrlRequestType.failure(DCError.invalidUrl)
    }
    
    var request = URLRequest(url: serviceUrl)
    request.httpMethod = "POST"
    request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
    
    return DCUrlRequestType.success(request)
}

1 个答案:

答案 0 :(得分:3)

有一个内置enum Result可以用作返回类型。并且在无法创建URLError(code: .badURL)的情况下,可以使用URL(由Foundation提供)。因此:

fileprivate func makePostRequest(apiUrl: String, params: [String: String]) -> Result<URLRequest, Error> {
    let urlString = "\(apiUrl)"
    guard let serviceUrl = URL(string: urlString) else {
        return .failure(URLError(.badURL))
    }

    var request = URLRequest(url: serviceUrl)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    do {
        request.httpBody = try JSONSerialization.data(withJSONObject: params, options: [])
    } catch {
        return .failure(error)
    }
    return .success(request)
}

但是...

编写此函数的自然方法是声明它throws,如下所示:

fileprivate func makePostRequest(apiUrl: String, params: [String: String]) throws -> URLRequest? {
    let urlString = "\(apiUrl)"
    guard let serviceUrl = URL(string: urlString) else {
        throw URLError(.badURL)
    }

    var request = URLRequest(url: serviceUrl)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try JSONSerialization.data(withJSONObject: params, options: [])
    return request
}

然后让呼叫者使用do/catch来处理错误,而不是让呼叫者切换Result情况。

如果呼叫者确实希望使用Result,则可以使用Result(catching:)初始化程序,该初始化程序(带有结尾闭包语法)如下所示:

let requestResult = Result { try makePostRequest(apiUrl: urlString, params: [:]) }