ios - swift 4 中的完成处理程序

标签 ios swift closures completionhandler

我有一个问题,我正在尝试解决与完成处理程序的使用有关的问题。我的 iOS 程序有 3 层:ViewController->Service->Networking。我需要通过 View Controller 的 API 调用加载一些数据。

我在 ViewController 中定义了函数(completionHandlers),这些函数应该在数据请求完成后执行,并且在只有两层存在时实现完成处理程序时很舒服,但在以下情况下会感到困惑:

DashboardViewController.swift

import UIKit

@IBDesignable class DashboardViewController: UIViewController {

    @IBOutlet weak var stepCountController: ExpandedCardView!
    var articles:[Article]?
    let requestHandler = RequestHandler()
    let dashboardService = DashboardService()

    override func viewDidLoad() {
        super.viewDidLoad()
        dashboardService.getDashboardData(completionHandler: getDashboardDataCompletionHandler)
    }

    func getDashboardDataCompletionHandler(withData: DashboardDataRequest) {
        print(withData)
    }
} 

DashboardService.swift

import Foundation

class DashboardService: GeneralService {

    var requestHandler: DashboardRequestHandler

    override init() {
        requestHandler = DashboardRequestHandler()
        super.init()
    }

    //this function should execute requestHandler.requestDashboardData(), and then execute convertDashboardData() with the result of previous get request
    func getDashboardData(completionHandler: @escaping (DashboardDataRequest) -> Void) {
        //on network call return
        guard let url = URL(string: apiResourceList?.value(forKey: "GetDashboard") as! String) else { return }
        requestHandler.requestDashboardData(url: url, completionHandler: convertDashboardData(completionHandler: completionHandler))
    }

    func convertDashboardData(completionHandler: (DashboardDataRequest) -> Void) {
        //convert object to format acceptable by view
    }
}

DashboardRequestHandler.swift

import Foundation

class DashboardRequestHandler: RequestHandler {

    var dataTask: URLSessionDataTask?

    func requestDashboardData(url: URL, completionHandler: @escaping (DashboardDataRequest) -> Void) {
        dataTask?.cancel()

        defaultSession.dataTask(with: url, completionHandler: {(data, response, error) in
            if error != nil {
                print(error!.localizedDescription)
            }

            guard let data = data else {
                return
            }

            do {
                let decodedJson = try JSONDecoder().decode(DashboardDataRequest.self, from: data)
                completionHandler(decodedJson)
            } catch let jsonError {
                print(jsonError)
            }

        }).resume()
    }
}

如果你看看 DashboardService.swift 中的评论,我的问题就很明显了。我将一个完成处理程序从 ViewController 传递到 Service,并且 Service 有自己的完成处理程序,该处理程序会传递给 RequestHandler,其中 View Controller 完成处理程序 (getDashboardDataCompletionHandler) 应在 Service 完成处理程序 (convertDashboardData()) 之后执行

请帮助我澄清如何实现这一点。我尝试像这样链接完成处理程序是否犯了设计错误,或者我是否遗漏了一些明显的东西。

谢谢

--编辑-- 我的请求处理程序实现如下:

import Foundation

class RequestHandler {
    //    let defaultSession = URLSession(configuration: .default)
    var defaultSession: URLSession!

    init() {
        guard let path = Bundle.main.path(forResource: "Api", ofType: "plist") else {
            print("Api.plist not found")
            return
        }
        let apiResourceList = NSDictionary(contentsOfFile: path)
        let config = URLSessionConfiguration.default
        if let authToken = apiResourceList?.value(forKey: "AuthToken") {
            config.httpAdditionalHeaders = ["Authorization": authToken]
        }
        defaultSession = URLSession(configuration: config)
    }
}

最佳答案

在这种情况下使用委托(delegate)会更清晰,例如这样:

protocol DashboardServiceDelegate {
    func didLoaded(_ viewModel: DashboardViewModel)
}

class DashboardViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        dashboardService.delegate = self
        dashboardService.getDashboardData()
    }
}
extension DashboardViewController: DashboardServiceDelegate {
    func didLoaded(_ viewModel: DashboardViewModel) {
        ///
    }
}


protocol DashboardRequestHandlerDelegate() {
    func didLoaded(request: DashboardDataRequest)
}

class DashboardService: GeneralService {
    private lazy var requestHandler: DashboardRequestHandler = { reqHandler in
        reqHandler.delegate = self
        return reqHandler
    }(DashboardRequestHandler())

    func getDashboardData() {
        guard let url = ...
        requestHandler.requestDashboardData(url: url)
    }
}

extension DashboardService: DashboardRequestHandlerDelegate {
    func didLoaded(request: DashboardDataRequest) {
        let viewModel = convert(request)
        delegate.didLoaded(viewModel)
    }
}

关于ios - swift 4 中的完成处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49230041/

相关文章:

ios - 在沙盒模式下使用测试用户登录失败(iOS SDK)

ios - 单元格中的个人资料图片未正确更新

swift - 在结构中使用静态闭包安全吗?

ios - iOS8 上的自动布局错误,但 iOS9 上没有

ios - 如何将 NSData 转换回 NSArray

ios - 在推送的 ViewController 中隐藏 TabBar 时出现问题,TabBar 在延迟一段时间后出现

ios - 如何通过 Firebase 在 GoogleSignIn 后重定向到另一个屏幕? iOS系统

ios - Swift Plist 读取和初始化数组作为键的对象

javascript - 在闭包之外引用数组是否会导致内存泄漏?

javascript - 如何检查javascript中绑定(bind)的闭包变量?