使用dataTask

时间:2018-01-08 16:24:01

标签: ios swift task

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

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

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

问题:如何显示/隐藏每次调用服务器的指示符?

登录视图上的

按钮:

@IBAction func btnLog2(_ sender: Any) {

    DispatchQueue.main.async(execute: {
        customActivityIndicatory(self.view, startAnimate: true)
    })

    let user = User(email: login_email.text!, password : login_password.text!)

    var jsonData = Data()
    let jsonEncoder = JSONEncoder()
    do {
        jsonData = try jsonEncoder.encode(user)
    }
    catch {
    }

    makeRequestPost(endpoint: "http://blog.local:4711/api/login",
                    requestType: "POST",
                    requestBody: jsonData,
                    completionHandler: { (response : ApiContainer<Login>?, error : Error?) in
                        if let error = error {
                            print("error calling POST on /todos")
                            print(error)
                            return
                        }

                        DispatchQueue.main.async(execute: {
                            customActivityIndicatory(self.view, startAnimate: false)
                        })

                        let a = (response?.result[0])!
                        let b = (response?.meta)!

                        if(b.sucess == "yes") {
                            DAKeychain.shared["email"] = (user.email) // Store
                            DAKeychain.shared["token"] = (a.token) // Store
                            DispatchQueue.main.async(execute: {
                                let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "tabBarClients") as UIViewController

                                self.present(viewController, animated: false, completion: nil)
                            })
                        }
                        else
                        {
                            DispatchQueue.main.async(execute: {
                                let myAlert = UIAlertController(title: "Error", message: "Invalid E-mail or Password", preferredStyle: .alert)
                                let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
                                myAlert.addAction(okAction)

                                self.present(myAlert, animated: true, completion: nil)
                            })
                        }
    } )


}

请求功能

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

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
    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<T>(endpoint: String,
                    requestType: String = "GET",
                    requestBody: Data,
                    completionHandler: @escaping (ApiContainer<T>?, Error?) -> ()) {

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
    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()

}

修改

我创建了一个CustomActivityIndi​​cator类,但是没有显示加载器。开始和停止打印在控制台上。

import Foundation
import UIKit
class CustomActivityIndicator {

var viewContainer = UIView()
var startAnimate:Bool? = true
var mainContainer = UIView()
var activityIndicatorView = UIActivityIndicatorView()
let viewBackgroundLoading = UIView()

init(viewContainer: UIView, startAnimate: Bool?) {
    self.viewContainer = viewContainer
    self.startAnimate = startAnimate
    setup()
}

func setup() {

    let mainContainer: UIView = UIView(frame: viewContainer.frame)
    mainContainer.center = viewContainer.center
    mainContainer.backgroundColor = UIColor.lightGray
    mainContainer.alpha = 0.5
    mainContainer.tag = 789456123
    mainContainer.isUserInteractionEnabled = true

    let viewBackgroundLoading: UIView = UIView(frame: CGRect(x:0,y: 0,width: 80,height: 80))
    viewBackgroundLoading.center = viewContainer.center
    viewBackgroundLoading.backgroundColor = UIColor.black
    viewBackgroundLoading.alpha = 0.5
    viewBackgroundLoading.clipsToBounds = true
    viewBackgroundLoading.layer.cornerRadius = 15

    let activityIndicatorView: UIActivityIndicatorView = UIActivityIndicatorView()
    activityIndicatorView.frame = CGRect(x:0.0,y: 0.0,width: 40.0, height: 40.0)
    activityIndicatorView.activityIndicatorViewStyle =
        UIActivityIndicatorViewStyle.whiteLarge
    activityIndicatorView.center = CGPoint(x: viewBackgroundLoading.frame.size.width / 2, y: viewBackgroundLoading.frame.size.height / 2)
}

func start(){
    DispatchQueue.main.async(execute: {
        print("start")
        self.viewBackgroundLoading.addSubview(self.activityIndicatorView)
        self.mainContainer.addSubview(self.viewBackgroundLoading)
        self.viewContainer.addSubview(self.mainContainer)
        self.activityIndicatorView.startAnimating()
    })
}

func stop() {
    DispatchQueue.main.async(execute: {
        print("stop")
        for subview in self.viewContainer.subviews {
            if subview.tag == 789456123{
                subview.removeFromSuperview()
            }
        }
    })
}

}

在func makeRequestPost内部

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

2 个答案:

答案 0 :(得分:1)

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

我做了什么?

1)我创建了一个类: ViewControllerUtils

for (i1 in 1:length(dat.diff))
{
diffy <- diff(as.numeric(dat.diff[,i1]))
dat.diff[,i1] <- c(diffy, NA)
}

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

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))
}

}

答案 1 :(得分:0)

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

请查看https://cocoapods.org/pods/ResultPromises或许您会发现它有用

修改

声明全局函数end然后将它们暴露给整个模块是个坏主意。最终可能会有数千个辅助函数,并且项目的复杂性将呈指数级增长。虽然很少有人仍在保护程序方法(当函数声明这种方式时),但社区在80年代后期从中演变而来。所以我强烈建议你声明类来包装所有与网络相关的函数(NetworkClient / Service / Manager无论如何)

回答你的问题:你可以把你的活动指标作为参数:

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

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