【问题标题】:Generic function with AlamofireAlamofire 的通用函数
【发布时间】:2018-06-19 15:01:19
【问题描述】:

我使用使用 Alamofire 的 iOS 应用程序,我想编写一个通用函数,用于将数据从服务器发送和检索到可解码对象,我的函数如下:

func pop <T : Codable>  (_ Url: inout String, _ popedList: inout [T]) {
    let url = URL(string:Url)
    Alamofire.request(url!, method: .post).responseJSON { response in
        let result = response.data
        do {
            let data = try JSONDecoder().decode(popedList, from: result!)// get error here
            print(data[0])

            let jsonEncoder = JSONEncoder()
            let jsonData = try! jsonEncoder.encode(data[0])
            let jsonString = String(data: jsonData, encoding: .utf8)
            print("jsonString: \(String(describing: jsonString))")

        } catch let e as NSError {
            print("error : \(e)")
        }
    }
} 

以及将对象发送到服务器的函数如下:

func push <T : Codable>  (_ Url: inout String, _ pushObject: inout T) {
    let jsonData = try! JSONEncoder().encode(pushObject)
    let jsonString = String(data: jsonData, encoding: .utf8)
    print("jsonString: \(String(describing: jsonString))")

    let url = URL(string:Url)

    Alamofire.request(url!,
                      method: .post,
                      parameters:jsonString)//it's need to creat a Dictionary instate of String
        .validate(statusCode: 200..<300)
        .validate(contentType: ["application/json"])
        .response { response in
            // response handling code
             let result = response.data
            print(response.data)
    }
}

我在第一个函数中遇到错误,

“不能使用类型为'([T], from: Data)'的参数列表调用'decode'”

“转义闭包只能通过值显式捕获inout参数”

编写这些以实现泛型功能的最佳方法是什么?

【问题讨论】:

  • 这两个函数都有很多不好的做法。除非绝对需要,否则不应在 Swift 中使用 inout 参数。也不要使用强制转换、强制解包和强制尝试,优雅地处理错误。

标签: swift alamofire generic-programming decodable


【解决方案1】:

经过几次搜索并尝试编辑我的函数后,我能够重写我的两个函数,以便得到我需要的:

 func pop<T: Decodable>(from: URL, decodable: T.Type, completion:@escaping (_ details: [T]) -> Void)
            {
       Alamofire.request(from, method: .post).responseJSON { response in
                let result_ = response.data
                do {
                    let data = try JSONDecoder().decode([T].self, from: result_!)
                    //let data = try JSONDecoder().decode(decodable, from: result_!)// get error here
                    //print(data[0])
                    print("data[0] : \(data[0])")
                    completion(data)
                } catch let e as NSError {
                    print("error : \(e)")
                }
            }
        }

    func push <T : Codable>  (_ Url:  String, _ pushObject:  T)
        {
            let jsonData = try! JSONEncoder().encode(pushObject)
            let jsonString = String(data: jsonData, encoding: .utf8)
            print("jsonString: \(String(describing: jsonString))")

            let url = URL(string:Url)

            Alamofire.request(url!,
                              method: .post,
                              parameters:convertToDictionary(text: jsonString!))//it's need to creat a Dictionary instate of String
                .validate(statusCode: 200..<300)
                .validate(contentType: ["application/json"])
                .response { response in
                    // response handling code
                    print(response.data!)
                    if let jsonData = response.data {
                        let jsonString = String(data: jsonData, encoding: .utf8)
                        print("response.data: \(String(describing: jsonString))")
                    }
            }
        }

        func convertToDictionary(text: String) -> [String: Any]? {
            if let data = text.data(using: .utf8) {
                do {
                    return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
                } catch {
                    print(error.localizedDescription)
                }
            }
            return nil
        }

【讨论】:

    【解决方案2】:

    对于第一个函数,JSONDecoder.decode() 需要 2 个参数:

    • 要解码到的类型:您希望它解码到的类/结构。这不是实例化的对象,只是类型。
    • 要解码的数据:将转换为您指定的类型的通用数据对象。

    因此,为了能够编写您的函数,使其具有通用 URL 和结果对象,您需要将对象类型和回调传递给它以将结果传递给它,因为网络操作是异步的。

    func dec<T: Decodable>(from: URL, decodable: T.Type, result: (T) -> Void) { 
        // your Alamofire logic
        let data = try JSONDecoder().decode(popedList, from: result!)
        result(data)
    }
    

    您可以将相同的逻辑应用于第二个函数。

    请注意,这不是处理最终错误的最佳方法,只是说明如何使用通用函数处理编码的示例。

    【讨论】:

    • 能否重写整个函数以及如何调用它?
    【解决方案3】:

    JSONDecoder().decode 方法采用类型和数据参数。密码类型不是popedList

    let data = try JSONDecoder().decode([T].self, from: result!)
    

    输入输出参数 函数参数默认为常量。尝试从该函数的主体内更改函数参数的值会导致编译时错误。这意味着您不能错误地更改参数的值。如果您希望函数修改参数的值,并且希望这些更改在函数调用结束后仍然存在,请将该参数定义为 in-out 参数。

    你没有在两个函数中改变popedList的值,所以使用inout是没有意义的。

    【讨论】:

    • 能否重写整个函数以及如何调用它?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-11
    • 1970-01-01
    • 1970-01-01
    • 2020-07-24
    • 2015-01-17
    • 2021-12-02
    相关资源
    最近更新 更多