Nicolas Meienberger
Nicolas Meienberger

Reputation: 777

UIButton | setTitle taking huge amount of time even in main thread

I’m reopening this question because my last one wast flagged as duplicate even if it’s actually not ! It’s the same problem but the solutions are not working with my code. I’m using swift 2.

So my problem is, as the title says : I have a UIButton in a tableViewCell and when I use the method « setTitle », it takes from 10 to 60 seconds to update the title. At the same time I’m using « addTarget » and it works instantly. So the title should also update. My button is set as « custom » in my storyboard.

When the view is loading I’m running the following code :

/* viewDidLoad */

override func viewDidLoad() {
    super.viewDidLoad() 
    boolAlready = false 
    findParticipation() 
}

/* findParticipation */

func findParticipation() {
    // After server request response :
    boolAlready = true 
    self.tableView.reloadData() 
}

/* cellForRowAtIndexPath */

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cellActions = tableView.dequeueReusableCellWithIdentifier(informationsCellArray[indexPath.row], forIndexPath: indexPath) as     ! eventDetailsAction

    if boolAlready { 
         cellActions.foundParticipation
    } else { 

        cellActions.btnParticipate.setTitle("...", forState: UIControlState.Normal)
        cellActions.btnParticipate.addTarget(self, action: « deleteParticion", forControlEvents: .TouchUpInside)
} 

/* In my custom cell */

func foundParticipation () {
    self.btnParticipate.setTitle("Annuler", forState: UIControlState.Normal)
    self.btnParticipate.addTarget(self, action: "deleteParticipation", forControlEvents: .TouchUpInside)
}

Different things I found on forums that didn’t worked :

  1. Putting my settitle action around dispatch_async(dispatch_get_main_queue()) {}

  2. Setting title for all differents UIControlStates

  3. Using setAttributedTitle()

  4. Using self.btnParticipate.setNeedsLayout() and self.btnParticipate.layoutIfNeeded() after the setTitle

  5. Disabling the button before and enable it after the setTitle

  6. self.addSubview(self.btnParticipate)

  7. Changing the title in titleLabel.text

  8. Doing everything said previously in the parent viewController using cellActions.btnParticipate

  9. UIView.performWithoutAnimation { self.btnParticipate.setTitle("Annuler", forState: .Normal) }

I’m now stuck and can’t find a solution for that.

Upvotes: 3

Views: 1060

Answers (5)

IMike17
IMike17

Reputation: 81

You can try to refer to this answer https://stackoverflow.com/a/29633647/4478037

Make sure your button is a "custom" button and not a "system" button.

Upvotes: 3

Nicolas Meienberger
Nicolas Meienberger

Reputation: 777

So after 1 week of tries, I decided to stop searching... I'm just calling findParticipation() synchronously and I'm not instantiating my tableView until I get foundParticipation() response.

I know it's way worse for the UX but it's still less time to wait.

Upvotes: 0

user1199624
user1199624

Reputation:

You can use

reloadRowsAtIndexPaths(_:withRowAnimation:)

to force a reload of the cell.

When the title changes that means that your code seems to be correct and its about rendering cycles. This would be one way to to reload the cell.

For reference: Apple Docs - UITableView reloadRowsAtIndexPaths

EDIT:


You have to call this method when some event gets fired, an requests finished etc. to update the cell. I had a second look at your code and it seems that your if-else in cell for row at index path is not doing what it should do. You should NOT call there any "action-performing-methods". Its just for initialization.

Your problem seems to be that your boolean boolAlready is the same for all cells. That will result in a never executing else-block. An therefore the title is not set, or its just set when the bool is set to false. You should probably print the bool there. And/or update your post with more information.

And its not good-readable code when you use nearly identical names like findParticipation and foundParticipation. You should probably refactor that.

Upvotes: 0

Ahmad Ishfaq
Ahmad Ishfaq

Reputation: 914

Your issue is when you are creating the cell the btnParticipate function won't run properly you have to code all those conditions in func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) method

Try this

let cellActions = tableView.dequeueReusableCellWithIdentifier(informationsCellArray[indexPath.row], forIndexPath: indexPath) as     ! eventDetailsAction

         cellActions.removeTarget(nil, action: nil, forControlEvents: .AllEvents)

         if boolAlready {
            cellActions.btnParticipate.setTitle("Annuler", forState: UIControlState.Normal)
            cellActions.btnParticipate.addTarget(self, action: "deleteParticipation", forControlEvents: .TouchUpInside)
         } else {

            cellActions.btnParticipate.setTitle("...", forState: UIControlState.Normal)
            cellActions.btnParticipate.addTarget(self, action: « deleteParticion", forControlEvents: .TouchUpInside)
         }

Upvotes: 0

Alexander Doloz
Alexander Doloz

Reputation: 4188

Try to wrap your setTitle call into performWithoutAnimation:

UIView.performWithoutAnimation {
    self.btnParticipate.setTitle("Annuler", forState: .Normal)
}

Upvotes: 0

Related Questions