john doe
john doe

Reputation: 23

UITableView reloadData not working when viewcontroller is loaded a 2nd time

I have a UITableView with custom cell displaying a list of files that can be downloaded. The cell displays the filename and download status. Everything working fine except one scenario :

  1. The user downloads a file and navigates back to the home screen while file download in progress...
  2. He comes back to the previous screen. File download still in progress.
  3. File download complete. I am using tableview.reloadData() at this point to refresh the download status to "Download Complete" but reloadData() not working in this scenario. The cell label still shows "Download in progress".

Scrolling the tableview to get the cell out of screen and back refreshes the cell correctly. Anyway to do this programmatically?"

Otherwise, in normal case where user doesn't change screen, reloadData() is working fine.

Any idea how to fix this?

Thanks

I have used alamofire download with progress in the function below which is inside my UIViewController.

func DownloadFile(fileurl: String, indexPath: NSIndexPath, itemPath: String, itemName: String, itemPos: String, ItemSelected:Bool) {

      let cell = myTableView.cellForRowAtIndexPath(indexPath) as! myCustomCell

      let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)


        Alamofire.download(.GET, fileurl, destination: destination)


       .progress {bytesRead, totalBytesRead, totalBytesExpectedToRead in


            // This closure is NOT called on the main queue for performance
            // reasons. To update your ui, dispatch to the main queue.
            dispatch_async(dispatch_get_main_queue()) {
                print("Total bytes read on main queue: \(totalBytesRead) / \(totalBytesExpectedToRead)")


                let progress = Int((Double(totalBytesRead)/Double(totalBytesExpectedToRead)) * 100)


                cell.lblMoreRuqyaFileInfo.text = "Downloading file...(\(progress)%)"


            }
        }
         .response { _, _, _, error in

           if let error = error {
                print("\(error)")
                cell.lblMoreRuqyaFileInfo.text = "Failed to download file. Please try again."
            } else {


            cell.lblMoreRuqyaFileInfo.text = "File Downloaded sucessfully"

          //reloadData() not working from here
            self.myTableView.reloadData()

            }

    }

}

The above func is being called in the tableview's editActionsForRowAtIndexPath below.

func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {

    if myTableView.cellForRowAtIndexPath(indexPath) == nil {
        let action = UITableViewRowAction()
          return [action]

    }

    let cell = myTableView.cellForRowAtIndexPath(indexPath) as! myCustomCell

    let fileurl = cell.textLabel!.text
    let ruqyainfo = cell.lblMoreRuqyaFileInfo.text

    let sItemPath = cell.lblCompiledRuqya.text! + "->" + cell.textLabel!.text! + "->\(indexPath.section)->\(indexPath.row)"
    let sItemName = cell.lblCompiledRuqya.text!
    let sItemPos = "->\(indexPath.section)->\(indexPath.row)"
    var bItemSelected:Bool = false
    if myTableView.cellForRowAtIndexPath(indexPath)?.accessoryType == UITableViewCellAccessoryType.Checkmark {
        bItemSelected = true
    } else {

        bItemSelected = false
    }

     //check if file already downloaded,return empty action, else show Download button
    if ruqyainfo?.containsString("Download") == false {
        let action = UITableViewRowAction()
         return [action]

    }


    let line = AppDelegate.dictCompiledRuqya.mutableArrayValueForKey(AppDelegate.dictCompiledRuqya.allKeys[indexPath.section] as! String)

    let name = line[indexPath.row].componentsSeparatedByString("#")

    let DownloadAction = UITableViewRowAction(style: .Normal, title: "Download\n(\(name[3]))") { (action: UITableViewRowAction!, indexPath) -> Void in

            self.myTableView.editing = false

            AppDelegate.arrDownloadInProgressItem.append(name[0])

            self.DownloadFile(fileurl!, indexPath: indexPath, itemPath: sItemPath, itemName: sItemName,itemPos: sItemPos, ItemSelected: bItemSelected)

        }

    DownloadAction.backgroundColor = UIColor.purpleColor()
    return [DownloadAction]
}

Upvotes: 3

Views: 1882

Answers (5)

Nguyen Hoan
Nguyen Hoan

Reputation: 1693

You used :

let cell = myTableView.cellForRowAtIndexPath(indexPath) as! myCustomCell

and set text for lblMoreRuqyaFileInfo :

cell.lblMoreRuqyaFileInfo.text = "File Downloaded sucessfully"

so, you don't have to call self.myTableView.reloadData()
Try:

dispatch_async(dispatch_get_main_queue()) {
        cell.lblMoreRuqyaFileInfo.text = "File Downloaded sucessfully"
    }

p/s and where did you call functionDownloadFile , show it, plz!

Upvotes: 0

Gil Sand
Gil Sand

Reputation: 6040

It could be a thread related issue (aka you're coming back from the download thread, not on the UI thread, hence the data is refreshed but not displayed).

Try using this on selfand pass it a selector that refreshes your tableview.

performSelectorOnMainThread:

Upvotes: 0

Avinash Jadhav
Avinash Jadhav

Reputation: 501

Hey @John Make sure your TableView datasource is reflected with file upload status permanently.

I think, when you complete file uploading you change status in tableview datasource

1. First scenario as you are switching to second view controller, and coming back to previous view, it might be reinitializing your datasource. Data source might wasn't permanently reflected.
2. In normal scenario, as you are on same view controller(not switching to other). Tableview datasource might be not reinitialized holding updated file upload status.

I suggest to save user file download status saved at some persistant storage or on web server. That doesn't leads to inconsistency in data.

Upvotes: 0

Russell
Russell

Reputation: 5554

you can use delegates so that the download controller can tell the first controller that the download is complete, and that it should redraw the tableView - or at least the indexPath that has just completed.

set up the download controller like this

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
    let destinationController : DownloadController = segue.destinationViewController as! DownloadController
    destinationController.delegate = self

    destinationController.indexRowToRefresh = currentlySelectedIndexRow        
}

and then in the download completion closure, add something like this

   delegate.refreshTableRow(indexRowToRefresh)

and in your first controller, implement the delegate method to refresh this row (or the whole table)

func refreshTableRow(indexRowToRefresh : Int)
{
    var indexPath = NSIndexPath(forRow: indexRowToRefresh, inSection: 0)
    tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Top)
}

Upvotes: 0

Yagnesh Dobariya
Yagnesh Dobariya

Reputation: 2251

//Objective C
    -(void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
       [self.yourTableView reloadData];
    }

//Swift
override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.yourTableView.reloadData()
}

Upvotes: 0

Related Questions