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];
Related
Is there a fast way to get all elements at indexes from an array returned from a UITableView (NSArray of NSIndexPaths).
For instance:
[self.dataSourceArray selectItemsAt:[self.tableView indexPathsForSelectedItems]]
There is no built-in method, but you can simply loop over the selected rows
(assuming that there is only one section) and add the corresponding elements
to a mutable array:
NSMutableArray *selectedObjects = [NSMutableArray array];
for (NSIndexPath *indexPath in [self.tableView indexPathsForSelectedRows]) {
[selectedObjects addObject:self.dataSourceArray[indexPath.row]];
}
word you are looking for is Lambda
there is two methots for that
you can look for it in link
Does Objective-C have List Lambda Query like C#?
it should look like this
NSPredicate *p = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
for(NSIndexPath i in [self.tableView indexPathsForSelectedItems]){
if(i.row == evaluatedObject.row){
return YES;
}
}
return NO;
}];
NSArray *result = [self.dataSourceArray filteredArrayUsingPredicate:p];
Use objectsAtIndexes: method of NSArray.
NSMutableIndexSet *mutableIndexSet = [[NSMutableIndexSet alloc] init];
// Add all indexes to NSMutableIndexSet
for (int i = 0; i < [self.tableView indexPathsForSelectedRows].count; i++) {
[mutableIndexSet addIndex: ((NSIndexPath *) [self.tableView indexPathsForSelectedRows][i]).row];
}
[self.dataSourceArray objectsAtIndexes:mutableIndexSet];
I am trying to create a view that contains a UITableView, I would like to populate the UITableView using an NSMutableArray of NSDictionaries. I would however like to split the NSMutableArray into sections using one of the NSDictionaries key values.
The NSDictionary looks like this
First Name
Last Name
Age
The NSMutableArray is not sorted however I would like to create the UITableView that is split up into sections based on age and sorted lowest to highest.
NSArray has a method called sortedArrayUsingComparator:, which is called on an NSArray object and takes a block which returns as NSComparison result as an argument.
You can sort on the Age key as such:
NSArray *sortedArray = [yourArray sortedArrayUsingComparator:
^NSComparisonResult(id a, id b) {
NSInteger ageA = [[(NSDictionary*)a objectForKey:#"Age"] integerValue];
NSInteger ageB = [[(NSDictionary*)b objectForKey:#"Age"] integerValue];
if(a < b)
return NSOrderedAscending;
if(b < a)
return NSOrderedDescending;
else
return NSOrderedSame;
}];
For splitting into sections, since we've already sorted it, we can just iterate through the array:
NSMutableArray *sectionedArray = [NSMutableArray array];
for(NSDictionary *curDict in sortedArray) {
if([[curDict objectForKey:#"Age"] isEqual:
[[[sectionedArray lastObject] firstObject] objectForKey:#"Age"]) {
[[sectionedArray lastObject] addObject:curDict];
} else {
NSMutableArray *newSection = [NSMutableArray arrayWithObject:curDict];
[sectionedArray addObject:newSection];
}
}
First of all, you need to sort the array with this function:
self.mutableArray = [mutableArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSInteger ageA = [[(NSDictionary*)a objectForKey:#"Age"] integerValue];
NSInteger ageB = [[(NSDictionary*)b objectForKey:#"Age"] integerValue];
if(a < b) return NSOrderedAscending;
if(b < a) return NSOrderedDescending;
return NSOrderedSame;
}];
Now you can extract from the array the distinct values for the key "Age":
NSArray *uniqueAges = [_mutableArray valueForKeyPath:#"#distinctUnionOfObjects.Age"];
Finally, you can use this array to return the number of section in the tableView delegate:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [uniqueAges count];
}
And also you can use the array to return the name of the section:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [uniqueAges objectAtIndex:section];
//remember to return a string if isn't so!
}
I have some JSON data that I am getting from my database. I can pull it fine and load it into my table view. my issue is separating my JSON data so I can section the tableview.
JSON
[{"id":"1","name":"steve mans","phoneNumber":"(559)123-4455","showNumber":"1","greenCard":"1","expiration":"2014-02-15","driver":"1","paid":"1","watch":"1"},
{"id":"2","name":"myself and me","phoneNumber":"(559)321-6784","showNumber":"1","greenCard":"1","expiration":"2013-10-18","driver":"0","paid":"0","watch":"2"},
{"id":"4","name":"tod bellesmithson","phoneNumber":"(559)678-3421","showNumber":"0","greenCard":"1","expiration":"2013-11-22","driver":"1","paid":"0","watch":"2"},
{"id":"3","name":"John Smith","phoneNumber":"(559)123-1234","showNumber":"1","greenCard":"0","expiration":"2013-10-08","driver":"0","paid":"1","watch":"3"},
{"id":"5","name":"greg smith","phoneNumber":"559 345-1234","showNumber":"1","greenCard":"1","expiration":"2013-10-08","driver":"0","paid":"1","watch":"3"}]
What I am trying to do is, separate this data into three sections in my tableview. So I thought create three different tables and load each table into a different section of the tableview. But the information is the same in each one (id, name, phone etc.) So I ended up with one table and added a column that designates what shift people work, 'watch'. So how do I separate the data by using the watch column, so in my tableview i will have:
section one
people who work night shift
section two
people who work morning
section three
night shift
Try with this code:
NSArray *data = (NSArray)[NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&error];
NSMutableArray *morningShift = [NSMutableArray array];
NSMutableArray *noonShift = [NSMutableArray array];
NSMutableArray *nightShift = [NSMutableArray array];
for (int i=0; i< [data count]; i++)
{
NSDictionary *item = data[i];
if (#"1" == item[#"watch"] )
{
[morningShift addObject:item];
} else if (#"2" == item[#"watch"] )
{
[noonShift addObject:item];
} else if (#"3" == item[#"watch"] )
{
[nightShift addObject:item];
}
}
try this
NSMutableArray *tableData = [NSMutableArray alloc] init];
NSArray* nameArr = [NSArray arrayWithObjects: #"1", #"2",#"3",nil];
for(int i=0; i<[nameArr count]; i++)
{
[tableData addObject:[jsonArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"watch = %#",[nameArr objectAtIndex:i]]] ];
}
TableView Delegate Methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [tableData count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[tableData objectAtIndex:section ] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell= nil;
//implement your logic to display the cell item;
NSArray sectionData = [tableData objectAtIndex:indexPath.section];
NSArray rowData = [sectionData objectAtIndex:indexPath.row];
return cell;
}
Please note i have not compiled the code. There is a chance of compilation error.
check for section in your cellForRowAtIndexPath method and load data accordingly,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//initialize cell
if (indexPath.section == 0){
// load data
}
return cell;
}
I am trying to add the image for search (magnifying glass) as the section, to easily go to the search bar.
This is the issue I am experiencing:
My code to setup the sections is as follows:
Note: self.fbFriends is an Array of Dictionaries that include the facebook friends of the user.
self.fbFriends = [[NSArray alloc] initWithArray:[[MESCache sharedCache] facebookFriends]];
self.searchResults = [[NSMutableArray alloc] init];
self.sections = [[NSMutableDictionary alloc] init];
BOOL found;
[self.sections setValue:[[NSMutableArray alloc] init] forKey:UITableViewIndexSearch];
// Loop through the friends and create our keys
for (NSDictionary *friend in self.fbFriends)
{
NSString *c = [[friend objectForKey:#"name"] substringToIndex:1];
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 friends into their respective keys
for (NSDictionary *friend in self.fbFriends)
{
[[self.sections objectForKey:[[friend objectForKey:#"name"] substringToIndex:1]] addObject:friend];
}
// Sort each section array
for (NSString *key in [self.sections allKeys])
{
[[self.sections objectForKey:key] sortUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES]]];
}
Here is my section setup and header views:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return 1;
} else {
return [[self.sections allKeys] count];
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return NSLocalizedString(#"FbFriendsSearchControllerSection", #"Fb Friends search controller - section title for search results table view");
} else {
return [[[self.sections allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:section];
}
}
Does anyone see how this is incorrect?
This is not a standard practice. There is no need for the extra section just to show a search.
Don't add the "search" section to your self.sections dictionary. Instead, you just have sections for the actual data. Then in your tableView:sectionForSectionIndexTitle:atIndex: method you can do:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
NSInteger res = 0;
if (tableView == self.tableView) {
if (index == 0) {
// If the user taps the search icon, scroll the table view to the top
res = -1;
[self.tableView setContentOffset:CGPointMake(0, 0) animated:NO];
} else {
res = ... // return the proper index for your data
}
} else {
res = 0;
}
return res;
}
Side note - you really want to have an array of dictionaries. The main array should represent the sections. As you have it now, you are constantly getting your main dictionary's keys and sorting them. This will be done MANY times - all needlessly. Using an array lets you quickly get the data from the section index.
The code works and populates the table with sections, but it has a flaw: It doesn't escape punctuation and 'The' prefixes in song titles, just like how the native music app does.
Would really appreciate some guidance on how I should go about doing this.
- (void)viewDidLoad
{
[super viewDidLoad];
MPMediaQuery *songQuery = [MPMediaQuery songsQuery];
self.songsArray = [songQuery items];
self.sectionedSongsArray = [self partitionObjects:self.songsArray collationStringSelector:#selector(title)];
}
- (NSArray *)partitionObjects:(NSArray *)array collationStringSelector:(SEL)selector
{
UILocalizedIndexedCollation *collation = [UILocalizedIndexedCollation currentCollation];
NSInteger sectionCount = [[collation sectionTitles] count];
NSMutableArray *unsortedSections = [NSMutableArray arrayWithCapacity:sectionCount];
for(int i = 0; i < sectionCount; i++)
{
[unsortedSections addObject:[NSMutableArray array]];
}
for (id object in array)
{
NSInteger index = [collation sectionForObject:object collationStringSelector:selector];
[[unsortedSections objectAtIndex:index] addObject:object];
}
NSMutableArray *sections = [NSMutableArray arrayWithCapacity:sectionCount];
for (NSMutableArray *section in unsortedSections)
{
[sections addObject:[collation sortedArrayFromArray:section collationStringSelector:selector]];
}
return sections;
}
I completely overlooked this. The answer here is to simply use MPMediaQuerySection. The Apple docs are there for a reason!
Cocotutch -
Here's the implementation that I used to index a query containing all the songs in my music library:
MPMediaQuery *allSongsQuery = [MPMediaQuery songsQuery];
// Fill in the all songs array with all the songs in the user's media library
allSongsArray = [allSongsQuery items];
allSongsArraySections = [allSongsQuery itemSections];
allSongsArraySections is an NSArray of MPMediaQuerySection, each of which has a title and a range. The NSArray object for section zero (with title #"A" in my case) has range.location of 0 and range.length of 158.
I return the range.length value for each section when numberOfRowsInSection is called for my UITableView. I use the range.location value in cellForRowAtIndexPath as the starting row of the section, and then add indexPath.row to it in order to arrive at the cell I need to return from my allSongsArray.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
....
// Return the number of rows in the section.
MPMediaQuerySection *allSongsArraySection = globalMusicPlayerPtr.allSongsArraySections[section];
return allSongsArraySection.range.length;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
...
MPMediaQuerySection *allSongsArraySection = globalMusicPlayerPtr.allSongsArraySections[indexPath.section];
rowItem = [globalMusicPlayerPtr.allSongsArray objectAtIndex:allSongsArraySection.range.location + indexPath.row];
....
}
Before using this I had tried to match the native music player's implementation by writing my own, and it didn't behave quite identically. Not only that, but the native indexing is MUCH faster!