简体   繁体   中英

Swift 3 UITableViewCell indexPath.row messing up

I have a TableView to show bunch of movies in. movies is the array of Movie objects. movieIDs is the array of movie ids. Ids are just strings.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "movieCell", for: indexPath) as! MovieCell

        // editing the cell here.

        cell.movieNameLabel.text = movies[indexPath.row].movieName
        cell.movieYearLabel.text = movies[indexPath.row].year

        // source of all hell here.

        for id in movieIDs {

            if id == movies[indexPath.row].movieID {

                print(id + " is equal to " + movies[indexPath.row].movieID)
                cell.myButton.setImage(/*there is an image here*/), for: .normal)

            }

        }

The for loop in cellForRowAt method:

for id in movieIDs {

        if id == movies[indexPath.row].movieID {

            print(id + " is equal to " + movies[indexPath.row].movieID)
            cell.myButton.setImage(//there is an image here), for: .normal)
        }

    }

I am comparing all the ids in the movieIDs to the id of the movie at the cell, which is movies[indexPath.row].movieID . If it returns true, i replace the image of the button inside the cell. When i print inside the if statement, it actually doesn't execute but it still replaces button images at random cells. And if i scroll too fast up and down, images of the buttons gets replaced in almost all cells, when its only intended to change for cells that ids match.

The reason that the cells are stuffed up is because they are reusable cells.

So for example, if you have cell #1 set up with an image, when you scroll down and that cell #1 goes off the screen and becomes cell #10 (for instance), it is still showing the image.

The solution is you have to remove the image that was previously set by checking if it doesn't match the movieID , set the image to nil .

You don't have to do the for loop here, instead you use the contains for array. So replace this code:

for id in movieIDs {

    if id == movies[indexPath.row].movieID {

        print(id + " is equal to " + movies[indexPath.row].movieID)
        cell.myButton.setImage(//there is an image here), for: .normal)
    }

}

with this:

if movieIDs.contains(movies[indexPath.row].movieID) {
    cell.myButton.setImage(//there is an image here), for: .normal)
}
else{
    cell.myButton.setImage(nil)
}

You have to set nil if no id matches:

var matched = false
for id in movieIDs {

    if id == movies[indexPath.row].movieID {

        print(id + " is equal to " + movies[indexPath.row].movieID)
        cell.myButton.setImage(//there is an image here), for: .normal)
        matched = true
    }

}

if !matched {
    cell.myButton.setImage(nil)
}

For a better solution, you should create a function to get the image:

if let image = getMovieImageByID(movies[indexPath.row].movieID) {
    cell.myButton.setImage(image), for: .normal)
} else {
    cell.myButton.setImage(nil), for: .normal)
}

func getMovieImageByID(movieID: String) -> UIImage? {
    for id in movieIDs {
        if id == movieID {
            // return the image for the respective movieID
        }
    }

    return nil
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM