swift 4中的完成处理程序
Posted
技术标签:
【中文标题】swift 4中的完成处理程序【英文标题】:Completion Handlers in swift 4 【发布时间】:2018-03-12 07:25:18 【问题描述】:我有一个关于使用完成处理程序的问题。我的 ios 程序中有 3 层,ViewController->Service->Networking。我需要通过视图控制器的 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,其中应在服务完成处理程序 (convertDashboardData()) 之后执行视图控制器完成处理程序 (getDashboardDataCompletionHandler)
请帮助我阐明如何实现这一点。我是在尝试像这样链接完成处理程序而犯了设计错误,还是我遗漏了一些明显的东西。
谢谢
--编辑-- 我的请求处理程序实现如下:
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)
【问题讨论】:
你能提供你对RequestHandler
类型的定义吗?
完成。这只是用与我的服务器通信所需的标头初始化我的 URLSession
如果您在DashboardService.swift
中将convertDashboardData(completionHandler: completionHandler)
行切换为completionHandler
,您拥有的代码应该可以工作
关于那条评论://convert object to format acceptable by view
- 如果你想实现这一点,你的DashboardService
也应该扮演一个适配器的角色,所以getDashboardData
方法的声明应该是这样的:func getDashboardData(completionHandler: @escaping (SomeTypeThatAdjustsDashboardDataToFormatAcceptableByView) -> Void)
。然后您必须在 DashboardService
中进行此转换
SomeTypeThatAdjustsDashboardDataToFormatAcceptableByView 将是另一个函数/闭包,不是吗?
【参考方案1】:
这种情况下使用委托比较清楚,比如这样:
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)
【讨论】:
我假设在 requestHandler.requestDashboardData(url: URL) 的实现中,我必须调用 delegate.didLoaded(request) ?? 是的,你必须在从 json 解码后调用它 对不起,我花了这么长时间才接受你的回答。当您发布此答案时,我有点实现了 completionHandler 方法。我现在意识到在这种情况下我发现委托方法更干净,并实现了它,我是我的代码。谢谢以上是关于swift 4中的完成处理程序的主要内容,如果未能解决你的问题,请参考以下文章
Swift 4 tableview 不使用通用完成处理程序显示数据