I found the problem, It was in the IB... there was not a connection from the column textField to the table view cell.
Post
Replies
Boosts
Views
Activity
I know how I am going to proceed. I will build an array that I will update from the ComboAction and then use this array for the tableView as opposed to try to update the tableView cells directly.
Thanks Claude, I used the @IBAction because I needed the contents of the comboBox and I had tried the delegate before and could not see a way to get contents of comboBox.
Thanks to Claude for getting this working..
I get an error when I added the following statement
NSComboBoxCell.delegate = self
The error was no delegate member for NSComboBoxCell..
So, I created a new test project which had a single view and a tableView that I added a comboBox to one of the columns without trying to use a datasource, I expected to see Item 1, Item 2 .. etc. in the column, but again nothing. Also, the comboBox is editable.
There must be something basic I am missing. Still looking for an example..
I changed func numberOfItemsInComboBoxCell(in comboBoxCell: NSComboBoxCell) - Int {
to
func numberOfItems(in comboBoxCell: NSComboBoxCell) - Int {
and the error went away, however it still does not work. Also, I put a breakpoint on the function " func comboBoxCell" and it does not get called.
Any Ideas how to resolve?
It turns out if I use a NSTextView object instead of NSTextField object the spelling and grammar are built in. So, all I had do to was the following:
create a scrollable text view object and then connect the TextView as follows:
@IBOutlet var itemDescription: NSTextView!
Then turn on continuous spell checking with
itemDescription.isContinuousSpellCheckingEnabled = true
Thanks Claude,
The WWDC video had some other items of interest as well as NSTextCheckingController, however as you said "light overview" but somewhat helpful.
I think I will take you suggestion and talk with apple support as I am mainly interested in NSTextCheckingController since it is the newer API.
You are correct. I had a name mismatched and once I changed this in now works fine!
Yes you are right it works with it commented out. I will investigate further as to why it was failing in this code.
Claude has been very helpful on this issue. Above and beyond!
numberOfColumns is 7 when I print it. I would be ok with you remote-ing into my system. Shoot me an email if you are willing to do this and we could set this up. My email is soule.bob@gmail.com
I changed the code to the following:
cellIdentifier = CellIdentifiers.LastUsedCell
}
if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: cellIdentifier), owner: nil) as? NSTableCellView {
// cell.textField?.stringValue = text
cell.textField?.stringValue = "Test Field"
print(cell.textField?.stringValue)
return cell
With this change it tells me that the issue must be in IB for that column because again the only column that it crashes on is itemUsed.
Do you agree?
After reading your latest post I changed the code. So, here is how the code looks now with the added print statement along with changing owner to self along with print results from console:
} else if currentColumn == fieldIdentifiers.LastUsed {
print("LastUsed", CellIdentifiers.LastUsedCell)
text = dateFormatter.string(from: currentItem.itemLastused!)
cellIdentifier = CellIdentifiers.LastUsedCell
}
if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: cellIdentifier), owner: self) as? NSTableCellView {
// cell.textField?.stringValue = text
cell.textField?.stringValue = "Test Field"
print(cellIdentifier, cell.textField?.stringValue)
return cell
}
temNumberCell Optional("Test Field")
itemLabelCell Optional("Test Field")
itemDescriptionCell Optional("Test Field")
itemAmountCell Optional("Test Field")
itemTaxCell Optional("Test Field")
itemQuantityCell Optional("Test Field")
LastUsed itemUsedCell
itemUsedCell Optional("Test Field")
2020-11-13 07:08:44.938747-0600 PayMe[2031:34187] [General] [<PayMe.Item 0x600001f23500> valueForUndefinedKey:]: this class is not key value coding-compliant for the key itemUsed.
One more thing I just tried. I added a 8th column with new identifiers, change the viewController code to match this new column and it also crashes.
It crashes on the return from NSTableViewDelegate code.
if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: cellIdentifier), owner: nil) as? NSTableCellView {
cell.textField?.stringValue = text
print(cell.textField?.stringValue)
return cell. ---> Crashes on this return for Column 7
}
return nil
}	---> Last Line of Code before crash
Below is the output from the print statement I added. As you can see it crash after Column 7..
Optional("1") ---> Column 1
Optional("adf") ---> Column 2
Optional("test") ---> Column 3
Optional("$450.00") ---> Column 4
Optional("Tax") ---> Column 5
Optional("3") ---> Column 6
Optional("Nov 01 2020") ---> Column 7
2020-11-12 06:32:57.660181-0600 PayMe[13901:179547] [General] [<PayMe.Item 0x600000e30280> valueForUndefinedKey:]: this class is not key value coding-compliant for the key itemUsed.
2020-11-12 06:32:57.667836-0600 PayMe[13901:179547] [General] (
0 CoreFoundation 0x00007fff2049d6af __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007fff201d53c9 objc_exception_throw + 48
2 CoreFoundation 0x00007fff204c5a9a -[NSException raise] + 9
....
To answer your questions..
On which line does the crash occur ?
It crashes on the return from the delegate code
Just to be sure:
the column identifier is for the NSTableColumn object, not NSTableCellView ?
Yes the column identifier for "itemUsed" is for the NSTableColumn
Have you check it is exactly "itemUsed", including capitalisation ?
Yes it is exactly
Could you show also how and where you call createItem()
func populateItemArray (row: Int) {
let currencyFormatter = NumberFormatter()
currencyFormatter.usesGroupingSeparator = true
currencyFormatter.numberStyle = .currency
// localize to your grouping and decimal separator
currencyFormatter.locale = Locale.current
let priceString = currencyFormatter.string(from: NSNumber(value: itemsFetched[row].itemAmount!))
itemsArray.add(Item.createItem(String(itemsFetched[row].itemId!),
itemLabel: itemsFetched[row].itemLabel!,
itemDescription: itemsFetched[row].itemDescription!,
itemAmount: priceString!,
itemTax: itemsFetched[row].itemTax!,
itemQuantity: String(itemsFetched[row].itemQuantity!),
itemLastused: itemsFetched[row].itemLastused!))
return
}
I have 7 columns defined for the tableView in IB Attributes inspector. I changed "itemUsedLast" to "itemUsed" to try and isolate how to fix this. So, itemUsed is the identifier for the column in tableView in IB Identity inspector.
Here is the sections of code dealing with this issue:
extension ItemsViewController: NSTableViewDelegate {
fileprivate enum CellIdentifiers {
static let NumberCell = "itemNumberCell"
static let LabelCell = "itemLabelCell"
static let DescriptionCell = "itemDescriptionCell"
static let AmountCell = "itemAmountCell"
static let TaxCell = "itemTaxCell"
static let QuantityCell = "itemQuantityCell"
static let LastUsedCell = "itemUsedCell"
}
fileprivate enum fieldIdentifiers {
static let Number = "itemNumber"
static let Label = "itemLabel"
static let Description = "itemDescription"
static let Amount = "itemAmount"
static let Tax = "itemTax"
static let Quantity = "itemQuantity"
static let LastUsed = "itemUsed"
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let currentItem = items[row]
var text: String = ""
var cellIdentifier: String = ""
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM dd YYYY"
tableView.backgroundColor = .gray
let currentColumn = tableColumn?.identifier.rawValue
if currentColumn == fieldIdentifiers.Number {
text = currentItem.itemNumber!
cellIdentifier = CellIdentifiers.NumberCell
} else if currentColumn == fieldIdentifiers.Label {
text = currentItem.itemLabel!
cellIdentifier = CellIdentifiers.LabelCell
} else if currentColumn == fieldIdentifiers.Description {
text = currentItem.itemDescription!
cellIdentifier = CellIdentifiers.DescriptionCell
} else if currentColumn == fieldIdentifiers.Amount {
text = currentItem.itemAmount!
cellIdentifier = CellIdentifiers.AmountCell
} else if currentColumn == fieldIdentifiers.Tax {
text = currentItem.itemTax!
cellIdentifier = CellIdentifiers.TaxCell
} else if currentColumn == fieldIdentifiers.Quantity {
text = currentItem.itemQuantity!
cellIdentifier = CellIdentifiers.QuantityCell
} else if currentColumn == fieldIdentifiers.LastUsed {
text = dateFormatter.string(from: currentItem.itemLastused!)
cellIdentifier = CellIdentifiers.LastUsedCell
}
if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: cellIdentifier), owner: nil) as? NSTableCellView {
cell.textField?.stringValue = text
return cell
}
return nil
}
This is the object that I populated from a SQLite table to then use to populate the tableView
class Item: NSObject {
@objc var itemNumber: String? = ""
@objc var itemLabel: String? = ""
@objc var itemDescription: String? = ""
@objc var itemAmount: String? = ""
@objc var itemTax: String? = ""
@objc var itemQuantity: String? = ""
@objc var itemLastused: Date?
@objc class func createItem(_ itemNumber: String, itemLabel: String, itemDescription: String, itemAmount: String, itemTax: String, itemQuantity: String, itemLastused: Date) -> Item {
let item = Item()
item.itemNumber = itemNumber
item.itemLabel = itemLabel
item.itemDescription = itemDescription
item.itemAmount = itemAmount
item.itemTax = itemTax
item.itemQuantity = itemQuantity
item.itemLastused = itemLastused
return item
}
}
The storyboard piece is very straight forward. Just a 7 column tableview and a status label at the bottom. All of the columns of the tableView look the same to me when I look at the various inspectors for each column.
Thanks for your help. Let me know if I can supply any other details.