James M-Coates
James M-Coates

Reputation: 115

Swift TableView Cell - Show Activity Spinner, Perform Function, Hide Activity Spinner

I am building an application in Swift that shows list of UITableView Cells. When the user taps a cell, I would like the following actions to perform in order:

  1. Deselect the row at the index path
  2. Show and animate the UIActivitySpinner
  3. Perform a function (lasts approximately 10 seconds)
  4. Hide the UIActivitySpinner

My current code is as follows:

     override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

             self.tableView.deselectRowAtIndexPath(indexPath, animated: true)

             let cell = tableView.cellForRowAtIndexPath(indexPath) as! TableViewCell

             cell.ActivitySpinner.startAnimating()

             myFunction() // Approximately 10 seconds.

             cell.ActivitySpinner.stopAnimating()

             return
        }

So the idea is that UIActivitySpinner will appear for 10 seconds while myFunction() executes, and disappear when myFunction() finishes.

enter image description here

The current problem is that the UIActivitySpinner only appears once myFunction() has finished executing. I am unsure how to have the ActivitySpinner appear before myFunction() starts, and disappear once myFunction() has finished.

About myFunction(): it is a C function that is linked in the bridging header and is mostly HTTP requests.

Upvotes: 1

Views: 202

Answers (1)

Alessandro Ornano
Alessandro Ornano

Reputation: 35402

First of all generally it's not a best practise using the first letter of your property in uppercase.

Then this below is not the best solution if you make an asyncronhous thread like a network call.. You can use this function (I dont recommended this):

func dispatchDelay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

.. and do:

cell.ActivitySpinner.startAnimating()
myFunction() // Approximately 10 seconds.
dispatchDelay(10.0) {
     cell.ActivitySpinner.stopAnimating()
}

This is what I suggest to you:

You must add completion handler to your C function like this example:

void myFunction(std::string urlStr, std::function<void(std::string)> callback)
{
  ...
  NSURLSessionDataTask* dataTask = 
    [defaultSession 
      dataTaskWithURL:url 
      completionHandler:
        ^(NSData *data, NSURLResponse *response, NSError *error) {
          if(error == nil)
          {
             NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
             NSLog(@"Data = %@",text);

             // invoke the callback here...
             callback(std::string([text UTF8String]));
          }
        }];
  ...
}

And in C you can use it like:

void callbackFunc(std::string data)
{
  ...
}

myFunction("...", callbackFunc);

What do you need to build now is a cross platform C -> Swift, if you dont know it you can follow these instruction "Building cross platform aint easy": this can permit to you to integrate callback to your swift code to handle the exact myFunction start time and end time.

Upvotes: 2

Related Questions