Iterate through array comparing dictionary values - macos

I have a NSMutableArray *dataArray containing NSDictionaries. I want to iterate through the array in order to create a new NSMutableArray *tempDataArray with objects from the first array if the searchString matches one of the dictionaries values.
Here is my code:
self.tempDataArray = [[NSMutableArray alloc] init];
for (int i = 0; i < kDelegate.dataArray.count; i++) {
NSDictionary *dict = [kDelegate.dataArray objectAtIndex:i];
for (int j = 0; j < [dict allValues].count ; j++) {
if ([[[[dict allValues] objectAtIndex:j]stringValue] isEqualToString:searchString]) {
[self.tempDataArray addObject:dict];
}
}
}
Now this doesn't work because the dictionary also contains a NSDate. At least that is what I am reading from the error message:
-[__NSTaggedDate stringValue]: unrecognized selector sent to instance 0x41b7809e2600000d
Which I dont understand, because I do declare all the values as stringValue.
That was the first part of my problem. The second half is that this only searches for an exact match but I would rather have a search determining if the dictionaries values contain a substring.
Anyway, thanks for all your help!

(untested):
self.tempDataArray = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < kDelegate.dataArray.count; i++) {
NSDictionary *dict = [kDelegate.dataArray objectAtIndex:i];
NSArray *allValues = [dict allValues];
for (NSUInteger j = 0; j < allValues.count; j++) {
NSObject *obj = [allValues objectAtIndex:j];
if ([obj isKindOfClass:[NSString class]]) {
NSRange range = [(NSString *)obj rangeOfString:searchString];
if (range.location != NSNotFound) {
[self.tempDataArray addObject:dict];
}
}
}
}

Related

Xcode: How to find out what NSLog automatically casts into?

Hello I am trying to save and load my game data. It cannot read an integer properly from a file, however it can read a string properly though...
Strangely enough when I print the number with NSLog it works!. However if I try to use the value or pass it into another value it doesn't.
Now I could 'fix' this by converting all the numbers into strings and then saving it, then loading the strings and converting it back to numbers. However I would like to know the proper way of doing it. Also there are 1600 tiles not including other data so that would be a noticeable overhead.
Can someone tell me what I am doing wrong or what NSLog is doing automatically?
Below is the code section relevant to the question. mapData[i][j] is an array of integers representing whats on a tile.
-(void)saveGame
{
NSLog(#"%s", "Saved");
NSString *temp = [self saveFilePath];
NSLog(#"%s %#", "FilePath", temp);
NSMutableArray *values = [NSMutableArray arrayWithCapacity:1602];
int i = 0;
int j = 0;
int a = 0;
for(i = 0; i < 40; i++)
{
for(j = 0; j < 40; j++)
{
//values[i] = mapData[j][k];
[values addObject:[NSNumber numberWithInteger:mapData[i][j]]];
NSLog(#"%d, %d", i, j);
NSLog(#"%s, %d", "Map Data: ", mapData[i][j]);
NSLog(#"%#", [values objectAtIndex:a]);
a++;
}
}
// test letter OK
NSString * letterA = #"a";
[values addObject:[NSString stringWithString:letterA]];
// test independant number
NSInteger aNum = 888;
[values addObject:[NSNumber numberWithInteger:aNum]];
NSArray *value = [NSArray arrayWithArray:values];
// test conversion OK
a = 0;
for(i = 0; i < 40; i++)
{
for(j = 0; j < 40; j++)
{
NSLog(#"%#", [value objectAtIndex:a]);
a++;
}
}
NSLog(#"%#", [value objectAtIndex:a]); // letter OK
a++;
NSLog(#"%#", [value objectAtIndex:a]); // number OK
[value writeToFile:[self saveFilePath] atomically:YES]; // atomically means all or nothing. i.e power fail will not save half
}
-(NSString *)saveFilePath
{
NSArray * path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[path objectAtIndex:0] stringByAppendingPathComponent:#"savefile.plist"];
}
-(void)loadGame
{
NSLog(#"%s", "Loaded");
NSString *loadPath = [self saveFilePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:loadPath];
if(fileExists)
{
NSArray *values = [[NSArray alloc] initWithContentsOfFile:loadPath];
int a = 0;
for(int i = 0; i < 40; i++)
{
for(int j = 0; j < 40; j++)
{
//mapData[i][j] = [values objectAtIndex:a];
//mapData[i][j] = (NSInteger)[values objectAtIndex:a];
NSInteger * tempNumber = [values objectAtIndex:a];
NSLog(#"%#", tempNumber); // YES!
int tempInt = (int)tempNumber;
NSLog(#"%d", tempInt); // no
mapData[i][j] = tempNumber;
NSLog(#"%d, %d, %d", a , i, j);
NSLog(#"%s, %d", "Loaded Map Data: ", mapData[i][j]); // no
a++;
}
}
// string works but integer doesnt...
NSString * letter;
letter = [values objectAtIndex:a];
NSLog(#"%#", letter); // YES
// this number OK - needs pointer AND NSLog...
a++;
NSInteger * number;
number = [values objectAtIndex:a];
NSLog(#"%#", number); // YES
}
}
Nvm I figured it out. NSLog was automatically unwrapping the numbers for me. Manually unwrapping will display the correct numbers instead of memory addresses.

Objective C: Search in a tableview with NSASCIIStringEncoding

I am searching into a UITableView using this:
titles = [NSArray arrayWithArray:[datamanager titlesForEntriesBetween:(NSInteger)[slider minSelectedValue] and:(NSInteger)[slider maxSelectedValue]containing:searchText]];
How can I encode array value with NSASCIIStringEncoding during the search process?
(Array contains "tĂȘte" for example.. and when I search "tete" nothing matches.. so I will encode array value just for my search)
I would add change the third parameter to your datamanager function:
- (NSArray*)titlesForEntriesBetween:(NSInteger)startIndex
and:(NSInteger)stopIndex
withFunction:(BOOL(^)(NSString*))block {
NSMutableArray *retVal = [NSMutableArray array];
for(NSInteger i = startIndex; i <= stopIndex; ++i) {
NSString *string = [array_ objectAtIndex:i];
if (block(string)) {
[retVal insertObject:string];
}
}
return retVal;
}
And then I would call the function like this:
titles = [datamanager titlesForEntriesBetween:(NSInteger)[slider minSelectedValue] and:(NSInteger)[slider maxSelectedValue] withFunction:^(BOOL)(NSString *str) {
NSData *data = [str dataUsingEncoding:NSASCIIStringEncoding];
NSString *simpleString = [[[NSString alloc] initWithData:data usingEncoding: NSASCIIStringEncoding] autorelease];
return [simpleString isEqualToString:str];
}]];
Note: I just typed this in, I haven't tried to compile/run this.

What is correct usage of e.g. [NSDictionary dictionaryWithObjects:forKeys:count:] under ARC?

I'm unsure how to correctly use [NSDictionary dictionaryWithObjects:forKeys:count:] together with ARC (automatic reference counting). The C arrays require some special modifier, otherwise they receive warning right away. What is a correct example?
Or, asked the other way around, is this safe usage?
#implementation NSArray (CreateDictionaryUsingBlock)
- (NSDictionary *)dictionaryWithKeysUsing:(id (^)(id obj))block
{
NSUInteger n = [self count];
__autoreleasing id *keys = (__autoreleasing id *)malloc(n*sizeof(id));
__autoreleasing id *objects = (__autoreleasing id *)malloc(n*sizeof(id));
for(int i = 0; i<n; i++) {
id object = [self objectAtIndex:i];
keys[i] = block(object);
objects[i] = object;
}
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects
forKeys:keys
count:n];
free(keys);
free(objects);
return dictionary;
}
#end

How to sort an array of NSDate(in NSMutableArray)?

Can anyone show me how to sort an array(NSMutableArray) of NSDate in order for the actual dates?
Thanks!
I believe you want to use something like -NSMutableArray sortUsingSelector: and pass in #selector(compare:). Ie, assuming you had an NSMutableArray of NSDates named *dateArray*:
[dateArray sortUsingSelector:#selector(compare:)];
Here you go just modify some part of code for your requirement
- (NSArray *)sortedWeightEntriesByWeightDate:(NSArray *)unsortedArray {
NSMutableArray *tempArray = [NSMutableArray array];
NSMutableArray *sortedArray = [NSMutableArray arrayWithCapacity:0];
#try {
for(int i = 0; i < [unsortedArray count];i++) {
NSDateFormatter *df = [[NSDateFormatter alloc]init];
MyDataModal *entry = [unsortedArray objectAtIndex:i];
[df setDateFormat:#"yyyy-MM-dd"];
NSDate *date = [df dateFromString:entry.weightDate];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
if(date) {
[dict setObject:entry forKey:#"entity"];
[dict setObject:date forKey:#"date"];
[tempArray addObject:dict];
}
[df release];
}
NSInteger counter = [tempArray count];
NSDate *compareDate;
NSInteger index;
for(int i = 0 ; i < counter; i++) {
index = i;
compareDate = [[tempArray objectAtIndex:i] valueForKey:#"date"];
NSDate *compareDateSecond;
for(int j = i+1 ; j < counter; j++) {
compareDateSecond=[[tempArray objectAtIndex:j] valueForKey:#"date"];
NSComparisonResult result = [compareDate compare:compareDateSecond];
if(result == NSOrderedDescending) {
compareDate = compareDateSecond;
index=j;
}
}
if(i!=index)
[tempArray exchangeObjectAtIndex:i withObjectAtIndex:index];
}
NSInteger counterIndex = [tempArray count];
for(int i = 0; i < counterIndex ; i++) {
[sortedArray addObject:[[tempArray objectAtIndex:i] valueForKey:#"entity"]];
}
}
#catch (NSException * e) {
NSLog(#"An exception occured while sorting weight entries by date");
}
#finally {
return [NSArray arrayWithArray:sortedArray];
}
}

NSArray to C array

Can we convert an NSArray to a C array?
If not what alternatives, are there? Suppose I need to feed the C array to OpenGL functions where the C array contains vertex pointers read from plist files.
The answer depends on the nature of the C-array.
If you need to populate an array of primitive values and of known length, you could do something like this:
NSArray* nsArray = [NSArray arrayWithObjects:[NSNumber numberWithInt:1],
[NSNumber numberWithInt:2],
nil];
int cArray[2];
// Fill C-array with ints
int count = [nsArray count];
for (int i = 0; i < count; ++i) {
cArray[i] = [[nsArray objectAtIndex:i] intValue];
}
// Do stuff with the C-array
NSLog(#"%d %d", cArray[0], cArray[1]);
Here's an example where we want to create a new C-array from an NSArray, keeping the array items as Obj-C objects:
NSArray* nsArray = [NSArray arrayWithObjects:#"First", #"Second", nil];
// Make a C-array
int count = [nsArray count];
NSString** cArray = malloc(sizeof(NSString*) * count);
for (int i = 0; i < count; ++i) {
cArray[i] = [nsArray objectAtIndex:i];
[cArray[i] retain]; // C-arrays don't automatically retain contents
}
// Do stuff with the C-array
for (int i = 0; i < count; ++i) {
NSLog(cArray[i]);
}
// Free the C-array's memory
for (int i = 0; i < count; ++i) {
[cArray[i] release];
}
free(cArray);
Or, you might want to nil-terminate the array instead of passing its length around:
// Make a nil-terminated C-array
int count = [nsArray count];
NSString** cArray = malloc(sizeof(NSString*) * (count + 1));
for (int i = 0; i < count; ++i) {
cArray[i] = [nsArray objectAtIndex:i];
[cArray[i] retain]; // C-arrays don't automatically retain contents
}
cArray[count] = nil;
// Do stuff with the C-array
for (NSString** item = cArray; *item; ++item) {
NSLog(*item);
}
// Free the C-array's memory
for (NSString** item = cArray; *item; ++item) {
[*item release];
}
free(cArray);
NSArray has a -getObjects:range: method for creating a C-array for a subrange of an array.
Example:
NSArray *someArray = /* .... */;
NSRange copyRange = NSMakeRange(0, [someArray count]);
id *cArray = malloc(sizeof(id *) * copyRange.length);
[someArray getObjects:cArray range:copyRange];
/* use cArray somewhere */
free(cArray);
I would suggest to convert yourself, with something like:
NSArray * myArray;
... // code feeding myArray
id table[ [myArray count] ];
int i = 0;
for (id item in myArray)
{
table[i++] = item;
}

Resources