I have this problem, I have a tableview with 3 different kind of news manage by segmented control. When I scrolled the news stays for example in the fifth new, if I click in the second segment, appears in the position 5 . Is not showing the news from the segment 1(the new one),at row 0 (beginning) , stays in the position I leave when I was scrolling. Why is happening this? what I'm doing wrong?. I'm using one tableview for the 3 different kinds of news and reload the tableview data every time I change the segment.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
NSLog("selectedSegmentIndex: \(self.sectionSegmentedControl.selectedSegmentIndex) - Row: \(indexPath.row)")
let cell:UITableViewCell = self.tableview.dequeueReusableCellWithIdentifier("Cell")!
// Grab the elements using the tag
let labelTitle:UILabel? = cell.viewWithTag(1) as! UILabel?
let labelSection:UILabel? = cell.viewWithTag(2) as! UILabel?
let labelDate:UILabel? = cell.viewWithTag(3) as! UILabel?
let imageView:UIImageView? = cell.viewWithTag(4) as! UIImageView?
// Check which segment to get data from
switch self.sectionSegmentedControl.selectedSegmentIndex {
case 0:
// If segment is 0, take data from cover News
if (indexPath.row <= self.coverNews.count - 1){
//Current new to display
let currentNewToDisplay = self.coverNews[indexPath.row]
//let currentNewToDisplay = self.news[indexPath.row]
// Get the image and assign to the imageView
if let actualImageView = imageView {
// Imageview actually exists
if currentNewToDisplay.imageUrl != "" {
// Image url exists, so download it
let imageUrl:NSURL? = NSURL(string: currentNewToDisplay.imageUrl)
// Download image with SDWebImage library
if let url = imageUrl {
actualImageView.sd_setImageWithURL(url)
}
}
}
// Get the news title and assign to the label
if let actualLabelTitle = labelTitle {
let title = currentNewToDisplay.title
actualLabelTitle.text = title
actualLabelTitle.numberOfLines = 0
actualLabelTitle.minimumScaleFactor = 0.1
}
// Get the news date and assign to the label
if let actualLabelDate = labelDate {
let character = "| "
actualLabelDate.text = character + currentNewToDisplay.date_short
}
// Get the news section and assign to the label
if let actualabelSection = labelSection {
actualabelSection.text = currentNewToDisplay.section
}
}
case 1:
// If segment is 1, take data from toprated News
if (indexPath.row <= self.topratedNews.count - 1){
let currentNewToDisplay2 = self.topratedNews[indexPath.row]
// Get the image and assign to the imageView
if let actualImageView2 = imageView {
// Imageview actually exists
if currentNewToDisplay2.imageUrl != "" {
// Image url exists, so download it
let imageUrl2:NSURL? = NSURL(string: currentNewToDisplay2.imageUrl)
// Download image with SDWebImage library
if let url2 = imageUrl2 {
actualImageView2.sd_setImageWithURL(url2)
}
}
}
// Get the news title and assign to the label
if let actualLabelTitle2 = labelTitle {
actualLabelTitle2.text = currentNewToDisplay2.title
actualLabelTitle2.numberOfLines = 0
actualLabelTitle2.minimumScaleFactor = 0.1
}
// Get the news date and assign to the label
if let actualLabelDate2 = labelDate {
let character2 = "| "
actualLabelDate2.text = character2 + currentNewToDisplay2.date_short
}
// Get the news section and assign to the label
if let actualabelSection2 = labelSection {
actualabelSection2.text = currentNewToDisplay2.section
}
}
case 2:
if (indexPath.row <= self.latestNews.count - 1){
// If segment is 2, take data from latestNews News
let currentNewToDisplay3 = self.latestNews[indexPath.row]
// Get the image and assign to the imageView
if let actualImageView3 = imageView {
// Imageview actually exists
if currentNewToDisplay3.imageUrl != "" {
// Image url exists, so download it
let imageUrl3:NSURL? = NSURL(string: currentNewToDisplay3.imageUrl)
// Download image with SDWebImage library
if let url3 = imageUrl3 {
actualImageView3.sd_setImageWithURL(url3)
}
}
}
// Get the news title and assign to the label
if let actualLabelTitle3 = labelTitle {
actualLabelTitle3.text = currentNewToDisplay3.title
actualLabelTitle3.numberOfLines = 0
actualLabelTitle3.minimumScaleFactor = 0.1
}
// Get the news date and assign to the label
if let actualLabelDate3 = labelDate {
let character3 = "| "
actualLabelDate3.text = character3 + currentNewToDisplay3.date_short
}
// Get the news section and assign to the label
if let actualabelSection3 = labelSection {
actualabelSection3.text = currentNewToDisplay3.section
}
}
default:
break
}
// Set insets to zero
cell.layoutMargins = UIEdgeInsetsZero
return cell
}
// MARK: Segmented Control
#IBAction func segmentedChanged(sender: UISegmentedControl) {
switch self.sectionSegmentedControl.selectedSegmentIndex {
case 0:
// If segment is 0, return rows for coverNews array
if (self.coverNews.count == 0) {
loadNews()
}else{
dispatch_async(dispatch_get_main_queue(), {
self.tableview.reloadData()
})
}
case 1:
// If segment is 1, return rows for topratedNews array
if (self.topratedNews.count == 0) {
loadNews()
}else{
dispatch_async(dispatch_get_main_queue(), {
self.tableview.reloadData()
})
}
case 2:
// If segment is 2, return rows for latestNews array
if (self.latestNews.count == 0) {
loadNews()
}else{
dispatch_async(dispatch_get_main_queue(), {
self.tableview.reloadData()
})
}
default:
break
}
}
// MARK: Load News
func loadNews(){
switch(sectionSegmentedControl.selectedSegmentIndex){
case 0:
self.model.getFeedNews("cover")
case 1:
self.model.getFeedNews("toprated")
case 2:
self.model.getFeedNews("latest")
default:
break
}
}
Related
I am attempting to have a table view that lists multiple things and allows a user to go through and select multiple cells with checkboxes. My code works up until a certain point, the problem is that the app crashes with the following error
Fatal error: Unexpectedly found nil while unwrapping an Optional value
whenever I call the following code
swift let currentCell = recommendToFriendTableView.cellForRow(at: selectedRow[i]) as? RecommendToFriendsTableViewCell
Here is the method where we set up the cells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (tableView == self.friendListTableView) {
let cell: FriendListTableViewCell = tableView.dequeueReusableCell(withIdentifier: "FriendListCell") as! FriendListTableViewCell
let rowNumber = (indexPath as NSIndexPath).row
var name = ""
if searchActive {
name = filtered[rowNumber]
}
else {
name = names[rowNumber]
}
cell.friendNameLabel.text = name
cell.friendNameLabel.backgroundColor = tableViewBgColor
cell.friendNameLabel.textColor = textColor
cell.recommendToFriendButton.layer.borderWidth = 1
cell.recommendToFriendButton.layer.borderColor = tableViewBgColor.cgColor
cell.recommendToFriendButton.layer.cornerRadius = 6
cell.recommendToFriendButton.backgroundColor = buttonBgColor
cell.backgroundColor = tableViewBgColor
//set target for buttons
cell.recommendToFriendButton.tag = rowNumber
cell.recommendToFriendButton.addTarget(self, action:#selector(recommendToFriendButtonClicked), for: UIControl.Event.touchUpInside)
return cell
}
else {
let cell: RecommendToFriendsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "RecommendToFriendsCell") as! RecommendToFriendsTableViewCell
let rowNumber = (indexPath as NSIndexPath).row
// set the content view background color
cell.contentView.backgroundColor = tableViewBgColor
// set the text color
cell.nameLabel.textColor = textColor
var dict_friend = NSMutableDictionary()
if searchActive {
dict_friend = filteredFriendsArray[rowNumber]
}
else {
dict_friend = friendsArray[rowNumber]
}
let name = dict_friend["name"] as! String
cell.nameLabel.text = name
let friendUID = dict_friend["uid"] as! String
cell.friendID = friendUID
let imageAddress = dict_friend["photo"] as? String
if imageAddress != "unavailable" && imageAddress != nil && imageAddress != ""{
//Swift forces us to wrap strings as optional to use them in logic
if let imageURL = imageAddress as String? {
//Swift forces us to wrap strings as optional to use them in logic
if let image = imageURL as String? {
//We convert the string into a URL and get the image
let url = URL(string: image)
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if error != nil {
print(error!)
return
}
//We create a new async thread to download and update the image
DispatchQueue.main.async {
//imageView.image = UIImage(data: data!)
cell.photoImageView.image = UIImage(data:data!)
}
}).resume()
}
} else {
cell.photoImageView!.image = UIImage(named: "placeholder-profile-male.png")
}
} else {
cell.photoImageView!.image = UIImage(named: "placeholder-profile-male.png")
}
cell.checkBoxImageView.image = cell.checkBoxImageView.image!.withRenderingMode(.alwaysTemplate)
cell.checkBoxImageView.tintColor = textColor
// Style the profile photo to show in a circle
cell.photoImageView.layer.borderWidth = 0
cell.photoImageView.layer.borderColor = tableViewBgColor.cgColor
// Set cornerRadius = a square UIImageView frame size width / 2
// In our case, UIImageView height = width = 60 points
cell.photoImageView.layer.cornerRadius = 30
cell.photoImageView.clipsToBounds = true
cell.selectionStyle = .none // to prevent cells from being "highlighted"
return cell
}
}
This is the method where we interact with them. The crash happens on a cellForRow call for a cell that is out of view (aka dequeued)
var firstFriendName: String = ""
var numberOfFriends = 0
if let selectedRow = recommendToFriendTableView.indexPathsForSelectedRows {
numberOfFriends = selectedRow.count
for i in 0..<selectedRow.count {
let currentCell = recommendToFriendTableView.cellForRow(at: selectedRow[i]) as! RecommendToFriendsTableViewCell
let friendID = currentCell.friendID
idList.append(",\(friendID)")
}
let firstSelectedCell = recommendToFriendTableView.cellForRow(at: selectedRow[0]) as! RecommendToFriendsTableViewCell
firstFriendName = firstSelectedCell.nameLabel.text!
After about a day of experimenting, I've yet to figure out the actual problem (other than the observation that it appears to be in regards to calling a dequeued cell)
Any help is appreciated.
When this line
let currentCell = recommendToFriendTableView.cellForRow(at: selectedRow[i]) as! RecommendToFriendsTableViewCell
crashes this means you access a non-visble cell so either use
if let currentCell = recommendToFriendTableView.cellForRow(at: selectedRow[i]) as? RecommendToFriendsTableViewCell { }
or better use the dataSource array of the table to get the data that you want to gran wrongly from the cell
Can you guys give me some help to hide the image and name if the message it's from the same user... I want only to show it for the first message...and if that user send more not to show anymore until another Id appear... like whatsapp does it..
currently I m having like this to show u an example
[![enter image description here][1]][1]
var isTheSameUser = false
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let selectedChat = chat[indexPath.row]
let myId = String(describing:UserDefaults.standard.value(forKey: "user_id")!)
let messageUserId = String(describing:selectedChat.owner_id)
if messageUserId == myId {
return myMessageCell(indexPath: indexPath)
}else {
return userMessageCell(indexPath: indexPath)
}
}
func myMessageCell(indexPath :IndexPath) -> UITableViewCell {
let cell = self.mainTableView.dequeueReusableCell(withIdentifier: "MyMessageTableViewCell", for: indexPath) as! MyMessageTableViewCell
let selectedChat = self.chat[indexPath.row]
let myId = String(describing:UserDefaults.standard.value(forKey: "user_id")!)
// Show only for the first message
// photo image
if !isTheSameUser {
cell.profileImageView.isHidden = false
cell.profileNameLabel.isHidden = false
} else {
cell.profileImageView.isHidden = true
cell.profileNameLabel.isHidden = true
}
if let userInfo = getUserMemberOf(userId: messageUserId) {
cell.profileImageView.imageFromURL(urlString: userInfo["photo"] as! String)
} else {
cell.profileImageView.image = #imageLiteral(resourceName: "accountIcon")
}
cell.profileNameLabel.text = "\(String(describing: cell.userProfileInfo!["name"]!))"
return cell
You need check the previous chat messsage id like for every message
if indexPath.row != 0 {
let prevItem = chat[indexPath.row - 1]
let currentItem = chat[indexPath.row]
if prevItem.owner_id! == currentItem.owner_id! {
// hide label and image
}else {
// show them
}
}
else {
// show them
}
im having a real nightmare with my project where i need to save cell contents to an object, for each object in an array. I cant get this to work by looping through table cells adn array objects and trying to match them all up.
So my next idea was to add didFinishEditing related functions into the cellForRowAt function?
Im not sure this would work either, but this is what i have:
Each row here has a label for the set, a picker for the reps that can be scrolled to a number, and a textfield to put a weight. Then i save each row as an object storing the set, rep and weight.
Issue is when editing this, how can i save these again overwriting the old values? Hence my plan above to use didFinishEditing methods.
My previous plan was the code below, but i cant figure out the annotated part. So i was hoping someone had guidance on how i can approach saying when editing rather than this save button function that doesnt work!
func saveUserExerciseSets() {
if userExercise == nil {
print("CREATING A FRESH SET OF SETS FOR THE NEW EXERCISE")
for cell in self.customSetsTable.visibleCells as! Array<NewExerciseTableViewCell> {
print("SAVING THESE CELLS \(customSetsTable.visibleCells)")
let newUserExerciseSet = UserExerciseSet(context: self.managedObjectContext)
newUserExerciseSet.setPosition = Int64(cell.setNumber.text!)!
newUserExerciseSet.setReps = Int64(cell.repsPicker.selectedRow(inComponent: 0))
newUserExerciseSet.parentExerciseName = self.userExerciseName.text
if self.localeIdentifier == "en_GB" {
let kgWeight = Measurement(value: Double(cell.userExerciseWeight.text!)!, unit: UnitMass.kilograms)
newUserExerciseSet.setWeight = kgWeight as NSObject?
newUserExerciseSet.initialMetricSystem = self.localeIdentifier
} else if self.localeIdentifier == "en_US" {
let lbsWeight = Measurement(value: Double(cell.userExerciseWeight.text!)!, unit: UnitMass.pounds)
newUserExerciseSet.setWeight = lbsWeight as NSObject?
newUserExerciseSet.initialMetricSystem = self.localeIdentifier
}
let fetchRequest: NSFetchRequest<UserExercise> = UserExercise.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "name == %#", self.exerciseNameToAddTo!)
do {
let parentExercise = try self.managedObjectContext.fetch(fetchRequest).first
parentExercise?.addToExercisesets(newUserExerciseSet)
print("SET ADDED TO EXERCISE")
} catch {
print("Fetching Routine Failed")
}
}
} else if self.userExercise != nil {
print("UPDATING EXISTING SETS FOR THE EXISTING EXERCISE")
let cells = self.customSetsTable.visibleCells as! Array<NewExerciseTableViewCell>
for cell in cells {
let exerciseSets = self.userExercise?.exercisesets?.allObjects as! [UserExerciseSet]
let sortedexerciseSets = exerciseSets.sorted { ($0.setPosition < $1.setPosition) }
let cellsSet = sortedexerciseSets //match the sortedexerciseSets set object to the cell index positions
cellsSet.setPosition = Int64(setsCell.setNumber.text!)!
cellsSet.setReps = Int64(setsCell.repsPicker.selectedRow(inComponent: 0))
if self.localeIdentifier == "en_GB" {
let kgWeight = Measurement(value: Double(cell.userExerciseWeight.text!)!, unit: UnitMass.kilograms)
cellsSet.setWeight = kgWeight as NSObject?
} else if self.localeIdentifier == "en_US" {
let lbsWeight = Measurement(value: Double(cell.userExerciseWeight.text!)!, unit: UnitMass.pounds)
cellsSet.setWeight = lbsWeight as NSObject?
}
cellsSet.parentExerciseName = self.userExerciseName.text
}
}
do {
try self.managedObjectContext.save()
print("THE SET HAS BEEN SAVED")
} catch {
fatalError("Failure to save context: \(error)")
}
delegate?.didFinishEditing()
self.dismiss(animated: true, completion: nil)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as? NewExerciseTableViewCell
else {
fatalError("Unexpected Index Path")
}
cell.backgroundColor = UIColor.customBackgroundGraphite()
cell.textLabel?.textColor = UIColor.white
cell.repsPicker.dataSource = self
cell.repsPicker.delegate = self
configure(cell, at: indexPath)
return cell
}
func configure(_ cell: NewExerciseTableViewCell, at indexPath: IndexPath) {
// configuring cells when theres a loaded exercise causes the issues --------------------
if self.userExercise != nil {
print("RESTORING CELLS FOR THE EXISTING EXERCISE")
let unsortedExerciseSets = self.userExercise?.exercisesets?.allObjects as! [UserExerciseSet]
let exerciseSets = unsortedExerciseSets.sorted { ($0.setPosition < $1.setPosition) }
let cellsSet = exerciseSets[indexPath.row]
cell.setNumber.text = String((indexPath.row) + 1)
let indexRow = Int(cellsSet.setReps)
print("INDEX ROW INT IS \(indexRow)")
cell.repsPicker.selectRow(indexRow, inComponent: 0, animated: true) //fix this crashing issue!
let localeIdentifier = Locale(identifier: UserDefaults.standard.object(forKey: "locale") as! String)
let setWeight = cellsSet.setWeight as! Measurement<UnitMass>
let formatter = MassFormatter()
formatter.numberFormatter.locale = localeIdentifier
formatter.numberFormatter.maximumFractionDigits = 2
if localeIdentifier.usesMetricSystem {
let kgWeight = setWeight.converted(to: .kilograms)
let finalKgWeight = formatter.string(fromValue: kgWeight.value, unit: .kilogram)
let NumericKgResult = finalKgWeight.trimmingCharacters(in: CharacterSet(charactersIn: "0123456789.").inverted)
cell.userExerciseWeight.text = NumericKgResult
} else {
let lbsWeight = setWeight.converted(to: .pounds)
let finalLbWeight = formatter.string(fromValue: lbsWeight.value, unit: .pound)
let NumericLbResult = finalLbWeight.trimmingCharacters(in: CharacterSet(charactersIn: "0123456789.").inverted)
cell.userExerciseWeight.text = NumericLbResult
}
} else if self.userExercise == nil {
print("NEW SET CELL ADDED FOR FRESH EXERCISE")
cell.setNumber.text = String((indexPath.row) + 1)
}
}
Try something like this to match the setIds correctly. That's where I think the issue is.
for x in sortedexerciseSets {
if x.setPosition == Int64(setsCell.setNumber.text!)! {
//save
}
}
Proper way to do it would be to have an array of those sets (I guess, since you tagged core-data, they are instances of NSManagedObject?). When user does ANY change in the cell (write new value in the text field or scroll to another value for reps) you need to update the approproate object in your array immediately. Then you could call save on NSManagedObjectContext when you're sure you want to save changes, or just call rollback on the context to cancel all changes.
I am modifying my paid for app to a free with IAP.
Some group types are free and some will need to be paid for.
On the tableView controller, there is a padlock UIImageView that displays each "locked" item if it is a part of a locked group.
When someone buys that group, or all, that padlock is meant to disappear. This padlock is not a part of the code that prevents the user from seeing the details as I have that code somewhere else and it works fine.
Initially, "Padlock" displays accurately. However, If I scroll up and down on the tableView, the padlocks will randomly disappear.
How to prevent this?
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
//
// We need to fetch our reusable cell.
//
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: Resource.SpeciesCell)!
//
// Get all of the components of the cell.
//
let specieImage: UIImageView = cell.viewWithTag(Resource.SpeciesImageTag) as! UIImageView
let specieName: UILabel = cell.viewWithTag(Resource.SpeciesNameTag) as! UILabel
let specieGenus: UILabel = cell.viewWithTag(Resource.SpeciesGenusTag) as! UILabel
let specieFamily: UILabel = cell.viewWithTag(Resource.SpeciesFamilyTag) as! UILabel
// Set our name, family and genus labels from our data.
//
specieName.text = self.species[(indexPath as NSIndexPath).row].specie
specieFamily.text = ""
specieGenus.text = self.species[(indexPath as NSIndexPath).row].speciesSubgroup
// **** Adding Padlock Begins HERE ****
let padLock: UIImageView = cell.viewWithTag(Resource.SpeciesCategoryLabelTag) as! UIImageView
padLock.image = UIImage(named: "PadlockIcon")
padLock.alpha = 0.7
let speciesGroupFreeArray: Array<String>
let speciesGroupVertebratesArray: Array<String>
let speciesGroupInvertebratesArray: Array<String>
speciesGroupFreeArray = ["eels", "Mammals", "Annelids", "Bivalvians", "Cephalopods", "Cool oddities", "Crustacean", "Echinoderms", "Hydrozoans", "Isopods"]
speciesGroupVertebratesArray = ["Fish", "Sharks", "Rays", "Reptilia", "Syngnathiformes"]
speciesGroupInvertebratesArray = ["Corals", "Gastropods"]
let fishesPurchased = UserDefaults.standard.bool (forKey: "ReefLife5Fishes")
let sharksPurchased = UserDefaults.standard.bool (forKey: "ReefLife6Sharks")
let nudisPurchased = UserDefaults.standard.bool (forKey: "ReefLife7Nudis")
let turtlesPurchased = UserDefaults.standard.bool (forKey: "ReefLife8Turtles")
let seahorsesPurchased = UserDefaults.standard.bool (forKey: "ReefLife9Seahorses")
let coralsPurchased = UserDefaults.standard.bool (forKey: "ReefLife4Corals")
let vertebratesPurchased = UserDefaults.standard.bool (forKey: "ReefLife3Vertebrates")
let invertebratesPurchased = UserDefaults.standard.bool (forKey: "ReefLife2Invertebrates")
let fullPurchased = UserDefaults.standard.bool (forKey: "ReefLife1Full")
let categoryName = self.species[(indexPath as NSIndexPath).row].group
if fullPurchased == true {
padLock.isHidden = true
} else if speciesGroupVertebratesArray.contains(categoryName) {
if vertebratesPurchased == true {
padLock.isHidden = true
} else {
if categoryName == "Fish" {
if fishesPurchased == true{
padLock.isHidden = true
} else{
}
} else if (categoryName == "Sharks" || categoryName == "Rays" ) {
if sharksPurchased == true{
padLock.isHidden = true
} else{
}
} else if categoryName == "Syngnathiformes" {
if seahorsesPurchased == true{
padLock.isHidden = true
} else{
}
} else if categoryName == "Reptilia" {
if turtlesPurchased == true{
padLock.isHidden = true
} else{
}
}
}
} else if speciesGroupInvertebratesArray.contains(categoryName) {
if invertebratesPurchased == true {
padLock.isHidden = true
} else {
if categoryName == "Corals" {
if coralsPurchased == true{
padLock.isHidden = true
} else{
}
} else if categoryName == "Gastropods" {
if nudisPurchased == true{
padLock.isHidden = true
} else{
}
}
}
}
if speciesGroupFreeArray.contains(categoryName) {
padLock.isHidden = true
}
// **** Adding Padlock Ends HERE ****
//
// We now need to set our photo. First, we need to fetch the photo based on our specie
// id.
//
let photos = AppDelegate.getRLDatabase().getSpeciePhotos(self.species[(indexPath as NSIndexPath).row].id)
//
// Set the image for our UIImageView.
//
if photos.isEmpty != true
{
specieImage.clipsToBounds = true
specieImage.contentMode = .scaleAspectFill
specieImage.image = UIImage(named: photos[0].name)
// specieImage.image = UIImage(named: photos[0].name)?.resizeTo(specieImage.bounds)
}
else
{
specieImage.image = UIImage(named: Resource.UnknownImage)?.resizeTo(specieImage.bounds)
}
//
// Return our new cell.
//
return cell
}
Please try replace this
if speciesGroupFreeArray.contains(categoryName) {
padLock.isHidden = true
}
to
padLock.isHidden = speciesGroupFreeArray.contains(categoryName)
Your code only ever sets padlock.isHidden = true. If you get a recycled cell where the padlock is already hidden, there's nothing to unhide it.
You need to explicitly set the padlock isHidden state in all cases.
Given your somewhat contorted code for setting the isHidden property, the simplest way to fix your current code would be to set padlock.isHidden = false At the beginning of your cellForRowAt() method. Then, if none of the cases set isHidden to true, it will always be unbidden, even in a case where you are reconfiguring a recycled cell where the padlock was hidden.
EDIT:
This a key take-away for managing table views and collection views in iOS. Always assume that a cell comes to you with all views set to a non-default state. Your code always needs to explicitly set every view to a specific state.
Think of a table view cell as a paper patient info form at a doctor's office where the office recycles the forms, and doesn't erase the info left by the previous patient. You always have to erase the info left by the previous patient. If you don't have an allergy to peanuts, it's not enough to simply not check that box. You have to erase the previous check marks and other info, or the previous patient's info will get mixed up with yours.
That's what's happening with your padlock.isHidden state. You're assuming it starts out in the default state, but it may not.
I have a tableView with three images in each cell which display all the images from my posts class.. So I download all the images then divide them by 3 when they're put in the cell!! So it doesn't show the same image 3 times in each cell when downloaded...
A bit confusing but If I show you my code you might understand how it works better!
But anyway what I'm trying to do now is the same but with the text, so in a cell depending on what's downloaded it will either show the images as normal or if they're text It will show text instead of the image!!
// HERE'S HOW I SORT THE 3 IMAGES WHEN DOWNLOADED (CellForRowAtIndexPath)
if post.dataType == 1
{
for imageView in cell.threeImages {
imageView.image = UIImage(named: "ImagePlaceHolder")
if counter < posts.count{
imageView.hidden = false
let imagePost = posts[counter++].image
imagePost!.getDataInBackgroundWithBlock { (data:NSData?, error:NSError?) -> Void in
if error == nil {
if let imageData = data {
imageView.image = UIImage(data: imageData)
}
}
}
} else {
imageView.hidden = true
}
// AND HERE'S HOW I SORT THEM / DIVIDE THEM BY 3 SO THEY'RE NOT ALL THE SAME FOR EACH ROW.
func roundUp(value: Double) -> Int {
if value == Double(Int(value)) {
return Int(value)
} else if value < 0 {
return Int(value)
} else {
return Int(value) + 1
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return = roundUp(Double(posts.count) / 3.0)
}
Here is what it looks like now on the simulator, after downloading all the images and it is also downloading 1 text column from parse: [![enter image description here][1]][1]
Now after I tried this code here:
//IMAGES
if post.dataType == 1
{
//Images
for imageView in cell.threeImages {
imageView.image = UIImage(named: "ImagePlaceHolder")
if counter < posts.count{
imageView.hidden = false
let imagePost = posts[counter++].image
imagePost!.getDataInBackgroundWithBlock { (data:NSData?, error:NSError?) -> Void in
if error == nil {
if let imageData = data {
imageView.image = UIImage(data: imageData)
//TEXT
for textHide in cell.threeLabels{
textHide.hidden = true
}}}} } else {
imageView.hidden = true
}
I get this result which is nearly there:
[![enter image description here][2]][2]
But what I am actually after is something where the text can be mixed up with the images like so:
[![enter image description here][3]][3]
I have a feeling it could be to do with the DataType code, as it allows either all images or all text...So here the code for my Struct too!
truct PostStruct {
var dataType : Int = 0 // 0 for text, 1 for picture
var date : NSDate
var username : NSString
var text : NSString?
var title : NSString?
var image : PFFile?
var uuid : NSString
var profileImage : PFFile
var caption : NSString?
init (dataTypeInit: Int, dateInit : NSDate, usernameInit: String, textInit: String, titleInit: String, uuidInit: String,profileImageInit: PFFile) {
dataType = dataTypeInit
date = dateInit
username = usernameInit
text = textInit
title = titleInit
uuid = uuidInit
profileImage = profileImageInit
}
init (dataTypeInit: Int, dateInit : NSDate, usernameInit: String, imageInit: PFFile, uuidInit: String, profileImageInit: PFFile, captionInit: String) {
dataType = dataTypeInit
date = dateInit
username = usernameInit
image = imageInit
uuid = uuidInit
profileImage = profileImageInit
caption = captionInit
}
}
var posts : [PostStruct] = []
UPDATE
for imageView in cell.threeImages {
imageView.image = UIImage(named: "ImagePlaceHolder")
for textView in cell.threeLabels {
let rowData = tableData[indexPath.row]
for indexInRow in 0...2
{
if indexInRow > rowData.posts.count
{
textView.hidden = true
imageView.hidden = true
// there are less posts for this row than the current index - so hide both the image and the text
// hide the imageView at position indexInRow
// hide the text view (label) at position indexInRow
}
else
{
let postt = rowData.posts[indexInRow]
// there is a post - check to see if it's text or an image
if postt.dataType == 1
// image type (replace this with an enumerator at some point)
{
postt.image!.getDataInBackgroundWithBlock { (data:NSData?, error:NSError?) -> Void in
if error == nil {
if let imageData = data {
imageView.image = UIImage(data: imageData)
imageView.hidden = false
textView.hidden = true
}
}
}
// display the image in image at position indexInRow
// hide the text view (label) at position indexInRow
}
else
{
imageView.hidden = true
textView.hidden = false
textView.text = postt.text as? String
// hide the imageView at position indexInRow
// display the text view (label) at position indexInRow
}
}
}}
}
Thanks in advance for any help!
I think you're overcomplicating things by using having to keep dividing by three - why not create the data for the tableview already split into rows of three?
You could have the rowData structure like this
struct rowData
{
var posts : [PostStruct] = []
}
and store it in a class-level variable like this
var tableData : [rowData] = []
and then parse the data into that structure when you load it
// create an array of tableData,
// where each element is of type rowData
// which has up to 3 `post` entries
// each of which is either an image or a text post
// the tableView methods are then based on tableData
var indexInRow = 0
for post in posts
{
if indexInRow == 0
{
// create a new rowData object
tableData.append(rowData())
}
tableData[tableData.count - 1].posts.append(post)
// using the modulo operator like this will return the remainder of dividing by 3, so it will always be 0, 1, 2
indexInRow = (indexInRow + 1) % 3
}
and then your tableView methods look something like this
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let rowData = tableData[indexPath.row]
for indexInRow in 0...2
{
if indexInRow > rowData.posts.count
{
// there are less posts for this row than the current index - so hide both the image and the text
// hide the imageView at position indexInRow
// hide the text view (label) at position indexInRow
}
else
{
// there is a post - check to see if it's text or an image
// UPDATE
let post = rowData.posts[indexInRow]
// UPDATE
if post.dataType == 0 // image type (replace this with an enumerator at some point)
{
// display the image in image at position indexInRow
// hide the text view (label) at position indexInRow
}
else
{
// hide the imageView at position indexInRow
// display the text view (label) at position indexInRow
}
}
}
return UITableViewCell()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return tableData.count
}