UITableView in iPhone app - how to get number of rows - objective-c

How can i store the number of current rows in a uitable into a variable?
This is my code for the table (that i think might be relevant):
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}

You should really get this from the source of the data, rather than the table view itself, I'd have thought. (It's a bit arse about face as they'd say around here.)
That said, you could use the numberOfRowsInSection: method within the UITableView as you've shown in your example.

Typically you'll have a data source that's backing the UITableView, usually array. In that case you could simply do [myDataSourceArr count].

I want to display a uiAlert if the number of rows goes above 1. But i dont know how to
That's easy, just check if your value in this case is above 0:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
id <NSFetchedResultsSectionInfo> sectionInfo =
[[self.fetchedResultsController sections] objectAtIndex:section];
if([sectionInfor numberOfObjects]>0){
<<Put your code here>>
}
return [sectionInfo numberOfObjects]];
}

Related

TableView doesn't allow for 'section' in dictionary

I want to loop through a list of json items to use in my sectioned tableView. For this I would like to restructure the data to have a section->array setup, where array contains an array of sessions.
First of all, I don't know if this is the preferred way to go, there may be easier ways. I keep getting the error that I am not allowed to use 'section' as an identifier in the dictionary. Moreover, when I use something else than a 'section' the dictionary keeps getting overridden.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSString *day = _json[#"days"][3];
NSString *key;
NSUInteger count = 0;
NSMutableArray *sessionList = [[NSMutableArray alloc] init];
NSArray *timeslotsSorted = [[_json[#"schedule"][day] allKeys]
sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSArray *locationsSorted = [[_json[#"schedule"][day][timeslotsSorted[section]] allKeys]
sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
for (key in locationsSorted) {
NSDictionary *temp = _json[#"schedule"][day][timeslotsSorted[section]][key];
if ([temp isKindOfClass:[NSDictionary class]]) {
[sessionList addObject:temp[#"title"]]; //test array
count++;
}
}
_sessionDict = #{
section: sessionList
};
return count;
}
You are doing all the work to build your data structure in the wrong place. Lets say there are 10 sections in your data. This will call the tableView: numberOfRowsInSection method 10 times which makes this a pretty inefficient place to do much work. You will also have to implement the method that returns the number of sections to show, and the method to display each individual row.
I would build my data structures in the viewWillLoad method and then store it locallaly and reuse it in all the tableView methods.
First, this is what NSInteger is:
typedef int NSInteger;
You must wrap it into an object. Something like:
[NSNumber numberWithInteger:section]
And than add it to your dictionary.
i don't really know that your timeslotsSorted and locationsSorted contain right items, but lets say they do. I would recommend you to have this sorting before - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section and - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; are called.
Lets say, you received JSON, so you have to parse it as you do, and then call [tableView reloadData] or reload visible cells with animations.
and then your tableView data source methods will be called and you will do something like:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [sessionList count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSString* key = [self.sessionList objectAtIndex:section];
return [[self.secions objectForKey:key] count];
}
and don't forget to make strong properties for self.sections and self.sessionList

One section per row in a UITableView

I am trying to create a UITableView that has one row per section to give the look of a message chat table. How would one achieve this? Using
[array count]
In different combinations in the two delegate methods below either return separate sections of the same cell or multiple rows in each section.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [array count];}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;}
That looks like it should do what you want. Then you need to use the section property from the index path instead of the row when picking out an array element in cellForRowAtIndexPath:.
To fix it:
[Array objectAtIndex:indexPath.section];
Use "section" instead of "row".

NSFetchedResultsControllerDelegate and deleteRowsAtIndexPaths: Section issue

In response of a delete operation on a CELL (not a section) of a tableView connected to a NSFetchedResultsController i obtain this error :
'Invalid update: invalid number of
sections. The number of sections
contained in the table view after the
update (1) must be equal to the number
of sections contained in the table
view before the update (2), plus or
minus the number of sections inserted
or deleted (0 inserted, 0 deleted).'
I understand that the problem is related to Section numbers after and before update. It says that i didn't delete sections, but the after-value is different from the before-value.
Ok this's true! but my section depend on row cells, so if i remove the last row cell of a section, the section disappear.
Here how i define Section and Row numbers:
Sections are created to group row by an attribute "date". Thus, if a row has the attribute "date" 10 April 2010 and a second row has 11 April 2010 i have 2 sections containing 1 row.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[self.controller sections]count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.controller sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
And here my definition of commitEditingStyle, where i remove cell from table and delete data from DB (object type "Transactions" is a subclass of NSManagedObjectContext, that define my model).
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
Transactions *trans = (Transactions *)[self.controller objectAtIndexPath:indexPath];
//Delete transaction
[self.context deleteObject:trans];
NSError *error = nil;
[self.context save:&error];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
}
I find where's the problem.
The delegate is defined in a controller called from a UITabBar. Every time its view appears, a function is called to Fetch data on NSFEtchedResultController(with performFetch) and setup the delegate for the NSFetchedResultControllerDelegate. This way (i don't know exactly why) every time i try to delete or insert cell/section on table, the delegate seems to be duplicated as many time as i opened the controller via UITabBar, thus Delegate function are repeated more than one time creating problem and errors that i described in the question.
To avoid this problem, now i setup Request and Delegate in init function of ViewController and in no other places. This ensure that it set only one reference to delegate and only one Fetch is performed over NSFetchResultController.

Obj-C, have a number of tableviews, need to quickly add code to say not data found?

I have a number of views with UITableViews and I'd like to quickly add code to each so that I can add a row with a simple label saying that there was no data to be shown.
Whats making things a little bit more complicated is that in some cases I'm using custom cells.
I don't want to have to change my populate data array functions, but I can't think of a way to add this feature to a lot of tables quickly.
Can anyone show me what to do ?
In the tableView:numberOfRowsInSection: data source method, get the number of rows as normal. Then, if the number is 0, return 1 instead. In the tableView:cellForRowAtIndexPath: method, perform the same test. If there is no data, use a different cell and set it up for your message.
The following example assumes that you have 1 section and that your data is an NSArray instance variable named theArray which contains strings.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger num = theArray.count;
return (num ? num : 1);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
if(theArray.count == 0) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
cell.textLabel.text = #"No Data Found";
return cell;
}
// Normal processing here
}

How do I only update specific columns in an NSTableView

I have an NSTableView, with two columns. Whenever I add data to the table, both columns display the same data. How do I only update a specific column?
I'm doing Mac Dev btw.
This is the code I'm using:
- (id)tableView:(NSTableView *)streamView objectValueForTableColumn:(NSTableColumn *)messageCol row:(int)row
{
return [[stream respond] objectAtIndex:row];
}
Thanks.
Check which column you're being asked to fill in in your implementation of tableView:objectValueForTableColumn:row:. That's why it passes you the column! Quick example, since you seem to be ignoring the "check what column you're being asked to fill in" part:
- (id)tableView:(NSTableView *)tableView
objectValueForTableColumn:(NSTableColumn *)column
row:(int)row
{
if ([[column identifier] isEqualToString:#"A"])
return [columnArrayA objectAtIndex:row];
if ([[column identifier] isEqualToString:#"B"])
return [columnArrayB objectAtIndex:row];
return nil;
}