Answer the question
In order to leave comments, you need to log in
How to update interface on button click (threading issue)?
Hello.
Help me figure out the flows, please.
What you want to implement: when you click on the button, the activity indicator starts, the code executes, the indicator stops. It seems to be simple, but I'm stuck.
@IBAction func button(_ sender: UIButton) {
acrivityIndicator.startAnimating()
//Код со множественными обращениями к серверу (URLSession.shared.dataTask)
acrivityIndicator.stopAnimating()
}
DispatchQueue.main.async {
self.acrivityIndicator.startAnimating()
}
@IBAction func button(_ sender: UIButton) {
DispatchQueue.global().async {
DispatchQueue.main.async {
acrivityIndicator.startAnimating()
}
//Код со множественными обращениями к серверу (URLSession.shared.dataTask)
DispatchQueue.main.async {
acrivityIndicator.stopAnimating()
}
}
}
print(Thread.isMainThread)
print(Thread.current)
true
<NSThread: 0x60000203e280>{number = 1, name = main}
Answer the question
In order to leave comments, you need to log in
Stopping the indicator should be done at the end of the work. Working with URLSession is asynchronous, so you need to stop the indicator in the completion task that you start.
All examples shown by you can be simply thrown out. This is sheer horror.
You can't prevent a user from doing something. At least he should be able to switch between tabs, if any.
If you want to show the user that the download is in progress, then make an overlay that will be shown while the task is running and hidden when it is finished. There are a million examples. First one from google:
https://stackoverflow.com/questions/27960556/loadi...
class ViewController: UIViewController {
@IBOutlet var button: UIButton!
var alert: UIAlertController?
func displayActivityIndicatorAlert() {
alert = UIAlertController(title: "Deleting from black list...", message: nil, preferredStyle: .alert)
let activityIndicator = UIActivityIndicatorView(style: .medium)
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
activityIndicator.isUserInteractionEnabled = false
activityIndicator.startAnimating()
alert!.view.addSubview(activityIndicator)
alert!.view.heightAnchor.constraint(equalToConstant: 95).isActive = true
activityIndicator.centerXAnchor.constraint(equalTo: alert!.view.centerXAnchor, constant: 0).isActive = true
activityIndicator.bottomAnchor.constraint(equalTo: alert!.view.bottomAnchor, constant: -20).isActive = true
present(alert!, animated: true)
}
func dismissActivityIndicatorAlert() {
alert?.dismiss(animated: true)
alert = nil
}
var blackList = [Int](0...9)
let lock = NSLock()
func asyncDeleteBlackList() {
var tasks = [URLSessionTask]()
tasks.reserveCapacity(10)
var results = [Int: String]()
results.reserveCapacity(10)
let group = DispatchGroup()
displayActivityIndicatorAlert()
for item in blackList {
group.enter()
let url = URL(string: "https://.../api/v1/today/batch")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
// Что-то делаем с ошибкой на клиенте...
return
}
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else
{
// Что-то делаем с ошибкой на сервере...
return
}
if let mimeType = httpResponse.mimeType,
mimeType == "application/json",
let data = data,
let string = String(data: data, encoding: .utf8)
{
print("Запрос №\(item) завершён.")
self.lock.lock()
results[item] = string
self.lock.unlock()
group.leave()
}
}
tasks.append(task)
task.resume()
}
group.notify(queue: .main) {
print("\nЗадача завершена.")
self.dismissActivityIndicatorAlert()
}
}
override func viewDidLoad() {
button.addTarget(self, action: #selector(pressed(sender:)), for: .touchUpInside)
}
@objc
func pressed(sender: UIButton) {
asyncDeleteBlackList()
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question