I want to add selected cells of UICollectionView in arrays, section wise in different arrays, means different arrays for each section. The problem is this that number of sections are dynamic. Below is my code.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSString *seatV;
int cs;
NSString *secVal = [arrSeatSel objectAtIndex:indexPath.section];
NSArray *arrSplit = [secVal componentsSeparatedByString:#":"];
seatV = [arrSplit objectAtIndex:1];
cs = [seatV integerValue];
int v;
NSString *cnt = [NSString stringWithFormat:#"%#",[arrTot objectAtIndex:indexPath.section]];
v = [cnt intValue];
NSString *sect = [NSString stringWithFormat:#"%d", indexPath.section];
if(indexPath.item < v)
{
if([sectionInfo count] < cs)
{
itemPaths = [self.collectionView indexPathsForSelectedItems];
sectionInfo = [NSMutableArray arrayWithArray: [self.collectionView indexPathsForSelectedItems]];
[selectedItemsInfo setObject:sectionInfo forKey:sect];
cell=[self.collectionView cellForItemAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"yellow_seat.png"]];
}
else
{
[self.collectionView deselectItemAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row inSection:indexPath.section] animated:YES];
[sectionInfo removeAllObjects];
}
[self.collectionView deselectItemAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row inSection:indexPath.section] animated:YES];
}
NSLog(#"section array:%#", sectionInfo);
NSLog(#"section array1:%#", sectionInfo1);
NSLog(#"selected seats dict:%#", selectedItemsInfo);
}
The array arrSeatSel is getting the number of sections and number of seats that can be choose from each section.
description of arr seatsel:(
"Family:2",
"Gold:3"
)
Here sections are 2 and cells that can be selected are 2. Similarly for other sections and in all cases.
arrTot is getting the total number of cells in each section
description of arrTot(
10,
10
)
array arrLevels are number of sections. and array itemPaths is adding the selected cells, and here the problem is, whichever section is it is adding selected cells, but each section has it's own limit of selecting cells. Hope you got my point, if anything clear ask freely.
In short i tell you what is happening here is there is seat map for different levels level 1, 2, etc. and for each level you can select limited seats, then those selected seats for different levels are required to add in different arrays.
Use a dictionary to store the details. section number becomes the keys and store an array of selected items corresponding to each keys
Here is outline
NSDictionary
Key:section0 value: array of selected items in section0
Key:section1 value: array of selected items in section1
Code
//Create a dictionary first
NSMutableDictionary *selectedItemsInfo = [NSMutableDictionary new];
// During selection
NSMutableArray *sectionInfo = [selectedItemsInfo objectForKey:indexPath.section];
if (sectionInfo == nil) {
NSMutableArray *array = [NSMutableArray array]
[array addObject: ] // add selected item
[selectedItemsInfo setObject:array forKey:indexPath.section];
}
else
{
[sectionInfo addObject: ] // add selected item
}
Edit (Imp code from discussion)
// Follow the below pattern
NSMutableArray *sectionInfo = [selectedItemsInfo objectForKey: [NSNumber numberWithInt:indexPath.section]];
if (sectionInfo == nil) {
NSMutableArray *array = [NSMutableArray array];
[array addObject: indexPath]; // add selected item
[selectedItemsInfo setObject:array forKey:[NSNumber numberWithInt:indexPath.section]];
}
else
{
// check the count
if([sectionInfo count] < cs)
{
[sectionInfo addObject: indexPath]; // add selected item
}
else
{
// No need to add the item. Deselect the cell
}
}
// To remove an item
sectionInfo = [selectedItemsInfo objectForKey: [NSNumber numberWithInt:indexPath.section]];
[sectionInfo removeObject:indexPath]
Related
I'm working on information retrieval where in the latest information in on top of UITableView. The code goes like this.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
LoanModel* loan = _feed.products[indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" ];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:#"Cell"];
}
NSString *myString = [NSString stringWithFormat:#"%#",[loan name]];
NSArray *myWords = [myString componentsSeparatedByString:#","];
NSMutableArray *reversed = [NSMutableArray arrayWithCapacity:[myWords count]];
NSEnumerator *enumerator = [myWords reverseObjectEnumerator];
for (id element in enumerator) {
[reversed addObject:element];
}
NSMutableString *reverseString = [reversed componentsJoinedByString:#","];
cell.textLabel.text = reverseString;
return cell;
}
I'm getting the JSON object which contain two fields cid and name respectively. I'm showing only the name is tableview. But I want to show it in reverse i,e last update should show at first. But above code showing the content in reverse. IF "hello" is the content, then it shows "olleh". Please suggest me how to get the UITableView in reverse list. I'm a newbie to iOS.
If you want to have the reversed order of cells / objects they represent, you have to change
LoanModel* loan = _feed.products[indexPath.row];
to
LoanModel* loan = _feed.products[_feed.products.count - 1 - indexPath.row];
assuming that _feed.products is an NSArray.
The array you are using to display the the data in tableView, you'll need to reverse that and then display the data in tableView
NSArray* reversed = [[myArray reverseObjectEnumerator] allObjects];
you can use this to make your array objects order in reverse.
Try This:
NSArray* reversedArray = [[myWords reverseObjectEnumerator] allObjects];
I'm working on a tableview that displays data about a company. I want to divide the data over 3 sections, to make it look more organized.
The data about a company is retreived from a mysql database and I receive it in one array, which looks like this:
{
companyAdress = "the street 9";
companyCity = "city";
companyFacebook = "facebook.com/companyname";
companyName = "name";
companyPhoneNumber = "0123 456 789";
companyTwitter = "www.twitter.com/companyname";
companyWebsite = "www.companyname.com";
companyZip = "0000 AA";
imageNumber = "3067913";
}
I want the companyName and imageNumber in the first section, the companyAdress, companyZip and companyCity in the second, and all the remaining variables in the third section.
I do not know how to properly do this, and I haven't found a useful answer/solution for this on SO or any other website I know.
How to I do this? any help, sample code and/or tutorial would be much appreciated, thank you in advance!
One approach would be to separate the data when you receive it into a two-dimensional array. So the array's first entry would be an array holding companyName and imageNumber, and so on.
With this implementation, numberOfSectionsInTableView would simply return myArray.count and numberOfRowsInSection would return myArray[section].count.
To access the appropriate values from there, you would do something like ((NSMutableArray*)myArray[indexpath.section])[indexpath.row]
You must use a Array of NSDictionary items,
then you get info for sections and tables rows.
adding a key for each record type.
This is a sample project for explain the use of NSArray and NSDictonary, I hope this help you.
You can download the xcode project from here http://www.germinara.it/download/FGTestTableView.zip and this is the result of the sample http://www.germinara.it/download/FGtesttableview.png
#import <UIKit/UIKit.h>
#interface FGViewController : UIViewController <UITableViewDataSource,UITableViewDelegate> {
NSMutableArray* records;
}
#property(nonatomic,strong) IBOutlet UITableView *tblRecordsList;
-(void) buildDataSource; //Build the datasource for the tableview
#end
#import "FGViewController.h"
#interface FGViewController ()
#end
#implementation FGViewController
#synthesize tblRecordsList;
- (void)viewDidLoad
{
[super viewDidLoad];
records = [[NSMutableArray alloc] init];
//Load data into array used as datasource
[self buildDataSource];
self.tblRecordsList.dataSource=self;
self.tblRecordsList.delegate=self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
//Load sample data
-(void) buildDataSource{
NSMutableDictionary* dict= nil;
[records removeAllObjects];
//Fill data source with your data
//Data to put on first section
dict=[NSMutableDictionary dictionaryWithCapacity:0];
[dict setObject:#"0" forKey:#"idsection"];
[dict setObject:#"company1" forKey:#"companyName"];
[dict setObject:#"picture1" forKey:#"imageNumber"];
[records addObject:dict]; //Add items to array
//Data to put on second section
dict=[NSMutableDictionary dictionaryWithCapacity:0];
[dict setObject:#"1" forKey:#"idsection"];
[dict setObject:#"address1" forKey:#"companyAdress"];
[dict setObject:#"zip1" forKey:#"companyZip"];
[dict setObject:#"city1" forKey:#"companyCity"];
[records addObject:dict]; //Add items to array
//Data to put on other section
dict=[NSMutableDictionary dictionaryWithCapacity:0];
[dict setObject:#"2" forKey:#"idsection"];
[dict setObject:#"facebook1" forKey:#"companyFacebook"];
[dict setObject:#"phone1" forKey:#"companyPhoneNumber"];
[dict setObject:#"twitter1" forKey:#"companyTwitter"];
[dict setObject:#"website1" forKey:#"companyWebsite"];
[records addObject:dict]; //Add items to array
}
//Get Dictionary using section key (idsection)
-(NSDictionary *) dictionaryForSection:(NSInteger) section{
for (NSDictionary *dict in records){
if(section == [[dict valueForKey:#"idsection"] intValue]){
return dict;
}
}
return nil;
}
//Table View Delegate
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell =nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"myCellReuseID"];
NSDictionary * dict = [self dictionaryForSection:indexPath.section]; //Get request dictionary info
//Process data for first section
if(indexPath.section == 0){
if(indexPath.row == 0)
cell.textLabel.text=[dict valueForKey:#"companyName"];
if(indexPath.row == 1)
cell.textLabel.text=[dict valueForKey:#"imageNumber"];
}
//Process data for second section
if(indexPath.section == 1){
if(indexPath.row == 0)
cell.textLabel.text=[dict valueForKey:#"companyAdress"];
if(indexPath.row == 1)
cell.textLabel.text=[dict valueForKey:#"companyZip"];
if(indexPath.row == 2)
cell.textLabel.text=[dict valueForKey:#"companyCity"];
}
//Process data for other section
if(indexPath.section == 2){
if(indexPath.row == 0)
cell.textLabel.text=[dict valueForKey:#"companyFacebook"];
if(indexPath.row == 1)
cell.textLabel.text=[dict valueForKey:#"companyPhoneNumber"];
if(indexPath.row == 2)
cell.textLabel.text=[dict valueForKey:#"companyTwitter"];
if(indexPath.row == 3)
cell.textLabel.text=[dict valueForKey:#"companyWebsite"];
}
return cell;
}
//Number of sections (first,second and other => 3)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
- (NSString *)tableView:(UITableView *)theTableView titleForHeaderInSection:(NSInteger)section
{
NSString * sectionTitle =#"";
switch (section) {
case 0:
sectionTitle = #"title first section";
break;
case 1:
sectionTitle = #"title second section";
break;
case 2:
sectionTitle = #"title other section";
break;
default:
break;
}
return sectionTitle;
}
//Count number of record for sections
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
int nRecords=0;
int idSection =0;
//Count number of items for specified section
for (NSDictionary *dict in records){
idSection = [[dict valueForKey:#"idsection"] intValue];
if(section == idSection){
nRecords = [[dict allKeys] count] -1 ; //All dictionary Keys - 1 (the first key "idsection")
}
}
return nRecords;
}
#end
I have a UITableView populated by a SQLite database. I added Section-based Grouping using the sectionIndexTitlesForTableView delegate method today and now when a Cell is selected, the String for indexPath.row is not the same as the text in the selected Cell.
My Code works like this.
I create an Array that holds the businesses from the SQLite database.
I sort that Array alphabetically.
I create an Array of letters of the Alphabet using only the letters of the Alphabet that businesses in the database begin with.
I use that Array, along with an NSPredicate to provide Grouped Header views which group the businesses by their first letter, alphabetically.
The Selected Row is written to the NSUserDefaults file, and a View Controller is pushed (iPhone), or an Observer is added for that key (iPad).
Unfortunately, since adding the header views, indexPath.row now returns a completely different string to that of the TextLabel of the selected Cell, and so a different Business' information is displayed.
Here are the important blocks of code for the main arrays.
- (void)viewDidLoad
{
// Lots of code...
arrayName = [[NSMutableArray alloc] init];
NameSet = [[NSMutableSet alloc] init];
sortedArray = [arrayName sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
alphabet = [[NSMutableArray alloc] init];
[alphabet addObject:#"{search}"];
for (int i=0; i<[sortedArray count]-1; i++)
{
char alphabetUni = [[sortedArray objectAtIndex:i] characterAtIndex:0];
NSString *uniChar = [NSString stringwithFormat:#"%c", alphabetUni];
if (![alphabet containsObject:uniChar])
{
[alphabet addObject:uniChar];
}
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [alphabet count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger rows = 0;
NSString *alpha = [alphabet objectAtIndex:section];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alpha];
businesses = [sortedArray filteredArrayUsingPredicate:predicate];
if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]){
rows = [self.searchResults count];
}
else {
rows = [businesses count];
}
return rows;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection (NSInteger)section
{
return [alphabet objectAtIndex:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
NSString *alpha = [alphabet objectAtIndex:indexPath.section];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alpha];
businesses = [sortedArray filteredArrayUsingPredicate:predicate];
if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]){
cell.textLabel.text =
[self.searchResults objectAtIndex:indexPath.row];
}
else{
NSString *cellValue = [businesses objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *selected = nil;
if (tableView == self.tableView)
{
selected = [businesses objectAtIndex:indexPath.row];
}
else if (tableView == searchDis.searchResultsTableView)
{
selected = [filteredData objectAtIndex:indexPath.row];
}
[def setObject:selected forKey:#"NameChoiceDetail"];
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
[self performSegueWithIdentifier:#"NameDetailPush" sender:self];
}
}
// Please excuse my horribly written code. I've only been working with Objective-C for 4 months, and Programming for about 8 months. Any suggestions/optimisations will be duly noted.
Your table view uses sections but your implementation of tableView:didSelectRowAtIndexPath: doesn't evaluate the section of the index path. So the code is missing something.
Furthermore, I find that your use of the businesses variable (it's probably an instance variable) very strange. It is assigned a value in tableView:cellForRowAtIndexPath: but not in tableView:didSelectRowAtIndexPath: even though it is used there. So the outcome if the latter depends on what table cell was displayed last and as a consequence it depends on scrolling user interaction. That might be the reason why the outcome looks rather random.
I am creating a static table view (must be compatible with iOS 4 - so I can't use iOS 5's method).
The way I have it is that I have two sections; the first has one cell, and the second has two cells. I made two arrays, one with the title of the only cell in the first section, and the second with both titles for both cells in the second section. So my dictionary looks like this:
(NSDictionary *) {
First = (
Title1 < --- Array (1 item)
);
Second = (
"Title1", < --- Array (2 items)
Title2
);
}
The issue I have is that I need to return number of rows in a section using tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section. So my question is, how do I retrieve the section from the dictionary using NSInteger section? I would also have to do the same thing in tableView:cellForRowAtIndexPath.
Thank you
If you don't understand how dictionaries work, I'd recommend simplifying the problem. Create one array for each section, then inside your delegate methods use a switch() statement to call [array count] for the row count etc. For the section count you could still use the original dictionary with [[dictionary allKeys] count].
EDIT:
I just saw #fzwo recommends the same thing in two comments
Your best bet is an array of arrays, as has been mentioned. To avoid the complexity with dictionaries, create two NSArray ivars for the table data and the section titles.
// in viewDidLoad
tableData = [NSArray arrayWithObjects:
[NSArray arrayWithObjects:
#"Row one title",
#"Row two title",
nil],
[NSArray arrayWithObjects:
#"Row one title",
#"Row two title",
#"Row three title",
nil],
nil];
sectionTitles = [NSArray arrayWithObjects:
#"Section one title",
#"Section two title",
nil];
// in numberOfSections:
return tableData.count;
// in numberOfRowsInSection:
return [[tableData objectAtIndex:section] count];
// in titleForHeaderInSection:
return [sectionTitles objectAtIndex:section];
// in cellForRowAtIndexPath:
...
cell.textLabel.text = [[tableData objectAtIndex:indexPath.section]
objectAtIndex:indexPath.row];
You could use other objects instead of the row titles if you need more data available to your cell.
To get the number of rows in your section you can use the following:
tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSString *key = [[dictionary allKeys] objectAtIndex: section];
return [[dictionary objectForKey:key] count];
}
And to get the cell value:
tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *key = [[dictionary allKeys] objectAtIndex: indexPath.section];
NSArray *values = [dictionary objectForKey:key];
NSString *value = [values objectAtIndex: indexPath.row];
// code to create a cell
return cell;
}
I have used a number of grouped tables tied to core data managed objects, where the sectionNameKeyPath value is used to identify the attribute in the data that should be used to denote sections for the table.
But how do I indicate the "sectionNameKeyPath equivalent" when I have a table that is being use to present an NSMutableArray full of objects that look like this:
#interface SimGrade : NSObject {
NSNumber * scoreValue;
NSString * commentInfo;
NSString * catName;
}
I would like to have sections defined according to the "catName" member of the class.
Consider, for example that my mutablearray has 5 entries where the 5 "catName" values are "Blue", "Blue", "Blue", "Red", and "Red". So I'd want the number of sections in the table for that example to be 2.
So, what I would 'like to do' could be represented by the following pseudo-code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return (The number of unique catNames);
}
Note: My interest in doing this is not so much for displaying separate sections in the table, but rather so that I can more easily calculate the sums of scoreValues for each category.
<<<<< UPDATE >>>>>>>>>
Joshua's help, as documented in his response has been right on. Here are the two new handlers for number of sections and number of rows per section...
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSMutableSet *counter = [[NSMutableSet alloc] init];
[tableOfSimGrades enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
[counter addObject:[object catName]];
}];
NSInteger cnt = [counter count];
[counter release];
NSLog(#">>>>> number of sections is -> %d", cnt);
return cnt;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSMutableDictionary *counter = [[NSMutableDictionary alloc] init];
NSMutableArray *cats = [[NSMutableArray alloc] init];
__block NSNumber *countOfElements;
[tableOfSimGrades enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
// check the dictionary for they key, if it's not there we get nil
countOfElements = [counter objectForKey:[object catName]];
if (countOfElements) {
// NSNumbers can't do math, so we use ints.
int curcount = [countOfElements intValue];
curcount++;
[counter setObject:[NSNumber numberWithInt:curcount] forKey:[object catName]];
NSLog(#">>>> adding object %d to dict for cat: %#", curcount, [object catName]);
} else {
[counter setObject:[NSNumber numberWithInt:1] forKey:[object catName]];
[cats addObject:[object catName]];
NSLog(#">>>>> adding initial object to dict for cat: %#", [object catName]);
}
}];
countOfElements = [counter objectForKey:[cats objectAtIndex: section]];
int catcount = [countOfElements intValue];
[counter release];
[cats release];
return catcount;
}
My current issue with this routine now lies in the following function... It is ignorant of any sections in the nsmutableArray and so for each section, it starts at index 0 of the array instead of at the 0th element of the appropriate section.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
SimGrade *tmpGrade = [[SimGrade alloc] init];
tmpGrade = [tableOfSimGrades objectAtIndex: indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Category: %#", tmpGrade.catName];
// [tmpGrade release];
return cell;
}
How do I transform the "indexpath" sent to this routine into the appropriate section of the mutableArray?
Thanks,
Phil
You could do something like this:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSMutableSet *counter = [[NSMutableSet alloc] init];
[arrayOfSims enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
[counter addObject:object.catName];
}];
NSInteger cnt = [counter count];
[counter release];
return cnt;
}
you'd probably want to memoize that, for performance reasons (but only after profiling it).
--- EDIT ---
You can use an NSMutableDictionary, too, to get counts of individual categories.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSMutableDictionary *counter = [[NSMutableDictionary alloc] init];
__block NSNumber *countOfElements;
[arrayOfSims enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
// check the dictionary for they key, if it's not there we get nil
countOfElements = [counter objectForKey:object.catName];
if (countOfElements) {
// NSNumbers can't do math, so we use ints.
int curcount = [countOfElements intValue];
curcount++;
[counter setObject:[NSNumber numberWithInt:curcount] forKey:object.catName];
} else {
[counter setObject:[NSNumber numberWithInt:1] forKey:object.catName];
}
}];
NSInteger cnt = [counter count];
// we can also get information about each category name, if we choose
[counter release];
return cnt;
}