Language : Swift , REALM, Working with tableview cells to display user entries.
I have a problem where I cannot figure out how to display images in a table view cell where each cell has different number of images coming in and the images itself are optional when the user saves their entry.
here is my problem - When I create a new image view in my stack view as you see in the code, to display the second image in the list, I am getting the error that the index path is out of bounds. Also, I cannot unwrap the journalAspects.inPictures[0].realmToThumbNailImage() because I get an error saying that it is not optional.
How do I go about solving this problem of showing different number of images in different cells with out crashing the app.
I have 3 user entries in my app
1st one has text, date and no images
2nd one has text, date and 1 image
3rd one has text, date and 2 images
here is what I want to see in my table view cell
first cell with just text and date
second cell with text, date and 1 image
third cell with text, date and 2 images
Thank you very much and your input is highly appreciated.
here is my code :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let displayCell = journalAspectTableViewDispay.dequeueReusableCell(withIdentifier: "firstAddCell", for: indexPath) as! FirstAddTableViewCell
if let journalAspects = RealmEntries?[indexPath.row] {
//MARK: Text display
displayCell.journalTextDisplayLabel.text = journalAspects.realmText
let pictureImageView = UIImageView()
pictureImageView.heightAnchor.constraint(equalToConstant: 70).isActive = true
pictureImageView.widthAnchor.constraint(equalToConstant: 70).isActive = truedisplayCell.stackViewForImageShow.addArrangedSubview(pictureImageView)
let secondpictureImageView = UIImageView()
secondpictureImageView.heightAnchor.constraint(equalToConstant: 70).isActive = true
secondpictureImageView.widthAnchor.constraint(equalToConstant: 70).isActive = true
displayCell.stackViewForImageShow.addArrangedSubview(secondpictureImageView)
if journalAspects.inPictures.count == 0 {
return displayCell
} else {
let imagesComingOut = journalAspects.inPictures[0].realmToThumbNailImage()
secondpictureImageView.image = imagesComingOut
let secondimagesComingOut = journalAspects.inPictures[1].realmToThumbNailImage() -- App crashes
pictureImageView.image = secondimagesComingOut -- App crashes
}
}
return displayCell
}
Hi, Thank you for your feedback, It is working, But when I implement it, I am having a strange problem. As I add new entries, the number of rows in the section won't change, and weird things happen. At first as I run and compile the app from the Xcode, everything seems right. Entries with one image has one image, entries with no image has no image and entries with 2 has 2. But as I scroll up and down, suddenly entries with no image gets populated with some image. Even though, I have added a new entry, the number of rows will still return the same. For instance if I have 10 entries at the start by running the compiler on the Xcode, then I add the 11th entry, as I scroll, the table view adds the 11th entry as 10th and knocks out the first entry. No matter how many I add, they just knock one down and add another at the top making the number of rows I see as a constant number since it is compiled. If you have any idea as to why that is happening, Please let me know Thank you again.
Have you checked that inPictures actually contains 2 images? You check that there's greater than 0, but not > 1. That can be the only reason for an out of range error in that line. A safer way would be:
switch journalAspects.inPictures.count {
case 2:
secondpictureImageView.image = journalAspects.inPictures[0].realmToThumbNailImage()
pictureImageView.image = journalAspects.inPictures[1].realmToThumbNailImage()
case 1:
pictureImageView.image = journalAspects.inPictures[1].realmToThumbNailImage()
// or maybe the other one - hard to tell as you've mixed up sequencing
default: break
}
return displayCell
Related
I am using limit option in tablview using swift.
for example:
If limit value contain "2" only two checkbox will able to select remaining checkbox will not able to select and
If limit value contain "0" all checkbox will able to select
The issue is you are trying to assign nil values to something.You are using ! in your code. It is hard unwrapping.If you use this mark 100% make sure your value is there.If you not sure use optional unwrapping.
Not Use,
let cell: MultiOnlinecell = self.onlinediscountmultiarraytableview.cellForRow(at: index) as! MultiOnlinecell
Use this, It is save you from app crash
let cell: MultiOnlinecell = self.onlinediscountmultiarraytableview.cellForRow(at: index) as? MultiOnlinecell ?? UITableViewCell()
I've created a collectionView in Storyboard and then put the Delegate and DataSource methods in an extension to the ViewController which manages that screen.
The collectionView uses a layoutDelegate to show a four-by-four grid of images. All cells are shown in the grid, so a cell not being visible isn't a problem and they are all instances of the class imageCVC, a subclass of UICollectionViewCell
This all loads without a problem, but I now want to manipulate four random images before passing control to the user. Mindful that the collectionView may not have fully loaded by the end of viewDidLoad, I call the routine that chooses which image to manipulate, changeImages() in the viewDidLayoutSubviews method. The function is as follows:
func changeImages() {
collectionView.layoutIfNeeded()
let maxChanges = 30
var imageIndex = 0
var imageChanges 0
while imageChanges < maxChanges {
imageIndex = Int.random(in: 0..<(collectionView.numberOfItems(inSection: 0)))
if let cell = collectionView.cellForItem(as: IndexPath(row: imageIndex, section: 0)) as? imageCVC {
changeCell(cell)
imagesChanges += 1
}
}
}
(EDIT: Incorporated Sam's suggestion (below), but it still always returns nil!)
Unfortunately, whilst the imageIndex gets set correctly (so the collection knows how many elements it has), the cellForItem call always returns nil. I've forced the layout at the beginning of the function, but it has no effect.
Please could someone let me know what I'm doing wrong? Many thanks in advance.
In the following line:
imageIndex = Int.random(in: 0...(collectionView.numberOfItems(inSection: 0)))
The code starts from 0 and goes all the way to the collection view items count, so if the count is 10, the code goes from 0 to 10 including 10 which is 11 items in total. This is probably what is causing the crash since there are only 10 items and we try to access 11 items.
Just change:
0...(collectionView.numberOfItems(inSection: 0)
To
0..<(collectionView.numberOfItems(inSection: 0)
After further investigation, it appears that the collectionView data is not being loaded until after the viewDidLayoutSubviews - which seems a little contradictory to me, but hey, I'm sure there's a good reason... - and so I have implemented what I consider to be a work-around.
I've taken the call to changeImages() out from the viewDidLayoutSubviews and put it into the completion segment of a DispatchQueue.main..., written in the viewDidLoad, as follows:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: {
self.changeImages()
})
Essentially, I'm giving the system time (0.3 seconds) to complete it's full loading of the subviews, rather than actually placing my code at the correct part of the cycle when I know that the views have been fully loaded. A solution but, I suspect, an inelegant one.
If anyone knows how I should be approaching it, I'd be very interested to hear. Thanks.
I'm working on a spendings tracker app. All the logic is now working, but when I want to display transaction data in a UILable, it displays it as optional("String")
I have looked around the Internet and have tried unwrapping the string in 2 different ways, but I'm not able to fix it.
Adding an ! to the end of the string gives an error Cannot force unwrap value of non-optional type "String"
Here is the code I'm using now that displays optional("String")
Here I set up my struct and array
struct Transaction {
var discr = ""
var amount = 0
}
var transactions = [Transaction]()
This is how I add data to the array
transactions.append(Transaction( discr: String(describing: transDescrInput.text), amount: Int(tempAmount)))
This is how I display the data in a tableview
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = transTable.dequeueReusableCell(withIdentifier: "sCell")
let discrText = transactions[indexPath.row].discr.uppercased()
cell?.textLabel?.text = "€\(transactions[indexPath.row].amount)"
cell?.detailTextLabel?.text = "\(discrText)"
return cell!
}
This is how it shows up in the app
Iphone simulator screenshot
The problem is already where you add data to the array.
Assuming that transDescrInput.text is an optional string,
String(describing: transDescrInput.text)
returns a non-optional string "Optional(text...)" and there is
no sensible way to revert that. You should use optional binding
or other unwrapping mechanisms instead, for example
if let text = transDescrInput.text {
transactions.append(Transaction(discr: text, amount: Int(tempAmount)))
}
or with nil-coalescing:
transactions.append(Transaction(discr: transDescrInput.text ?? "", amount: Int(tempAmount)))
As a rule of thumb, String(describing:) almost never the correct
solution (even if the compiler suggest it as a Fix-it), it only hides
the actual problem.
Right after posting this post I realised I have to unwrap the text before I add it to my array. So I changed the way I save the string:
transactions.append(Transaction( discr: String(describing: transDescrInput.text!), amount: Int(tempAmount)))
I added an ! behind the transDescrInput.text to unwrap it before I save it to my array.
May I suggest do something like this?
let discrText = transactions[indexPath.row].discr.uppercased()
cell?.detailTextLabel?.text = "\(discrText!)"
First of all i wanne apologize for the code that will be used. I'am completely new to programming in general and it probably looks like .... :)
My problem is the following;
I have 1 ViewController (VC1) with 2 embedded container views (both TableViewControllers). Causs of the UI layout i want for my app i couldn't just use 1 TableVieController. Both of these container views have Textfields, labels, pickerviews that needs to be provided with data by the user.
Now i want to save all this data with 1 button from the VC1.
Everything displays without error but when i tap the save button is gives me the following error:
Could not cast value of type AddRaptorTableVCContainerOne' (0x1099ad840) to AddRaptorTableVCContainerTwo' (0x1099ad270).
Thanks in advance!
#IBAction func addRaptorSaveButton(sender: UIBarButtonItem) {
// Reference to childViewController
let childViewOne = childViewControllers.last as! AddRaptorTableVCContainerOne
let childViewTwo = childViewControllers.last as! AddRaptorTableVCContainerTwo
// Reference moc
let manObjCon = self.manObjCon
let addRaptorEntity = NSEntityDescription.entityForName("AddRaptorEntity", inManagedObjectContext: manObjCon!)
// Create instance of data model and initialize
var newRaptor = AddRaptorEntity(entity: addRaptorEntity!, insertIntoManagedObjectContext: manObjCon)
// Map our properties
newRaptor.image = UIImageJPEGRepresentation(self.addImageView.image, 1)
newRaptor.name = childViewOne.nameTextField.text
newRaptor.ringNo = childViewTwo.ringNoInputTextField.text
// Save our context
var error: NSError?
manObjCon!.save(nil)
println(newRaptor)
In two lines, you're saying that childViewControllers.last is two different things. Check whats actually in childViewControllers, using the debugger or by printing, and pick the right thing to cast as AddRaptorTableVCContainerTwo.
I have an array of objects which all have a timeStamp (NSDate) and I am trying to sort them with the closure below.
The problem is that this works well without any optimisation, so with debug builds all is fine and dandy. But in with optimisations I get the following EXC_BAD_ACCESS.
reportCells.sort({ (a: UITableViewCell, b: UITableViewCell) -> Bool in
if let first = a as? GreenelyTableViewCell,
second = b as? GreenelyTableViewCell {
if let firstDate = first.timeStamp,
secondDate = second.timeStamp {
let comparison = firstDate.compare(secondDate)
if comparison == NSComparisonResult.OrderedAscending {
return false
} else {
return true
}
}
}
return false
})
Any workarounds?
The issue is you are sorting the cells. Which is not a proper approach first of all. You should sort your data source array. Because table is managing its cells in memory and when you make an array of cells. It will cause issues in backend even if it seems working. Now coming to your problem,
You are sorting cells and when you get back to the tableview listing methods, it agains fetches the data from data source i mean your array of objects. And tableview don't finds proper arrangements of data. I mean your cells are in 1 , 4, 2, 3 order after your sort while your data is stil in 1,2,3,4 order. This will cause table view to throw exception. More over, cells resulebility will cause also issue. So for your is to sort your data before showing it to cell. And I bet your problem will be resolved.