dictionaryOfWebsites = [[NSMutableDictionary alloc] init];
[dictionaryOfWebsites setObject:#"http://www.site1.com" forKey:#"Site1"];
[dictionaryOfWebsites setObject:#"http://www.site2.com" forKey:#"Site2"];
[dictionaryOfWebsites setObject:#"http://www.site3.com" forKey:#"Site3"];
[dictionaryOfWebsites setObject:#"http://www.site4.com" forKey:#"Site4"];
Above is my dictionary. I want to have a tableview where the text in the UITableViewCell will say "Site1" and the subtext will have the URL.
I know this will get me all the keys
NSArray *keys = [dictionaryOfWebsites allKeys];
// values in foreach loop
for (NSString *key in keys) {
NSLog(#"%# is %#",key, [dict objectForKey:key]);
}
you're help would be greatly appreciated
If my approach is not the best one, please let me know so I can learn from your recommendations.
Try
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[dictionaryOfWebsites allKeys] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Initialize cell of style subtitle
NSArray *keys = [[dictionaryOfWebsites allKeys]sortedArrayUsingSelector:#selector(compare:)];
NSString *key = keys[indexPath.row];
cell.textLabel.text = key;
cell.detailTextLabel.text = dictionaryOfWebsites[key];
return cell;
}
Edit : It is better to have an array of dictionaries for these kind of representation.
Each dictionary with two key value pairs Title and Subtitle.
self.dataArray = [NSMutableArray array];
NSDictionary *dict = #{#"Title":#"Site1",#"Subtitle":#"http://www.site1.com"};
[dataArray addObject:dict];
//Add rest of the dictionaries to the dataArray
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.dataArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Initialize cell of style subtitle
NSDictionary *dict = self.dataArray[indexPath.row];
cell.textLabel.text = dict[#"Title"];
cell.detailTextLabel.text = dict[#"Subtitle"];
return cell;
}
You could try:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//cell initialization code
NSString *title = [keys objectAtIndex:indexPath.row];
cell.textLabel.text = title;
cell.detailTextLabel.text = [dictionaryOfWebsites objectForKey:title];
return cell;
}
in that case declare keys array as a property.
Related
I'm making a title indexed event invitation list. I have an array with EventStatus objects. I'm making the _data array for table like,
for (int i = 0; i < eventStatusList.count; i++) {
NSString *firstName = ((OCEventStatus*)eventStatusList[i]).user.firstName;
[_sortedUsers setObject:((OCEventStatus*)eventStatusList[i]).user.firstName forKey:[firstName substringToIndex:1]];
}
_sortedUserTitles = [[[_sortedUsers allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] mutableCopy];
_data = [eventStatusList mutableCopy];
[self.dataTableView reloadData];
and I think this for loop thing is too slow. Is there a way to do this in a good manner? Following is the title index making up logic with UITablrViewDataSource methods.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [_sortedUserTitles count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSString *sectionTitle = [_sortedUserTitles objectAtIndex:section];
NSArray *sectionUsers = [_sortedUsers objectForKey:sectionTitle];
return [sectionUsers count];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
// return animalSectionTitles;
return _alphabetArray;
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
return [_sortedUserTitles indexOfObject:title];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [_sortedUserTitles objectAtIndex:section];
}
This is error because of in the _sortedUsers dictionary has a string instead of an array. How may I fix this? And also please suggest a fast, good manner to implement this title index.
If you want to create an List of Firstnames try this perhaps.
At interface:
#property(nonatomic, strong)NSMutableDictionary *dict;
#property(nonatomic, strong)NSMutableArray *alphabet;
_dict = [NSMutableDictionary new];
_alphabet = [NSMutableArray new];
[eventStatusList sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
OCEventStatus *ev1 = (OCEventStatus*)obj1;
OCEventStatus *ev2 = (OCEventStatus*)obj2;
return [ev1.firstName compare:ev2.firstName];
}];
for(OCEventStatus *state in eventStatusList){
NSString *firstchar = [[state.firstName substringToIndex:1] lowercaseString];
if([dict objectForKey:firstchar]==nil){
NSMutableArray *tmp = [NSMutableArray new];
[tmp addObject:state];
[_dict setObject:tmp forKey:firstchar];
[_alphabet addObject:firstChar];
}else{
[[dict objectForKey:firstchar] addObject:state];
}
}
Now you have an Array of firstnames in a Dictionary which has the first letter as the key for Example: a -> ["Alfred","Albert",...]
In the Datasource methods you have to return it like this...
-(NSInteger)numberOfSectionsInTableView:(UITableView*)tableView{
return dict.count;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection;(NSInteger)section
{
return [dict objectForKey:[alphabet objectAtIndex:section]].count;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
OVEventStatus *state = [[dict objectForKey:[alphabet objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.text = state.firstName;
return cell;
}
Please try if this fits for you
Update:
If you also want to Sort the Arrays I would recommend to sort the eventListBy firstName first! So you have the correct order when you loop over the eventStatusList.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I had an application in which I had a response like:
{
"16-06-2016" = (
{
cccc = 16;
dddd = 17;
}
);
"17-06-2016" = (
{
cccc = 14;
dddd = 19;
},
{
cccc = 1;
dddd = 9;
}
);
"18-06-2016" = (
{
cccc = 14;
dddd = 19;
},
{
cccc = 1;
dddd = 9;
}
);
}
How will I display this NSDictionary in my UITableView. Can anybody help me?
Try something like this
self.sectionArr = [jsonDic allKeys]; //First get all section from dictionary like this
Now implement TableView delegate methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.sectionArr.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [self.sectionArr objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *arr = [jsonDic objectForKey:[self.sectionArr objectAtIndex:section]];
return arr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell= [tableview dequeueReusableCellWithIdentifier:#"Cell"];
NSArray *arr = [jsonDic objectForKey:[self.sectionArr objectAtIndex:indexPath.section]];
cell.textLabel.text = [[arr objectAtIndex:indexPath.row] valueForKey:#"dddd"];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *arr = [jsonDic objectForKey:[self.sectionArr objectAtIndex:indexPath.section]];
NSLog(#"Selected Obj - %#",[[arr objectAtIndex:indexPath.row] valueForKey:#"dddd"]);
}
Hope this will help you.
When I display an NSDictionary in a UITableView, since delegate methods like cellForRowAtIndexPath uses indexes, I typically do something like this to get an item at a particular index:
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Get array of keys
NSArray *keys = [self.dictionary allKeys];
// Get key for the current row
NString *key = [keys objectAtIndex:indexPath.row];
// Get object for current row
id object = [self.dictionary objectForKey:key];
// Then do the typical stuff
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:#"Cell"
forIndexPath:indexPath];
....
Though, in your case, "object" is an NSDictionary, so do something like this:
...
// Get object for current row
NSDictionary *item = [self.dictionary objectForKey:key];
id cccc = [item objectForKey:#"cccc"];
id dddd = [item objectForKey:#"dddd"];
....
If you need the keys sorted, then use keysSortedByValueUsingSelector: rather than allKeys.
Maybe something like this?
(I put data you've provided into dict variable)
#interface MainViewController () {
NSDictionary *dict;
NSArray *sortedKeysAsSectionNames;
}
- (void)viewDidLoad {
[super viewDidLoad];
dict = #{#"16-06-2016": #[#{#"cccc": #(16), #"dddd": #(17)}],
#"17-06-2016": #[#{#"cccc": #(14), #"dddd": #(19)},
#{#"cccc": #(1), #"dddd": #(9)}],
#"18-06-2016": #[#{#"cccc": #(14), #"dddd": #(19)},
#{#"cccc": #(1), #"dddd": #(9)}]
};
NSArray *dictKeys = [dict allKeys];
sortedKeysAsSectionNames = [dictKeys sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
NSDateFormatter *format = [[NSDateFormatter alloc] init];
format.dateFormat = #"dd-MM-yyyy";
NSDate *date1 = [format dateFromString:(NSString *)obj1];
NSDate *date2 = [format dateFromString:(NSString *)obj2];
return [date1 compare:date2];
}];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return sortedKeysAsSectionNames.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [(NSArray *)[dict objectForKey:sortedKeysAsSectionNames[section]] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
id key = sortedKeysAsSectionNames[indexPath.section];
NSArray *dataInSectionArray = [dict objectForKey:key];
NSDictionary *dataForCellDict = [dataInSectionArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
}
cell.textLabel.text = [[dataForCellDict objectForKey:#"cccc"] description];
cell.detailTextLabel.text = [[dataForCellDict objectForKey:#"dddd"] description];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return sortedKeysAsSectionNames[section];
}
I have been trying to set the uiTableViewHeader for my UITableView for a couple of days now with no luck. I don't think I am far off. Currently it shows the section Titles however multiples the number of records by X amount ( I presume my count may be wrong).
I think I need to further configure my cellForRowAtIndexPath method but Im unsure how.
I am a bit confused. I need to group the rowsAtIndexPath to the sections and stop them multiplying.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"atozCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
//Searchbar code is here
NSDictionary *dataDict = [self.sortedArray objectAtIndex:indexPath.section];
cell.textLabel.text = [dataDict objectForKey:#"Title"];
}
return cell;
}
Section Counts
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self.sectionArray count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [self.sectionArray objectAtIndex:section];
}
Data Populated from
// Find out the path of recipes.plist
NSString *path = [[NSBundle mainBundle] pathForResource:#"law2" ofType:#"plist"];
// Load the file content and read the data into arrays
self.dataArray = [NSArray arrayWithContentsOfFile:path];
//Sort the array by section
self.sortedArray = [self.dataArray sortedArrayUsingDescriptors:#[
[NSSortDescriptor sortDescriptorWithKey:#"Section" ascending:YES],
[NSSortDescriptor sortDescriptorWithKey:#"Title" ascending:YES]]];
//Section for sorting
self.sectionArray = [self.sortedArray valueForKeyPath:#"Section"];
Always you are sending index of the object. So please try to use this one
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
return [self.tableDataIndexTitles objectAtIndex:index];
}
I have tableView, which I am getting data from array and also the number of section and section title also from array, but when I give section title from array it breaks the App.
Getting values in array:
NSArray *tempArray =[[DataController staticVersion] startParsing:#"http://www.celeritas-solutions.com/pah_brd_v1/productivo/getCategory.php"];
for (int i = 0; i<[tempArray count]; i++) {
id *item = [tempArray objectAtIndex:i];
NSDictionary *dict = (NSDictionary *) item;
ObjectData *theObject =[[ObjectData alloc] init];
[theObject setCategoryID:[dict objectForKey:#"CategoryID"]];
[theObject setCategoryTitle:[dict objectForKey:#"CategoryTitle"]];
[theObject setCategoryDescription:[dict objectForKey:#"CategoryDescription"]];
[theObject setCategoryAddedByUserID:[dict objectForKey:#"CategoryAddedByUserID"]];
[theObject setCategoryAddedDateTime:[dict objectForKey:#"CategoryAddedDateTime"]];
[categoryArray addObject:theObject];
[theObject release];
theObject=nil;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [categoryArray count] ;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
[categoryArray objectAtIndex:section];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
expect a string in return.
Try
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
ObjectData *theObject =[categoryArray objectAtIndex:section];
return theObject.categoryTitle;
}
try like this ,
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection(NSInteger)section
{
return [[categoryArray objectAtIndex:section] valueForKey:#"title"];//replace title with your key value
}
You are adding an instance of ObjectData class into the categoryArray. The tableView:titleForHeaderInSection:method asks for an NSString object to set it as the header of the section. Check what you are returning in the titleForHeaderInSection: method. It has to be an NSString object.If you want to set the category title as your section header title, return the categoryTitle as
return [(ObjectData*)[categoryArray objectAtIndex:section] categoryTitle];
I have a plist with an alphabetical indexed list of entries. I now want to add a further level so that each entry has a definition text (like a small dictionary.) I need some advice as to how to modify my plist and code to accommodate this. The existing code is below - it's from the Apress book, but I can't seem to modify it for another level.
NSString *path = [[NSBundle mainBundle] pathForResource:#"sortedglossary" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc]initWithContentsOfFile:path];
self.names = dict;
[dict release];
NSArray *array = [[names allKeys] sortedArrayUsingSelector:#selector(compare:)];
self.keys = array;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"numberOfSectionInTable start");
return [keys count];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"numberOfRowsInSection start");
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
return [nameSection count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
static NSString *SectionsTableIdentifier = #"SectionsTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:SectionsTableIdentifier] autorelease];
}
cell.text = [nameSection objectAtIndex:row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSLog(#"titleForHeader");
NSString *key = [keys objectAtIndex:section];
return key;
}
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return keys;
}
There are a number of ways to accomplish this. Normally I will just create another child of the root node in the plist for definitions.
So your plist would have the array of your entries and it would have another dictionary. The dictionary contains the definition text, keyed by the values from the first array. That way, you can just look up the definition when you need it.
So the structure would look roughly like this:
Root
Entries(NSArray)
0 => entryA(NSString)
1 => entryB(NSString)
...
x => entryX(NSString)
Definitions(NSDictionary)
entryA(NSString) => definitionA(NSString)
entryB(NSString) => definitionB(NSString)
...
entryX(NSString) => definitionX(NSString)