How do i get numberOfRowsInSection from nested NSMutableDictionary? - ios

I am trying to follow this post http://www.appcoda.com/ios-programming-index-list-uitableview/ to create sections using UITableViewController.
I am using two NSMutableDictionaries first(_curatedItemDictionary) dictionary is to store key value pairs from Parse and second (_sectionsDictionary) is to store these in dictionary as key and values as Category type.
[_sectionsDictionary setObject:[obj objectForKey:#"Category"] forKey:_curatedItemDictionary];
I did this because i couldn't store the key as category and value as dictionary as dictionaries will not support duplicate keys.
I am getting numberOfSectionsInTableView by using the below code
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
for(NSString *key in [_sectionsDictionary allKeys]) {
[_cleanArray addObject:[_sectionsDictionary objectForKey:key]];
}
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:_cleanArray];
for (id item in set) {
NSInteger count = (unsigned long)[set countForObject:item];
[_rowForIndexArray addObject:[NSNumber numberWithInteger:count]];
}
_cleanSectionArray = [[NSSet setWithArray:_cleanArray] allObjects];
return [_cleanSectionArray count];
}
How do i get numberOfRowsInSection from the above information ? How do i know which items are being iterated for a particular section ?
Here is the code I am using to create curatedItemDictionary from Parse.com data
PFQuery *query = [PFQuery queryWithClassName:[NSString stringWithString:self.classname]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
for (PFObject *obj in objects) {
self.curatedItemDictionary = [[NSMutableDictionary alloc]init];
[_curatedItemDictionary setValue:[obj objectForKey:#"ItemName"] forKey:#"ItemName"];
[_curatedItemDictionary setValue:[obj objectForKey:#"Price"] forKey:#"Price"];
[_sectionsDictionary setObject:[obj objectForKey:#"Category"] forKey:_curatedItemDictionary];
[self.tableView reloadData];
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];

Based on the code provided in the comment to the original post something similar to that, just an alternative:
self.sectionsDictionary = [NSMutableDictionary new];
NSMutableArray *sectionsArray;
for (PFObject *obj in objects) {
sectionsArray = [self.sectionsDictionary objectForKey: [obj objectForKey:#"Category"]];
if (nil == sectionsArray) sectionsArray = [NSMutableArray new];
[sectionsArray addObject: obj]
[self.sectionsDictionary setObject: sectionsArray forKey: [obj objectForKey:#"Category"]];
}
Then in your numberOfSectionsInTableView you can get the amount of sections just by accessing count method on NSMutableDictionary
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [self.sectionsDictionary count];
}
And then if you need number of rows in each particular section:
- (NSInteger) tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
NSArray *keys = [self.sectionsDictionary allKeys];
id aKey = [keys objectAtIndex:section];
NSMutableArray *arr = [self.sectionsDictionary objectForKey:aKey];
return (arr) ? arr.count : 0;
}
But of course you can loop through the keys in your sectionsDictionary when preparing the datasource and put section index with some key, so you do not need to do use the allKeys trick.

Related

Split a single NSMutableArray into two so that I can set each in each of the section in UITableView

I want to use multiple sections feature UITableView. I have a single NSMutableArray which consists of data in dictionary format. In that dictionary there is a key which has values as '0' and '1'.
I want to create two separate NSMutableArray out of that so that I can assign them accordingly in different sections.
For example :
if (indexPath.section==0) {
NSDictionary *Data = [roomList1 objectAtIndex:indexPath.row];
} else {
NSDictionary *Data = [roomList2 objectAtIndex:indexPath.row];
}
Assuming the value in your dictionary is always set you could do something like:
NSMutableArray *firstArray = [NSMutableArray new];
NSMutableArray *secondArray = [NSMutableArray new];
for (NSDictionary *dictionary in yourArray) {
if ([dictionary objectForKey:#"yourValue"] isEqualToString: #"0") {
[firstArray addObject:dictionary];
} else if ([dictionary objectForKey:#"yourValue"]isEqualToString: #"1") {
[secondArray addObject:dictionary];
}
}
You can use this
- (NSDictionary *)groupObjectsInArray:(NSArray *)array byKey:(id <NSCopying> (^)(id item))keyForItemBlock
{
NSMutableDictionary *groupedItems = [NSMutableDictionary new];
for (id item in array) {
id <NSCopying> key = keyForItemBlock(item);
NSParameterAssert(key);
NSMutableArray *arrayForKey = groupedItems[key];
if (arrayForKey == nil) {
arrayForKey = [NSMutableArray new];
groupedItems[key] = arrayForKey;
}
[arrayForKey addObject:item];
}
return groupedItems;
}
Ref: Split NSArray into sub-arrays based on NSDictionary key values
Use like this
NSMutableArray * roomList1 = [[NSMutableArray alloc] init];
NSMutableArray * roomList2 = [[NSMutableArray alloc] init];
for(int i = 0;i< YourWholeArray.count;i++)
{
if([[[YourWholeArray objectAtIndex:i] valueForKey:#"YourKeyValueFor0or1"] isEqualToString "0"])
{
[roomList1 addObject:[YourWholeArray objectAtIndex:i]];
}
else if([[YourWholeArray objectAtIndex:i] valueForKey:#"YourKeyValueFor0or1"] isEqualToString "1"])
{
[roomList2 addObject:[YourWholeArray objectAtIndex:i]];
}
}
NSMutableArray *roomList1 = [[NSMutableArray alloc] init];
NSMutableArray *roomList2 = [[NSMutableArray alloc] init];
for (NSString *key in [myDictionary allKeys]) {
if (myDictionary[key] isEqualToString: #"0") {
[roomList1 addObject: myDictionary[key]];
} else {
[roomList2 addObject: myDictionary[key]];
}
}
try this way :-
NSMutableArray *getdata=[[NSMutableArray alloc]init];
getdata=[results objectForKey:#"0"];
NSMutableArray *getdata2=[[NSMutableArray alloc]init];
getdata2=[results objectForKey:#"1"];
use this two array and populate the section with now of rows at indexpathrow
define number of section 2
if (section==0){
getdata
}
else{
getdata2
}

Make an array equal to another array for specific objects

What I'm trying to do is to make an array equal to another but for specific objects. Like the second array holds a lot of objects and I want the first array to take specific objects from the second array and then return it in NumberOfRowsInSection.
Here is what I tried but it returns nothing:
-(NSInteger) tableView: (UITableView * ) tableView numberOfRowsInSection: (NSINteger) section {
NSArray *array;
NSString * foundString;
NSInteger i;
for (i = 0; i < [LabelFilesArray count]; i++) {
if ([[[LabelFilesArray objectAtIndex: i] objectForKey: #"teamSide"] isEqualToString: #"test2"]) {
array = [LabelFilesArray objectAtIndex: i] ObjectForKey: #"teamSide"]; //Here is my problem.
foundString = #"found";
if ([foundString isEqualToString: #"found"]) {
break;
}
}
}
return array.count; //it returns nothing
}
You need to keep things simple, so select the data you want in your tableview as soon as you get it, and store it in a 3rd array.
This allows you to delete and re-arrange rows and makes your datasource methods simple.
ViewController.m:
#interface ViewController()
{
NSMutableArray *_tableData;
}
- (void)methodThatGetsData
{
// Get data in LabelFilesArray
_tableData = [NSMutableArray new];
for (NSDictionary *dict in LabelFilesArray) {
for (NSString *filter in _filterArray) {
if (dict[#"teamSide"] isEqualToString:filter]) {
[_tableData addObject:dict];
break;
}
}
}
[_tableView reloadData];
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection: (NSINteger)section {
[_tableData count];
}
// etc.
You can use NSPredicate also to filter contents of array.
Example:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K = %#", key, [dict objectForKey:key]];
_filterArray = [LabelFilesArray filteredArrayUsingPredicate:predicate];

Order the Categories (column) as they are stored in Parse backend

I am trying to populate data of restaurants from Parse with the column "Category" data as section heading for the list of items. However the section titles for the items are getting displayed randomly. I want them to be displayed as they are stored in the backend. I tried doing [query orderByAscending:#"Category"]; which sorts the Categories alphabetically and has no change in the results. The below is my current implementation...
-(void) listAllItems {
PFQuery *query = [PFQuery queryWithClassName:[NSString stringWithString:self.restaurantName]];
[query whereKey:#"DinnerLunch" containsString:self.lunchDinnerPreference];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
for (PFObject *obj in objects) {
self.curatedItemDictionary = [[NSMutableDictionary alloc]init];
[_curatedItemDictionary setValue:[obj objectForKey:#"ItemName"] forKey:#"ItemName"];
[_curatedItemDictionary setValue:[obj objectForKey:#"Price"] forKey:#"Price"];
[_curatedItemDictionary setValue:[obj objectForKey:#"Category"] forKey:#"Category"];
[_curatedItemDictionary setValue:#"" forKey:#"ModifiableItems"];
_sectionsArray = [_sectionsDictionary objectForKey: [obj objectForKey:#"Category"]];
if(nil == _sectionsArray){
self.sectionsArray = [[NSMutableArray alloc]init];
}
[_sectionsArray addObject:_curatedItemDictionary];
[_sectionsDictionary setObject: _sectionsArray forKey: [obj objectForKey:#"Category"]];
NSLog(#"categories keys are %#", [self.sectionsDictionary allKeys]);
}
[self.tableView reloadData];
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [_sectionsDictionary count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
NSArray *keys = [self.sectionsDictionary allKeys];
return [keys objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSArray *keys = [self.sectionsDictionary allKeys];
id aKey = [keys objectAtIndex:section];
NSMutableArray *arr = [self.sectionsDictionary objectForKey:aKey];
return (arr) ? arr.count : 0;
}
I fixed it by creating a new NSMutableArray. Actually i read it from this post How can i get Original order of NSDictionary/NSMutableDictionary?
I added this line while iterating through my PFObjects [_categoryMutableArray addObject:[obj objectForKey:#"Category"]]; and then i used the below lines in my titleForHeaderInSection and numberOfRowsInSection
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return [_categoryMutableArray objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// NSArray *keys = [self.sectionsDictionary allKeys];
id aKey = [_categoryMutableArray objectAtIndex:section];
NSMutableArray *arr = [self.sectionsDictionary objectForKey:aKey];
return (arr) ? arr.count : 0;
}

Sort based on LastName - Null exception

In my code i'm sorting contacts using lastname,It shows error with LastName is null.How to sort null lastname into hash symbol.
Here my code
-(void)updateView:(NSArray*)contactsArray{
[self.dataArray removeAllObjects];
[self.sections removeAllObjects];
[self.dataArray addObjectsFromArray:contactsArray];
BOOL found;
for (Contact *contact in self.dataArray)
{
NSString *c = [[contact.lastName substringToIndex:1] uppercaseString];
found = NO;
for (NSString *str in [self.sections allKeys])
{
if ([str isEqualToString:c])
{
found = YES;
}
}
if (!found)
{
[self.sections setValue:[[NSMutableArray alloc] init] forKey:c];
}
}
// Loop again and sort the books into their respective keys
for (Contact *contact in self.dataArray)
{
[[self.sections objectForKey:[[contact.lastName substringToIndex:1] uppercaseString]] addObject:contact];
}
// Sort each section array
for (NSString *key in [self.sections allKeys])
{
[[self.sections objectForKey:key] sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"lastName" ascending:YES]]];
}
NSLog(#"Check %#",contactsArray);
[self.tableView reloadData];
}
Everywhere that you do
[contact.lastName substringToIndex:1];
Is unsafe if you might possibly have an empty string because the substring request will always throw a range exception. You need to change that code.
The simple option is to check the length beforehand and if it's too short substitute some other known value so that all of the empty last names are grouped together.

how to change order of NSMutable array in same way another mutable arrays get changed

I have three arrays. They are name, birthdates and remaining days like below:
name birthdate remaining
"Abhi Shah", "01/14", 300
"Akash Parikh", "12/09/1989", 264
"Anand Kapadiya", "12/01", 256
"Annabella Faith Perez", "03/02", 347
"Aysu Can", "04/14/1992", 25
"Chirag Pandya" "10/07/1987" 201
I want to rearrange the remaining days array into ascending order,
but at the same time name and birthdate should also get reordered in the same way.
See this example below:
name birthdate remaining
"Aysu Can", "04/14/1992", 25
"Chirag Pandya" "10/07/1987" 201
"etc..."
use NSMutableDictionary to store data to NSMutableArray
NSMutableArray *array=[[NSMutableArray alloc]init];
for (int i=0; i<totalRows; i++)
{
NSMutableDictionary *dic=[[NSMutableDictionary alloc]init];
[dic setValue:[array_1 objectAtIndex:i] forKey:#"names"];
[dic setValue:[array_2 objectAtIndex:i] forKey:#"birthdate "];
[dic setValue:[array_3 objectAtIndex:i] forKey:#"remanning"];
[array addObject:dic];
[dic release];
}
here after you arrange name array,use search option to use name not use index and
use NSPredicate search data in NSMutableArray
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"names matches[cd] %#", name];
NSArray *result = [array filteredArrayUsingPredicate:predicate];
NSMutableDictionary *dict = [[[result objectAtIndex:0] mutableCopy] autorelease];
NSLog(#"%#",dict);// result
self.arrayForRows = [[NSMutableArray alloc]init];
NSMutableArray *arrayForNames = [[NSMutableArray alloc]initWithObjects:#"Abhi Shah",#"Akash",#"Nagavendra",#"Ramana",#"Simhachalam", nil];
NSMutableArray *arrayForBirthDates = [[NSMutableArray alloc]initWithObjects:#"01/14/94",#"01/14",#"11/07/87",#"12/07/89",#"23/08/91", nil];
NSMutableArray *arrayForRemaining = [[NSMutableArray alloc]initWithObjects:#"200",#"320",#"32",#"450",#"14", nil];
for (int i=0; i<arrayForBirthDates.count; i++)
{
NSMutableDictionary *tempDicts = [[NSMutableDictionary alloc]init];
[tempDicts setObject:[arrayForNames objectAtIndex:i] forKey:#"names"];
[tempDicts setObject:[arrayForBirthDates objectAtIndex:i] forKey:#"birth"];
[tempDicts setObject:[NSNumber numberWithInt:[[arrayForRemaining objectAtIndex:i] intValue]] forKey:#"remaining"];
[self.arrayForRows addObject:tempDicts];
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"remaining" ascending:YES];
[self.arrayForRows sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
Use this in tableView listing
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.arrayForRows count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifer = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifer];
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifer];
}
cell.textLabel.text = [[self.arrayForRows objectAtIndex:indexPath.row] valueForKey:#"names"];
return cell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
once try like this it'l help you,
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init];
[dict setObject:#"rahul" forKey:#"name"];
[dict setObject:#"10" forKey:#"value"];
NSMutableDictionary *dict1=[[NSMutableDictionary alloc]init];
[dict1 setObject:#"ttt" forKey:#"name"];
[dict1 setObject:#"6" forKey:#"value"];
NSMutableArray *ar=[[NSMutableArray alloc]init];
[ar addObject:dict];
[ar addObject:dict1];
NSSortDescriptor *Sorter = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:NO];
[ar sortUsingDescriptors:[NSArray arrayWithObject:Sorter]];
NSLog(#"---%#",ar);
Put each row into a dictionary, and out those dictionaries into an array. Then sort your away using a predicate or sort block. If you want an array containing just the sorted names for example, you could use [ array valueForKeyPath:#"name" ]
Array looks like:
[
{ #"name" : ...,
#"birthdate" : ...birthdate...,
#"remaining" : ...days remaining... } ,
{...},
{...}
]
such as your MutableArray is a Dictionarys array , you can use sortUsingComparator
to sort the array
[array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
int a = [(NSNumber *)[(NSDictionary *)obj1 objectiveForKey: #"remanning"] intValue];
int b = [(NSNumber *)[(NSDictionary *)obj2 objectiveForKey: #"remanning"] intValue];
if (a < b) {
return NSOrderedAscending;
}
else if(a == b)
{
return NSOrderedSame;
}
return NSOrderedDescending;
}];
For example , I have a test :
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#(30),#(20),#(5),#(100), nil];
[array sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
int a = [(NSNumber *)obj1 intValue];
int b = [(NSNumber *)obj2 intValue];
if (a < b) {
return NSOrderedAscending;
}
else if(a == b)
{
return NSOrderedSame;
}
return NSOrderedDescending;
}];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"%# , %d",obj,idx);
}];
then the output is :

Resources