If you have an NSArray object named anArray and an NSIndexSet object named anIndexSet, you can iterate forward through an index set as shown in below.
Excerpt, Apple Documents:
NSArray *anArray = [NSArray array];
NSIndexSet *anIndexSet = [NSIndexSet indexSetWithIndex:3];
NSUInteger index = [anIndexSet firstIndex];
while(index != NSNotFound) {
NSLog(#" %#",[anArray objectAtIndex:index]);
index = [anIndexSet indexGreaterThanIndex:index];
}
Why terminating NSRangeException in the above scenario?
I think this example describes the situation better. Also, not used an empty array as you say. Thanks so much rmaddy!!!
NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:#"K",#"G",#"G",#"E",#"R",#"G",#"E",#"G",#"G",#"M", nil];
NSIndexSet *anIndexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [mutableArray count])];
NSUInteger index = [anIndexSet lastIndex];
while (index != NSNotFound) {
if ([[mutableArray objectAtIndex:index] isEqualToString:#"G"]) {
[mutableArray removeObjectAtIndex:index];
}
index = [anIndexSet indexLessThanIndex:index];
}
NSLog(#" %#", mutableArray);
Related
I am developing an iOS App. When I try to get the number of cells for section using a NSMutableArray, I get
[__NSCFString count]: unrecognized selector sent to instance
0x60400043f9c0.
Please help. Here is the code:
for (NSDictionary *dict in _array) {
NSString *dic = [dict objectForKey:#"product_base"];
if (dic == nil) {
}else{
[_productfliters addObject:dic];
}
NSString *dicMaterial = [dict valueForKey:#"product_material"];
if (dicMaterial == nil) {
}else{
[_productfliters addObject:dicMaterial];
}
// NSMutableDictionary *value = [[NSMutableDictionary alloc]init];
// [value setValue:[dict valueForKey:#"product_size"] forKey:#"ABC"];
NSString *dicSize = [dict valueForKey:#"product_size"];
[_productfliters addObject:dicSize];
}
self.sectionNames =[_arrayHeading mutableCopy];
self.sectionItems =[_productfliters mutableCopy];
NSLog(#"%#",self.sectionItems);
_tableview.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
_tableview.rowHeight = UITableViewAutomaticDimension;
_tableview.estimatedRowHeight = 100;
self.expandedSectionHeaderNumber = -1;
[_tableview reloadData];
- (void)tableViewExpandSection:(NSInteger)section withImage:(UIImageView *)imageView {
NSArray *sectionData = [self.sectionItems objectAtIndex:section];
if (sectionData.count == 0) { //Error this part app crash NSCFString count
self.expandedSectionHeaderNumber = -1;
return;
} else {
[UIView animateWithDuration:0.4 animations:^{
imageView.transform = CGAffineTransformMakeRotation((180.0 * M_PI) / 180.0);
}];
NSMutableArray *arrayOfIndexPaths = [NSMutableArray array];
for (int i=0; i< sectionData.count; i++) {
NSIndexPath *index = [NSIndexPath indexPathForRow:i inSection:section];
[arrayOfIndexPaths addObject:index];
}
self.expandedSectionHeaderNumber = section;
[_tableview beginUpdates];
[_tableview insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation: UITableViewRowAnimationFade];
[_tableview endUpdates];
}
}
You unload strings and put them into _productfliters:
for (NSDictionary *dict in _array) {
NSString *dic = [dict objectForKey:#"product_base"];
if (dic == nil) {
}else{
[_productfliters addObject:dic];
}
...
You then assign that to sectionItems:
self.sectionItems =[_productfliters mutableCopy];
You then extract one of those strings, but call it an array (even though you put strings in there, so it's a string):
NSArray *sectionData = [self.sectionItems objectAtIndex:section];
Just because you say NSArray here doesn't make it so. You're just telling the compiler what you expect to be true. objectAtIndex: return id ("any object"). It trusts you when you say it's an NSArray, but it isn't true.
You then call .count on a NSString and crash.
It's unclear what you're actually trying to do here, but you have an array of strings, not an array of arrays.
Note that ObjC has a new feature called lightweight generics that would possibly have caught this mistake. Had you declared sectionNames as either NSArray<NSString *>* or NSArray<NSArray<NSString *>*>* (depending on which one you wanted this to be), the compiler probably would have thrown a warning (maybe even an error). Lightweight generics are nowhere near as powerful as Swift's generics, but they can catch some type mismatches like this.
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 would like to show an index bar on my tableview with all my songs sorted by alphabetical order and those foreign language songs in # just like how the iPod music in iOS do it.
However i gotten an error
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[LibraryViewController partitionSongObjects:collationStringSel:]: unrecognized selector sent to instance 0x1454be90'
any comments are greatly appreciated thanks.
//viewDidLoad
[[MediaService sharedService]getAllSongsItemInSongs:^(NSArray *data) {
self.songArray = [[NSMutableArray alloc]initWithArray:data];
}];
NSMutableArray *songNameArray = [NSMutableArray array];
for (Song *songNameItem in self.songArray)
{
[songNameArray addObject:songNameItem.songName];
}
self.sectionArray = [self partitionSongObjects:songNameArray collationStringSel:#selector(songName)];
[self.songLibraryTableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
- (NSMutableArray *)partitionObjects:(NSArray *)array collationStringSelector:(SEL)selector
{
self.collation = [UILocalizedIndexedCollation currentCollation];
NSInteger sectionCount = [[self.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 = [self.collation sectionForObject:object collationStringSelector:selector];
[[unsortedSections objectAtIndex:index] addObject:object];
}
NSMutableArray *sections = [NSMutableArray arrayWithCapacity:sectionCount];
for (NSMutableArray *section in unsortedSections)
[sections addObject:[self.collation sortedArrayFromArray:section collationStringSelector:selector]];
return sections;
}
you have a simple mistyping method name you call: [self partitionSongObjects:songNameArray collationStringSel:#selector(songName)] whereas you probably should:
[self partitionSongObjects:songNameArray collationStringSelector:#selector(songName)]
I would like to show an index bar on my tableview with all my songs sorted by alphabetical order and those foreign language songs and numerical in # just like how the iPod music in iOS.
I read the first character of all my song array object exclude duplicates and append it as the index.
How can i filter foreign / non alphabet and numbers ?
this is how it looks like, ugly.
would to show something like iPod.
-(NSMutableArray *)updateSongSectionIndexWithArray:(NSArray*)songArray andSelector:(SEL)selector
{
NSArray *indexedArray = [self partitionObjects:songArray collationStringSelector:selector];
return [[NSMutableArray alloc]initWithArray:indexedArray];
}
-(NSArray *)partitionObjects:(NSArray *)array collationStringSelector:(SEL)selector
{
self.collation = [UILocalizedIndexedCollation currentCollation];
NSInteger sectionCount = [[self.collation sectionTitles] count];//section count is take from sectionTitles and not sectionIndexTitles
NSMutableArray *unsortedSections = [NSMutableArray arrayWithCapacity:sectionCount];
//create an array to hold the data for each section
for(int i = 0; i < sectionCount; i++)
{
[unsortedSections addObject:[NSMutableArray array]];
}
if ([self.catString isEqualToString:ARTISTS])
{
//put each object into a section
for (id object in array)
{
if (!object)
{
continue;
}
NSInteger index = [self.collation sectionForObject:object collationStringSelector:selector];
[[unsortedSections objectAtIndex:index] addObject:object];
}
}
else
{
for (id object in array)
{
NSInteger index = [self.collation sectionForObject:object collationStringSelector:selector];
[[unsortedSections objectAtIndex:index] addObject:object];
}
}
NSMutableArray *sections = [NSMutableArray arrayWithCapacity:sectionCount];
//sort each section
for (NSMutableArray *section in unsortedSections)
{
[sections addObject:[self.collation sortedArrayFromArray:section collationStringSelector:selector]];
}
return sections;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[[UILocalizedIndexedCollation currentCollation] sectionTitles] count];
}
I did a similar solution for a contacts application. I start by defining the alphabet myself, then you can add to each section the items that fit (case insensitive compare for the letters, Characterset for the numbers). After the list is filled, you can remove (or hide) the sections which have no entry.
I did a similar thing for one of my apps. To split titles I used this code:
NSString* alphabet = #"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSArray* indexes = [alphabet componentsSeparatedByString:#""];
for (NSString* title in self.titles) {
char c = [[title uppercaseString] characterAtIndex:0];
NSString* index = [NSString stringWithFormat:#"%c",c];
if ([alphabet rangeOfString:index].location == NSNotFound) {
//The title does not start with a valid letter
index = #"#";
}
NSMutableArray* sectionObjects = [self.sections objectForKey:index];
if (!sectionObjects) {
sectionObjects = [[NSMutableArray alloc] init];
[self.sections setObject:sectionObjects forKey:index];
}
[sectionObjects addObject:title];
}
Obviously this code is still missing the sort part since it's trivial.
I ended up getting this my index to work by this
-(NSArray *)partitionObjects:(NSArray *)array collationStringSelector:(SEL)selector
{
self.collation = [UILocalizedIndexedCollation currentCollation];
NSInteger sectionCount = [[self.collation sectionTitles] count];//section count is take from sectionTitles and not sectionIndexTitles
NSMutableArray *unsortedSections = [NSMutableArray arrayWithCapacity:sectionCount];
//create an array to hold the data for each section
for(int i = 0; i < sectionCount; i++)
{
[unsortedSections addObject:[NSMutableArray array]];
}
if ([self.catString isEqualToString:ARTISTS])
{
//put each object into a section
for (id object in array)
{
if (!object)
{
continue;
}
NSInteger index = [self.collation sectionForObject:object collationStringSelector:selector];
[[unsortedSections objectAtIndex:index] addObject:object];
}
}
else
{
NSInteger index;
for (id object in array)
{
Song *songItem = object;
NSString* charIndex;
if([songItem.songName length]<=2)
{
charIndex = [songItem.songName substringToIndex:1];
}
else if([songItem.songName length]<=3)
{
charIndex = [songItem.songName substringToIndex:2];
}
else if([songItem.songName length]<=4)
{
charIndex = [songItem.songName substringToIndex:3];
}
else if([songItem.songName length]>=5)
{
charIndex = [songItem.songName substringToIndex:4];
}
NSRegularExpression *regex = [[NSRegularExpression alloc]
initWithPattern:#"[a-zA-Z]" options:0 error:NULL];
NSUInteger matches = [regex numberOfMatchesInString:charIndex options:0
range:NSMakeRange(0, [charIndex length])];
if (matches >=2)
{
NSLog(#"matches %i",matches);
index = [self.collation sectionForObject:object collationStringSelector:selector];
[[unsortedSections objectAtIndex:index] addObject:object];
}
else
{
index = 26;
[[unsortedSections objectAtIndex:index] addObject:object];
}
NSLog(#"songItem %# is in index %i",songItem.songName, index);
}
}
NSMutableArray *sections = [NSMutableArray arrayWithCapacity:sectionCount];
//sort each section
for (NSMutableArray *section in unsortedSections)
{
[sections addObject:[self.collation sortedArrayFromArray:section collationStringSelector:selector]];
}
return sections;
}
I am getting values which are sorted from a plist and displaying them in a tableview. I am providing the capability of entering a custom category which will be written to plist. But I want that to be Inserted in the sorted alphabetical order. Can someone suggest me how to get the indexpath of the row where it has to be inserted. I have used the following code where the custom entry will be inserted at the 0 location
NSInteger section = 0;
NSInteger row = 0;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
NSDictionary *categoryDictionary = [NSMutableDictionary dictionary];
[categoryDictionary setValue:newCategoryName forKey:#"name" ];
[categoryDictionary setValue:#"custom.png" forKey:#"image"];
[[self categoriesArray]insertObject:categoryDictionary atIndex:row];
[[self categoriesArray] writeToFile:[self dataFilePath] atomically:YES];
NSArray *indexPathsToInsert = [NSArray arrayWithObject:indexPath];
[[self tableView]insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationRight];
[self.categoriesArray writeToFile:[self dataFilePath] atomically:YES];
Try
NSMutableDictionary *categoryDictionary = [NSMutableDictionary dictionary];
[categoryDictionary setObject:newCategoryName forKey:#"name" ];
[categoryDictionary setObject:#"custom.png" forKey:#"image"];
//Add new category to array
[self.categoriesArray addObject:categoryDictionary];
//Sort Array
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES];
[self.categoriesArray sortUsingDescriptors:#[sortDescriptor]];
//Write array to plist
[self.categoriesArray writeToFile:[self dataFilePath] atomically:YES];
NSInteger section = 0;
//Get the index of saved Category item
NSInteger row = [self.categoriesArray indexOfObject:categoryDictionary];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
[self.tableView insertRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationRight];
In your table you will get section and row using following
NSInteger section = indexPath.section;
NSInteger row = indexPath.row;
if you have an array of sortable items, you can use this code snippet as help:
NSArray *sortedArray = #[#"a" , #"b", #"d", #"c", #"f"];
sortedArray = [sortedArray sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
NSLog(#"%#", sortedArray);
int c = [sortedArray indexOfObject:#"c"];
NSLog(#"%d", c);
Logs ->
(
a,
b,
c,
d,
f
)
2
so you first insert your object in the "toSort" array and then get the index of it ;)