Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用dataTask在func上快速显示和隐藏活动指示器_Ios_Swift_Task - Fatal编程技术网

Ios 使用dataTask在func上快速显示和隐藏活动指示器

Ios 使用dataTask在func上快速显示和隐藏活动指示器,ios,swift,task,Ios,Swift,Task,我有一个函数,可以进行调用并等待服务器的响应。我想在请求之前显示活动指示器,并在同一函数的回答之后隐藏它。为什么?避免代码重复。我将在其他操作中调用服务器 它现在的工作方式是:手动调用登录按钮上的开始和停止动画 为了测试指示器,我在服务器上添加了睡眠 问题:如何显示/隐藏每次呼叫服务器的指示灯? 登录视图上的按钮: 内部函数makeRequestPost func makeRequestPost<T>(endpoint: String, req

我有一个函数,可以进行调用并等待服务器的响应。我想在请求之前显示活动指示器,并在同一函数的回答之后隐藏它。为什么?避免代码重复。我将在其他操作中调用服务器

它现在的工作方式是:手动调用登录按钮上的开始和停止动画

为了测试指示器,我在服务器上添加了睡眠

问题:如何显示/隐藏每次呼叫服务器的指示灯?

登录视图上的按钮:

内部函数makeRequestPost

func makeRequestPost<T>(endpoint: String,
                    requestType: String = "GET",
                    requestBody: Data,
                    activityIndicator: CustomActivityIndicator? = nil,
                    completionHandler: @escaping (ApiContainer<T>?, Error?) -> ()) {


activityIndicator?.start() .......
func makeRequestPost(端点:字符串,
requestType:String=“GET”,
请求主体:数据,
activityIndicator:CustomActivityIndicator?=零,
completionHandler:@正在转义(ApiContainer?,错误?->()){
活动指示灯?.start()。。。。。。。
在操作按钮上:

let loading = CustomActivityIndicator(viewContainer: self.view, startAnimate: true)
    makeRequestPost(endpoint: "http://blog.local:4711/api/login",
                    requestType: "POST",
                    requestBody: jsonData,
                    activityIndicator: loading,
                    completionHandler: { (response : ApiContainer<Login>?, error : Error?) in
let load=CustomActivityIndicator(viewContainer:self.view,startAnimate:true)
makeRequestPost(端点:http://blog.local:4711/api/login",
请求类型:“POST”,
请求主体:jsonData,
活动指示器:加载,
completionHandler:{(响应:ApiContainer?,错误:error?)位于

我假设您的makeRequest函数位于单独的服务类中,因此基本上您可以在onRequestComplete块上添加常规onrequeststart,并在调用postmakeRequest时执行它们

请看一看,也许你会发现它很有用

编辑:

声明全局函数结束并将其暴露给整个模块是一个坏主意。最终可能会有数千个辅助函数,项目的复杂性将成倍增加。尽管fews仍然保护过程性方法(当函数以这种方式声明时),社区在80年代后期从它演变而来。所以我强烈建议您声明类来包装所有与网络相关的函数(NetworkClient/Service/Manager等)

回到您的问题:您可以将活动指示器作为参数:

func makeRequestPost<T>(endpoint: String,
                    requestType: String = "GET",
                    requestBody: Data,
                    activityIndicator: CustomActivityIndicator?,
                    completionHandler: @escaping (ApiContainer<T>?, Error?) -> ()) 
func makeRequestPost(端点:字符串,
requestType:String=“GET”,
请求主体:数据,
activityIndicator:CustomActivityIndicator?,
completionHandler:@正在转义(ApiContainer?,错误?->())

因此,您可以在函数中启动并完成它,而不是在任何时候使用函数复制/粘贴代码。

在阅读了一些教程后,我最终回答了自己的问题

我做了什么?

1) 我创建了一个类:ViewControllerUtils

2) 在func makeRequestPost上,我添加了一个新的参数(视图),并调用启动和停止加载视图

func makeRequestPost<T>(endpoint: String,
                    requestType: String = "GET",
                    requestBody: Data,
                    view: UIView,
                    completionHandler: @escaping (ApiContainer<T>?, Error?) -> ()) {

ViewControllerUtils().showActivityIndicator(uiView: view)

guard let url = URL(string: endpoint) else {
    print("Error: cannot create URL")
    let error = BackendError.urlError(reason: "Could not create URL")
    completionHandler(nil, error)
    return
}

var urlRequest = URLRequest(url: url)
let session = URLSession.shared
urlRequest.httpMethod = "POST"
urlRequest.httpBody = requestBody
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")

let task = session.dataTask(with: urlRequest, completionHandler: {
    (data, response, error) in

    ViewControllerUtils().hideActivityIndicator(uiView: view)
    guard let responseData = data else {
        print("Error: did not receive data")
        completionHandler(nil, error)
        return
    }
    guard error == nil else {
        completionHandler(nil, error!)
        return
    }

    do {
        let response = try JSONDecoder().decode(ApiContainer<T>.self, from: responseData)
        completionHandler(response, nil)
    }
    catch {
        print("error trying to convert data to JSON")
        print(error)
        completionHandler(nil, error)
    }

})

task.resume()

}
func makeRequestPost(端点:字符串,
requestType:String=“GET”,
请求主体:数据,
视图:UIView,
completionHandler:@正在转义(ApiContainer?,错误?->()){
ViewControllerUtils().showActivityIndicator(uiView:view)
guard let url=url(字符串:端点)else{
打印(“错误:无法创建URL”)
let error=BackendError.urlError(原因:“无法创建URL”)
completionHandler(无,错误)
返回
}
var urlRequest=urlRequest(url:url)
让session=URLSession.shared
urlRequest.httpMethod=“POST”
urlRequest.httpBody=requestBody
urlRequest.addValue(“应用程序/json”,forHTTPHeaderField:“内容类型”)
URL请求.addValue(“应用程序/json”,用于HttpHeaderField:“接受”)
让task=session.dataTask(带:urlRequest,completionHandler:{
(数据、响应、错误)
ViewControllerUtils().hideActivityIndicator(uiView:view)
guard let responseData=其他数据{
打印(“错误:未收到数据”)
completionHandler(无,错误)
返回
}
保护错误==nil else{
completionHandler(无,错误!)
返回
}
做{
让response=try JSONDecoder().decode(ApiContainer.self,from:responseData)
completionHandler(响应,无)
}
抓住{
打印(“尝试将数据转换为JSON时出错”)
打印(错误)
completionHandler(无,错误)
}
})
task.resume()
}

它还不是一个类。我在我的问题中添加了helper函数。尽量避免将函数保留为全局函数。在这种情况下,您可以创建可以发送请求的NetwrokService,并为其提供requestDidSent/DidComplete块,如果有,您在整个应用程序中使用相同的活动指示器。
func makeRequestPost<T>(endpoint: String,
                    requestType: String = "GET",
                    requestBody: Data,
                    activityIndicator: CustomActivityIndicator? = nil,
                    completionHandler: @escaping (ApiContainer<T>?, Error?) -> ()) {


activityIndicator?.start() .......
let loading = CustomActivityIndicator(viewContainer: self.view, startAnimate: true)
    makeRequestPost(endpoint: "http://blog.local:4711/api/login",
                    requestType: "POST",
                    requestBody: jsonData,
                    activityIndicator: loading,
                    completionHandler: { (response : ApiContainer<Login>?, error : Error?) in
func makeRequestPost<T>(endpoint: String,
                    requestType: String = "GET",
                    requestBody: Data,
                    activityIndicator: CustomActivityIndicator?,
                    completionHandler: @escaping (ApiContainer<T>?, Error?) -> ()) 
class ViewControllerUtils {

var container: UIView = UIView()
var loadingView: UIView = UIView()
var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()

/*
 Show customized activity indicator,
 actually add activity indicator to passing view

 @param uiView - add activity indicator to this view
 */
func showActivityIndicator(uiView: UIView) {

    self.container.frame = uiView.frame
    self.container.center = uiView.center
    self.container.backgroundColor = UIColor.white
    self.container.alpha = 0.7
    self.container.tag = 789456123

    loadingView.frame = CGRect(x:0, y:0, width:80, height:80)
    loadingView.center = uiView.center
    loadingView.backgroundColor = UIColor.black
    loadingView.clipsToBounds = true
    loadingView.layer.cornerRadius = 10

    activityIndicator.frame = CGRect(x:0.0, y:0.0, width:40.0, height:40.0);
    activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.whiteLarge
    activityIndicator.center = CGPoint(x:loadingView.frame.size.width / 2, y:loadingView.frame.size.height / 2);

    DispatchQueue.main.async {
        self.loadingView.addSubview(self.activityIndicator)
        self.container.addSubview(self.loadingView)
    uiView.addSubview(self.container)
    self.activityIndicator.startAnimating()
    }
}

/*
 Hide activity indicator
 Actually remove activity indicator from its super view

 @param uiView - remove activity indicator from this view
 */
func hideActivityIndicator(uiView: UIView) {
    DispatchQueue.main.async {
    if let viewWithTag = uiView.viewWithTag(789456123) {
        viewWithTag.removeFromSuperview()
    }
    else {
        return
    }
    }
}

/*
 Define UIColor from hex value

 @param rgbValue - hex color value
 @param alpha - transparency level
 */
func UIColorFromHex(rgbValue:UInt32, alpha:Double=1.0)->UIColor {
    let red = CGFloat((rgbValue & 0xFF0000) >> 16)/256.0
    let green = CGFloat((rgbValue & 0xFF00) >> 8)/256.0
    let blue = CGFloat(rgbValue & 0xFF)/256.0
    return UIColor(red:red, green:green, blue:blue, alpha:CGFloat(alpha))
}

}
func makeRequestPost<T>(endpoint: String,
                    requestType: String = "GET",
                    requestBody: Data,
                    view: UIView,
                    completionHandler: @escaping (ApiContainer<T>?, Error?) -> ()) {

ViewControllerUtils().showActivityIndicator(uiView: view)

guard let url = URL(string: endpoint) else {
    print("Error: cannot create URL")
    let error = BackendError.urlError(reason: "Could not create URL")
    completionHandler(nil, error)
    return
}

var urlRequest = URLRequest(url: url)
let session = URLSession.shared
urlRequest.httpMethod = "POST"
urlRequest.httpBody = requestBody
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")

let task = session.dataTask(with: urlRequest, completionHandler: {
    (data, response, error) in

    ViewControllerUtils().hideActivityIndicator(uiView: view)
    guard let responseData = data else {
        print("Error: did not receive data")
        completionHandler(nil, error)
        return
    }
    guard error == nil else {
        completionHandler(nil, error!)
        return
    }

    do {
        let response = try JSONDecoder().decode(ApiContainer<T>.self, from: responseData)
        completionHandler(response, nil)
    }
    catch {
        print("error trying to convert data to JSON")
        print(error)
        completionHandler(nil, error)
    }

})

task.resume()

}