NSTableView not updating like I think it should - objective-c

I have the following code:
- (void)updateServerList {
[crazyStuff reloadData];
NSLog(#"Hi");
}
- (int)numberOfRowsInTableView:(NSTableView *)tableView
{
NSLog(#"Numbers have Changed");
return [serverBrowser.servers count];
}
- (id)tableView:(NSTableView *)tableView
objectValueForTableColumn:(NSTableColumn *)tableColumn
row:(int)row
{
NSLog(#"Starting updates for table");
NSNetService* server = [serverBrowser.servers objectAtIndex:row];
return [server name];
}
- (IBAction)tableViewSelected:(id)sender
{
//row = [sender selectedRow];
NSLog(#"the user just clicked on row ");
}
This is part of a chat program that I'm trying to expand. It was designed for the iOS and I'm working to get it to work on my laptop and chat with my iPad. I know that updateServerList is called correctly from my log statement. I also now that numberOfRowsInTableView: is called on startup but not anytime else. I would like to have my Table (the outlet crazyStuff) updated everytime updateServerList is called. How would I trouble shoot to see if it is or is not? I am not seeing the data show up in the table that "should" be there

I take it then that at startup, when numberOfRowsInTableView is called, it returns 0? If not, is tableView:objectValueForTableColumn:row: ever called then?
My first guess would be the "crazyStuff" is, in fact, not connected to anything or connected to something other than the table view you intend. Might want to log the value of crazyStuff in updateServerList.

Within updateServerList you should [crazyStuff noteNumberOfRowsChanged]. I thought reloadData causes the table to re-ask its dataSource for the numberOfRowsInTableView:, though...

Related

Two NSTableViews in a single view

I have two NSTableViews in a same view and they have the same data source and delegate.
The two table views are named as varTableView and constraintTableView. Now the number of rows in each is different and I I am finding it difficult to implement the two methods:
-(NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
-(id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
Is there any way to identify the tableviews and return the corresponding number of rows?
My implementation was something like this:
-(NSInteger) numberOfRowsInTableView:(NSTableView *)tableView{
if([tableView.identifier isEqualToString:#"variableTableView"]){
return [self.arrayOfVariableNames count];
}
else{
return [self.arrayOfConstraintNames count];
}
}
it is always returning the count of constraints names but not the variable names
you can implement this either by using name of table or tag of table to know for which table particular delegate method is called for like
-(NSInteger) numberOfRowsInTableView:(NSTableView *)tableView -(id) tableView: (NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row: (NSInteger)row
{
if (tableView == varTableView)// or check table tag, first you need to set tag for table
{
// do something with varTableView
return ([array1 count]);
}
else if (tableView == constraintTableView)
{
// do something with constraintTableView
return ([array2 count]);
}
}
Yes. It's the tableView parameter in the methods you included.
if (tableView == varTableView)
{
// do something with varTableView
}
else if (tableView == constraintTableView)
{
// do something with constraintTableView
}
The number of rows tends to be the number of objects in the array serving as the data source.
As suggested in other answers you can differentiate between two tables by comparing its outlets. There s also another way but you would have to change your existing designs a bit.
Instead of adding two table views in one view controller, create a placeholder view for both of them. Create two table view controllers and add them to these placeholder views as subviews. This way you can have both tables in separate controllers and it will get rid of all the if else blocks which you will end up writing. It might slow you down initially but you will get benefitted later.

*** Illegal NSTableView data source (<NSView: 0x102535290>). Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:

OK, this is driving me crazy, i have an Xcode OSX App that i have been working on. I made some changes recently and i have started getting the following error at compile time:
iModerate Desktop[72478:303] *** Illegal NSTableView data source (<NSView: 0x102535290>).
Must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
I cannot workout where this is coming from, i have implemented both these methods in my appDelegate:
- (NSView *)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
// The return value is typed as (id) because it will return a string in most cases.
id returnValue=nil;
// The column identifier string is the easiest way to identify a table column.
NSString *columnIdentifer = [tableColumn identifier];
// Get the name at the specified row in namesArray
NSString *theName = [[self.twitterClientsController arrangedObjects] objectAtIndex:row];
// Compare each column identifier and set the return value to
// the Person field value appropriate for the column.
if ([columnIdentifer isEqualToString:#"name"]) {
returnValue = theName;
}
return returnValue;
}
and this
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return[[self.twitterClientsController arrangedObjects] count];
}
And app delegate is set as NSTableViewDelegate
Now the extra weird/frustrating thing, is that i have no NSTableView in the xib, i did, but i have deleted them all. I have event opened the XIB in BBedit and searched for NSTableView and there is 100% not one in there!
So, help please! If i could work out what NSView: 0x102535290 is i could maybe track this down.
Help to save my sanity greatly appreciated!
Gareth
it is solved with me that way :
remove the datasource and the delegate connections from the interfaceBuilder.
make an outlet property for the your tableview in the .h file
in the .m file in applicationDidFinishLaunching method set the delegate and datasource manually for your tableview
[self.tableView setDelegate:self];
[self.tableView setDataSource:self];

How to move around searchResultsTableView

I suppose I want to move them to place that I like best. I can set the frame, but where should I set that?
Also how do I ensure that the table still show up irrelevant of whether search result is empty or not?
This is what I have tried:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
controller.searchResultsTableView.frame=self.placeForTableView.frame;
controller.searchResultsTableView.hidden=false;
controller.searchResultsTableView.alpha =1;
[self debugMode:nil];
return true;
}
Result:
When text is searchResultsTableView is still empty
When there is one character, the frame is not moved yet
When there are more than 2 characters, things work as I wish.
Then I added things like this:
- (void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView
{
[self putTableViewWhereItBelongs:tableView];
}
- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
[self putTableViewWhereItBelongs:tableView];
}
-(void)putTableViewWhereItBelongs :(UITableView *) tableView
{
[self.view addSubview:tableView];
tableView.frame=self.placeForTableView.frame;
tableView.hidden=false;
tableView.alpha =1;
}
This works EXACTLY as I wish with one small catch. At the very beginning it doesn't work. At the very beginning the tableView is neither shown or hidden.
Another Update:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
//UISearchDisplayController * controller = [self displayControllerForThisSearchBar:searchBar];
if (IsEmpty(searchBar.text)) {
searchBar.text=#" ";
searchBar.text=#"";
}
//[self putTableViewWhereItBelongs:controller.searchResultsTableView];
}
Problem:
Awkward
A short glitch. I don't want this to be animated. I don't want my user to even know I have this problem. Well it does look a little animated for less than 1 second
Otherwise the final result is exactly as I please.
I wonder if anyone can improve this.

Unable to move rows in a UITableView even when grabber are displaying

I have a somewhat weird issue, and I can't quite figure out what am I missing. I have a UITableView which is editable in place (i.e. when my UI is loaded, I send my table the setEditing:YES animated:YES message). The last row in the table is intended to be the "Add New" row. All rows except the last row in my table can be moved around. None of the rows can be deleted.
The rows show up correctly, and the grabbers shows up on the right side of all rows except the last row (as intended). The problem is that I am unable to move the rows. When I tap on the grabber to move the row, it kind of jiggles in place, but I can't drag it up or down. Here's the relevant snippet of code:
- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleNone;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == [self.itemArray count] ) {
return NO;
}
return YES;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == [self.itemArray count]) {
return NO;
}
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
Item *item = [self.itemArray objectAtIndex:fromIndexPath.row];
[self.itemArray removeObjectAtIndex:fromIndexPath.row];
[self.itemArray insertObject:item atIndex:toIndexPath.row];
}
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
if ([proposedDestinationIndexPath row] < [self.itemArray count]) {
return proposedDestinationIndexPath;
}
NSIndexPath *betterIndexPath = [NSIndexPath indexPathForRow:[self.itemArray count]-1 inSection:0];
return betterIndexPath;
}
On trying to debug, it seems that the tableView:moveRowAtIndexPath: gets called almost immediately even as I am holding on to the grabber (i.e. I have not lifted my finger yet). Moreover, my tableView:targetIndexPathForMoveFromRowAtIndexPath:proposedDestinationIndexPath: does not get invoked at all.
Any thoughts on what am I doing wrong? Any suggestions on what I should try to fix this issue?
I had the same problem, and #wilsontgh & #Andy responses took me in the right direction. However I couldn't afford removing the needed PanRecognizer from the superview, nor disabling it in certain views.
What worked for me was to set this on the main view recognizer, which avoids cancelling touches handled to other views/recognizers.
panRecognizer.cancelsTouchesInView = NO;
I had this problem too. Check if you have a UIGestureRecognizer (for me it was a UIPanGestureRecognizer) that is attached to the UITableView's superviews. I removed it and the reordering worked.
In my case, it is the "hide nav bar on swipe" feature that caused the re-order to fail. Therefore make sure it is turned off if you need the UITableView re-order feature.
navigationController?.hidesBarsOnSwipe = false
Note that navigation controller is shared across all view controllers of the same navigation stack, therefore one screen can affect all other ones even after pushing/pop-ing operations.
I recently had the same problem and this thread pointed me in the right direction, but the better approach is to use the gesture recognizer's delegate method gestureRecognizerShouldBegin: to determine if you are in a situation where you want to process it or not.
In my situation I had a swipe gesture on a main view controller and was displaying a table in a child view controller. In gestureRecognizerShouldBegin: I return a NO when the child view controller is active, which allows the table to see every gesture and the container view controller doesn't handle anything.
The method tableView:moveRowAtIndexPath:toIndexPath: does get called immediately upon touching the control. From the UITableViewDataSource Protocol Reference:
The UITableView object sends this message to the data source when the user presses the reorder control in fromRow.
So this is expected behavior.
I believe the problem is in your tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:. Do you have a specific reason to include this method? Have you tried leaving it out and going with the proposed position?
For example, it seems that ([proposedDestinationIndexPath row] < [self.itemArray count]) will always return true...
In my case, the problem was in the keyboardDismissMode property.

NSTableView WILL NOT RELOAD

Hey guys, so in my newest program I use an NSTableView to display words on the left, and thier definitions on the right. these words and definitions are load from a .plist file, and at application startup the table view loads these words and definitions and displays them just fine. My problem comes in when the user tries to add a word and definition using the text boxes and buttons, the word is actually added to the .plist, meaning the method is running fine, but the table view refuses to display the new line. only until after i quit the program and reopen it does the tableview display the new line. I tested to see if the table view was connected properly by sending it other messages such as selectedRow and dataSource, all came back with responces, and proper responces at that. Currently the class that is used as the dataSource and delegate is a subclass to my main class with all my varibles and dictionaries. (I am big on using as little classes as possible). Lastly I tried inserting noteNumberOfRowsChanged in before reloadData, but still nothing.
I have tested everything and it just seems that the reloadData method is not initiating anything. Like I said, my table view is being sent the message, the new info is actually being added to the dicitinoary adn array, the amount of rows is being updated by the count method, and what proves it even more is that when the program is restarted it displays everything just fine. below is the relevent code, where currentWordList and currentDefitionList are the Array and Dictionary suppying the data to the dataSource, and editLibraryCardList is the NSTableView I am trying to reload.
the dataSource class code:
#interface EditorDataTable : SAT_Vocab_MacController {
IBOutlet NSTableColumn *editLibraryWordColumn;
IBOutlet NSTableColumn *editLibraryDefinitionColumn;
}
- (int)numberOfRowsInTableView:(NSTableView *)tableView;
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row;
#end
#implementation EditorDataTable
- (int)numberOfRowsInTableView:(NSTableView *)tableView {
return ([currentWordList count]);
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row {
if (tableColumn == editLibraryWordColumn) {
return [currentWordList objectAtIndex:row];
}
if (tableColumn == editLibraryDefinitionColumn) {
return [currentDefinitionList valueForKey:[[currentWordList objectAtIndex:row]lowercaseString]];
}
}
#end
method that adds the word to the list:
- (IBAction) editLibraryAddWordToLibrary: (id) sender {
if (self = [super init]) {
currentWordList = [[NSArray alloc] initWithContentsOfFile:userSATWordListPath];
currentDefinitionList = [[NSDictionary alloc] initWithContentsOfFile:userSATDefinitionListPath];
}
[currentWordList addObject:[[editLibraryNewCardWordInput stringValue]capitalizedString]];
[currentDefinitionList setObject:[editLibraryNewCardDefinitionInput stringValue] forKey:[[editLibraryNewCardWordInput stringValue]lowercaseString]];
aWordCounter = [currentWordList indexOfObject:[[editLibraryNewCardWordInput stringValue]capitalizedString]];
[aWordLabel setStringValue: [[NSString alloc] initWithFormat:#"%#", [currentWordList objectAtIndex: aWordCounter]]];
[aDefinitionLabel setStringValue: [[NSString alloc] initWithFormat:#""]];
[currentWordList writeToFile:userSATWordListPath atomically:YES];
[currentDefinitionList writeToFile:userSATDefinitionListPath atomically:YES];
[cardCountdownNumber setStringValue: [[NSString alloc] initWithFormat:#"%i", ([currentWordList count] - (1 + aWordCounter))]];
[editLibraryCardList noteNumberOfRowsChanged];
[editLibraryCardList reloadData];
}
Iv'e been stuck for days and any ideas will help! Thanks.
Zach
Have you tried debugging into your selectRowAtIndexPath method to make sure the reload occurs? (after you call [tableView reloadData] should be able to see this) Are you using UITableViewController?
If you wanted a callback after reload to know when its done, you could try:
[tableView reloadData];
[self performSelector:#selector(selectRowAtIndexPath:) withObject:indexPath afterDelay:0.0];
For those who are curious, i moved my code from the dataSource subclass to the main class, and it worked. i guess you cannot subclass the dataSource. Hope this helps!