我有一个函数可以进行调用并等待来自服务器的响应。我想在请求之前显示活动指示器,并在对此相同功能的回答之后隐藏它。为什么?避免代码重复。我会在其他操作中调用服务器。
它的工作方式就是现在:在登录按钮上手动调用开始和停止动画。
为了测试指标,我在服务器上添加了睡眠。
问题:如何显示/隐藏每次调用服务器的指示符?
登录视图上的按钮:
@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()
}
修改
我创建了一个CustomActivityIndicator类,但是没有显示加载器。开始和停止打印在控制台上。
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
答案 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?) -> ())
因此,您可以启动它并在您的函数内完成它,而不是在您使用函数时复制/粘贴代码。