How to show activity in fast?

in my application I have a username named usernamaeTextfield, passwordtextfield and login. When the login button is used, I check the fields. At this time, I need to show the actindicator, but my var activity pointer is always hidden. This is my code.

@IBOutlet weak var activity: UIActivityIndicatorView! override func viewDidLoad() { self.activity.hidden = true super.viewDidLoad()} @IBAction func login(sender: AnyObject) { activity.hidden = false activity.startAnimating() if (self.username.isEmpty || self.password.isEmpty){ self.showAlert("Asegurese de ingresar un usuario y contraseña!") }else{ var user = user_function() if !user.user_valid(self.username,password: self.password){ self.showAlert("Usuario Invalido") }else{ } } activity.hidden = true activity.stopAnimating() } 

my code is user_valid

 func user_valid(username :String, password : String)->Bool{ var resultados : Array<JSON> = [] userbase64 = self.encode_to_base64(username) passbase64 = self.encode_to_base64(password) var api = channels_function() resultados = api.load_videos("https://api.cxntv.com/api/v1/videos/?type=canales&page_size=100&ordering=-id") if errormessage.isEmpty{ api.save_LiveChannels(resultados) saver_user(userbase64, passbase64: passbase64, username: username, password: password) errormessage = "" return true }else{ errormessage = "" return false} } 

and uploads the video:

 func load_videos(url :String)->Array<JSON>{ var resultados : Array<JSON> = [] var request = Get_Data() self.task_completed = false request.remoteUrl = url request.getData({data, error -> Void in println("los datos") //println(data) if (data != nil){ // Fix possible error if no "results" key if let results = data["results"].array { resultados = results self.task_completed = true } println("Data reloaded") } else { println("api.getData failed") self.task_completed = true } }) while(!self.task_completed){} return resultados } 

and get the data:

 var remoteUrl = "" func getData(completionHandler: ((JSON!, NSError!) -> Void)!) -> Void { let url: NSURL = NSURL(string: remoteUrl)! let request: NSMutableURLRequest = NSMutableURLRequest(URL: url) let session = NSURLSession.sharedSession() println(request.HTTPBody) request.addValue(userbase64 ,forHTTPHeaderField: "X_CXN_USER") request.addValue( passbase64,forHTTPHeaderField: "X_CXN_PASS") let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in if (error != nil) { return completionHandler(nil, error) } var error: NSError? let json = JSON(data : data) if (error != nil){ return completionHandler(nil, error) } else { if let results = json["detail"].string { errormessage = results return completionHandler(nil, error) } else { return completionHandler(json, nil) } } }) task.resume() } 
0
source share
5 answers

The problem is loadVideos , in which you made a very good asynchronous method and made it synchronous (block user interface updates) and made it rather inefficient with the while . Instead, make loadVideos asynchronous:

 func loadVideos(url:String, completionHandler: (Array<JSON>?) -> ()) { var request = Get_Data() request.remoteUrl = url request.getData {data, error in println("los datos") //println(data) if (data != nil){ // Fix possible error if no "results" key if let results = data["results"].array { completionHandler(results) } println("Data reloaded") } else { println("api.getData failed") completionHandler(nil) } } } 

And then userValid should use the completion block parameter (using its own lock completion pattern):

 func userValid(username :String, password : String, completionHandler: (Bool) -> ()) { userbase64 = encode_to_base64(username) passbase64 = encode_to_base64(password) var api = channelsFunction() api.loadVideos("https://api.cxntv.com/api/v1/videos/?type=canales&page_size=100&ordering=-id") { results in if results != nil { api.save_LiveChannels(results!) saver_user(userbase64, passbase64: passbase64, username: username, password: password) errormessage = "" completionHandler(true) }else{ completionHandler(false) } } } 

And then login will also call this asynchronously:

 @IBAction func login(sender: AnyObject) { activity.hidden = false activity.startAnimating() if username.isEmpty || password.isEmpty { showAlert("Asegurese de ingresar un usuario y contraseña!") } else { userValid() { success in if !user.user_valid(self.username,password: self.password){ self.showAlert("Usuario Invalido") }else{ } dispatch_async(dispatch_get_main_queue(), { activity.hidden = true activity.stopAnimating() } } } } 

I am sure that I do not have all of your functions and variables, but I hope you can see the pattern: Do not use synchronous methods and use completionHandler parameters with your asynchronous methods.

-

If you want to see my original answer, which I posted before you shared the additional code, see the change history of this answer. But the main approach is outlined above.

0
source

This is because you show and hide it in the same method, preventing the application from updating the screen.

Try to send

 // CODE*** activity.hidden = true activity.stopAnimating() 

asynchronously.

0
source

Your code contains a connection to the server, so that the code between startAnimating and stopAnimating will execute in another thread and that the hidden function will be executed before you notice.

What you need to do is show activityIndicator and hide it inside the connection code after receiving a response from the server. In addition, you must write code to hide the activityIndicator inside the dispatch as follows:

 dispatch_async(dispatch_get_main_queue(), { () -> Void in activity.hidden = true activity.stopAnimating() }) 

an answer might be more helpful if you post the rest of the code.

Edit:

You must remove the hide code from the login function and hide the ActivityIndicator object in load_videos as follows:

 func load_videos(url :String)->Array<JSON>{ ... request.getData({data, error -> Void in println("los datos") dispatch_async(dispatch_get_main_queue(), { () -> Void in activity.hidden = true activity.stopAnimating() }) ... }) return resultados } 
0
source

Your displayed code will never work properly. Since you are in IBAction, you can safely assume that when you call this function, you usually work in the main thread.

I assume that the // CODE*** section takes a lot of time (otherwise the activity indicator will not be needed).

Therefore you are either currently performing

  • in fact, they perform an expensive operation on the main thread and therefore block it → very badly. Since you are in the main / UI loop, there are no updates to the user interface, so the activity indicator is not displayed until the login is completely accurate when you hide the indicator again.
  • or perform the operation asynchronously in the background (recommended). If you do this, you will have to move stopAnimating to this background job.

What you have to do is the following:

 @IBAction func login(sender: AnyObject) { activity.hidden = false activity.startAnimating() dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { // CODE*** dispatch_async(dispatch_get_main_queue(), { activity.hidden = true activity.stopAnimating() }) }) } 

It is important to note that stopping must be done in the main thread.

0
source

you should learn to use dispatch_async

 dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)){ //Code take time here //<#Code#> dispatch_async(dispatch_get_main_queue(){ //update UI //<#Code#> } } 

and remember that the UPDATE UI in the main queue

0
source

Source: https://habr.com/ru/post/1011514/


All Articles