When I deleted xib files for my view controllers, I got this error: "Could not load NIB in bundle...with name 'LibraryViewController'". I referenced this question.
Things I have already done:
Deleted app from simulator
Deleted derived data
Cleaned build folder
Restarted my computer
Attempted to clean the contents of /var/folders. However, I could not delete the folders 8k, gf, and zz inside /var/folders because they are required by Mac OS.
Is there any way I can delete my unused xib files without crashing my app?
Update:
override func viewDidLoad() {
libraryTable.register(UINib(nibName: "categoriesTableViewCell", bundle: nil), forCellReuseIdentifier: "categoriesTableViewCell")
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "categoriesTableViewCell", for: indexPath) as! categoriesTableViewCell
return cell
} else {
let cell = songTableViewCell()
return cell
}
}
Replace the code where you register the cell (you now want created in code rather than the .xib/storyboard), as follows:
libraryTable.register(UITableViewCell.self, forCellReuseIdentifier: "categoriesTableViewCell")
The line you show above registers the nib, so when it's time to create a cell you've told it its in a certain nib file. The replacement line creates a default cell programmatically, which means you need to make any modifications to it using swift code rather than the GUI approach which InterfaceBuilder provides. It is very straightforward.
Related
I can segue from an embedded UIKit tableview to a SwiftUI view, with the necessary data. I select the indexPath.row with a tableView(_didSelectRowAt).
However, the #IBSegueAction takes place before the didSelectRowAt. This makes the detailView lag one selected row: it shows the previously selected row.
I tried to put the didSelectRowAt first, tried to embed them: no chance
I saw in a WWDC video that it should be possible lo select the right row, but can't figure out the right syntax from this short segment (about minute 6:00)
https://developer.apple.com/videos/play/wwdc2019/231/
#IBSegueAction func MeasurementDetail(_ coder: NSCoder) -> UIViewController? {
return UIHostingController(coder: coder, rootView: PointDetailSwiftUIView(pointDetail: measurements[selectedMeasurementRow]))
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedMeasurementRow = indexPath.row
}
How do I solve the problem?
In that WWDC session, Tanu doesn't care when UIKit calls tableView(_:didSelectRowAt:). Instead, her #IBSegueAction asks the table view for the selected row, by using tableView.indexPathForSelectedRow.
Make sure you have a tableView outlet connected to your table view. You already have a tableView outlet if your view controller is a subclass of UITableViewController. Then use tableView.indexPathForSelectedRow:
#IBSegueAction func MeasurementDetail(_ coder: NSCoder) -> UIViewController? {
guard let row = tableView.indexPathForSelectedRow?.row else { return nil }
let detailView = PointDetailSwiftUIView(pointDetail: measurements[row])
return UIHostingController(coder: coder, rootView: detailView)
}
I Use trailingSwipeActionsConfigurationForRowAt in IOS11 but when swipe multiple then app cracked.
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .normal, title: "Delete") { action, view, completionHandler in
print("Deleting!")
completionHandler(false)
}
delete.backgroundColor = UIColor.red
let config = UISwipeActionsConfiguration(actions: [delete])
config.performsFirstActionWithFullSwipe = false
return config
}
and some error
*** Assertion failure in -[UISwipeActionController swipeHandlerDidBeginSwipe:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3694.4.18/SwipeActions/UISwipeActionController.m:268
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'No occurrence for index path (null)'
TL;DR - look if you are doing something with your data (e.g. reloading) between your swipes.
I had similiar issue when I swipe-to-delete one cell (leaving it in edit mode - delete action visible) and then trying to swipe another caused that my app crashed. In my case it was because reloading table data in between those swipes.
Swipe-to-delete gesture calls willBeginEditingRowAtIndexPath and didEndEditingRowAtIndexPath methods on UITableViewDelegate object. In the latter one I called tableView.reloadData(). When I swipe-to-delete other cell I got didEndEditingRowAtIndexPath method called for the first cell (also reloading data) and just after that system called willBeginEditingRowAtIndexPath for the other cell and the data was out of sync and UIKit crashes.
When I removed the code that reloading data in didEndEditingRowAtIndexPath method my app won't crashes anymore :)
You need to implement tableView(_:editActionsForRowAt:).
As a minumum, return empty array, but not nil:
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
return []
}
I just used UIViewController + UITableViewDataSource & UITableViewDelegate combination instead of using UITableViewController for the swiping issue.
I'm using editActionsForRowAtIndexPath with Swift to add a option to my app cells.
My app is a homework list app, where you can set its subject, its category, the date you need it ready for and add a description. Also, there is a option that when you swipe the cell to the left you will be able to set the homework as Done. To show that, I created a label and added it to the cell, that if the homework is pending, the label will be Pending. If it was set as done, it will be Concluded. The thing is that when I'm setting ONE cell as done, it is setting all the other cells, which is not what I want.
The code I'm using to say that I only want THIS cell to be set as done is this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("AtivCell") as? AtivCell {
if !isPending {
pendencia[indexPath.row] = false
saveData()
}
cell.configureCell(materias[indexPath.row], data: datas[indexPath.row], descricao: descricoes[indexPath.row], pendencia: pendencia[indexPath.row], categoria: categorias[indexPath.row])
return cell
} else {
return AtivCell()
}
}
Here is the entire project, I really need help, I don't think I did anything wrong.
I've tried deleting the app from my iPhone (where I'm testing), tried closing Xcode, tried everything, it just does not work!!!
Link: https://github.com/HenriqueDoura/Agenda/tree/master/agenda-app
You should be using dequeueReusableCellWithIdentifier with the forIndexpath parameter, which always returns a cell. The one you've used requires you to test if it's nil and create one, which you are doing in the else clause and then not initialising it.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("AtivCell", forIndexPath: indexPath) as? AtivCell {
cell.configureCell(materias[indexPath.row], data: datas[indexPath.row], descricao: descricoes[indexPath.row], pendencia: pendencia[indexPath.row], categoria: categorias[indexPath.row])
return cell
}
You can use your current function if you want, but you need to declare cell as var, and create it if dequeue returns nil, and then set its values.
Also your !isPending code will not work properly. Within editActionsForRowAtIndexPath, you should be setting pendencia[indexPath.row] = false.
I am using UICollectionViewDataSource & UICollectionViewDelegate in my personal ViewController subclass file. I can now click on the cell in CollectionView and navigate to the child ViewController I want, but the target's viewDidLoad method is always run before the didSelectItemAtIndexPath, so I can't get the selected cell's info before the view comes out, for example to get the label name of the selected cell.
Below is the codes I did for now, line 2 is always comes before line 1, but I need to get line 1 first, any ideas?
in UICollectionView's ViewController with datasource and delegate:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
println("1") //line 1
}
in target's ViewController:
override func viewDidLoad() {
super.viewDidLoad()
println("2") //line 2
}
P.S: push segue is using from main to target.
Use didHighlightItemAtIndexPath instead of didSelectItemAtIndexPath solved my problem.
Use prepareForSender:segue: instead of collectionView:didSelectItemAtIndexPath:. The sender is the cell that was tapped. If you need its index path, you can get it from the collection view using indexPathForCell: (passing the sender as the argument).
I am learning how to use a table based app using Simon NG Swift Programming guide. I typed in the code verbatim and the Xcode environment gets stuck on the let cell = tableView line of code.
Can someone tell me what I am doing wrong?
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var restaurantNames = ["Cafe Deadend", "homei", "teakha", "cafe loius", "petite oyster", "royal oak", "for knee rest",
"jimmy johns", "mickey dee", "daddies big burgers"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return restaurantNames.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as UITableViewCell
// configure the cell
cell.textLabel?.text = restaurantNames[indexPath.row]
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The first error I saw when running your code is this:
2015-02-17 16:28:05.645 delete-me-maps[8008:151860] *** Terminating app due
to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to
dequeue a cell with identifier Cell - must register a nib or a class for the
identifier or connect a prototype cell in a storyboard'
If this is the error you're getting, then you need to add the following to viewDidLoad:
if let myTableView = self.tableView {
self.tableView!.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
Otherwise dequeueReusableCellWithIdentifier does not know what kind of class to use for the cell.
Could you post the error message?
Also, wether the app builds or fails building is not only about the code in your .swift files, it's also about the correct tagging/identifying in your storyboard. Have you made sure you haven't messed up the cell identifiers on your project earlier?
You may simply need to set the prototype cell identifier to "Cell". (Make sure it is exactly the same as in the code).
Go to the storyboard, click on your tableview, click on the attributes.
Give yourself a prototype cell by changing it from 0 to 1.
Click on the prototype cell. Set the 'identifier' attribute to "cell".
I believe that you need to set the Prototype Cell to have the identifier "Cell". You do this by:
Going to Main.storyboard, clicking the cell in the Document Outline, then go to the Attributes Inspector and Type in Cell in the 'Identifier' field.