Why does this type conversion of NSString to NSNumber returns invalid value of -1? - nsstring

This is the line of code in question:
bks.quantity = [NSNumber numberWithInteger: [[arrayOfSplitStrings[i] objectAtIndex:[[sd.dictionaryOfUserIndexes objectForKey: #"29"] intValue]] intValue]-1];
sd.dictionaryOfUserIndexes objectForKey: #"29" contains a string (representing a quantity) that has to be converted to NSNumber. When the statement is executed with a valid string quantity (0-10) it always returns -1, when it is supposed to return the NSNumber for the value.
What am I doing wrong?

This is not a "straight forward" answer (since the solution is just a silly one), it's more a suggestion on work methods, that's why I post an answer.
It's not always good to put it various lines in a single line.
Especially when in your case you encounter an issue. It's better to split each command, one by one, and to debug, check the value of each ones.
In your case:
bks.quantity = [NSNumber numberWithInteger: [[arrayOfSplitStrings[i] objectAtIndex:[[sd.dictionaryOfUserIndexes objectForKey: #"29"] intValue]] intValue]-1];
==>
NSInteger userOfIndexes = [[sd.dictionaryOfUserIndexes objectForKey: #"29"] intValue];
NSLog(#"userOfIndexes: %d", userOfIndexes);
NSInteger n = [arrayOfSplitStrings[i] objectAtIndex:userOfIndexes] intValue];
NSLog(#"n: %d", n);
bks.quantity = [NSNumberWithInteger:n-1];
I added NSLog(), but the values could be check with breakpoints and debugger. I could have also add a check on arrayOfSplitStrings with
NSArray *splitStrings = arrayOfSplitString[i];
NSLog(#"splitStrings: %#", splitStrings);
and replace n with:
NSInteger n = [splitStrings objectAtIndex:userOfIndexes] intValue];
That way, you would have check that apparently (according to your comment), your issue was were to put the "-1.
NSInteger n = [[arrayOfSplitStrings[i] objectAtIndex: userIndex-1] intValue];

Related

CoreData Using Sqlite and Unicode Strings Fetch Not Working

I have an application where i am storing japanese text in a coredata sqlite database. Populating the data seems to work ok (as far as I can tell), but when I search on any string field it returns no records. If I search on one of my integer fields it does.
The string data is unicode (ie, Japanese characters), so my question is will core data not work with Unicode? Seems unlikely. Does something special have to be done so a search (fetch) will work?
Code to populate the data looks like this:
WordProgress *newWordProgress = [NSEntityDescription insertNewObjectForEntityForName:#"WordProgress" inManagedObjectContext:progressContext];
newWordProgress.kanji = kanji;
newWordProgress.kanji = kana;
newWordProgress.senseIndex = [NSNumber numberWithInt:senseIndex];
newWordProgress.skillType = [NSNumber numberWithInt:skillType];
newWordProgress.leitnerDeck = leitnerDeck;
newWordProgress.dateLastShown = lastShownDate;
Code to test my fetch, looks like this:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"kanji = %#", #"彼"];
NSFetchRequest *testRequest = [[NSFetchRequest alloc] init];
[testRequest setPredicate:pred];
[testRequest setEntity:[NSEntityDescription entityForName:#"WordProgress" inManagedObjectContext:progressContext]];
NSArray *results = [progressContext executeFetchRequest:testRequest error:&error];
But returns no records, when I know that records were populated.
Just tried this too, and even this seems to fail. I'm sure I must be doing something fundamentally wrong:
WordProgress *newWordProgress = [NSEntityDescription insertNewObjectForEntityForName:#"WordProgress" inManagedObjectContext:progressContext];
newWordProgress.kanji = #"彼";
newWordProgress.kanji = kana;
newWordProgress.senseIndex = [NSNumber numberWithInt:senseIndex];
newWordProgress.skillType = [NSNumber numberWithInt:skillType];
newWordProgress.leitnerDeck = leitnerDeck;
newWordProgress.dateLastShown = lastShownDate;
NSPredicate *pred = [NSPredicate predicateWithFormat:#"kanji = %#", #"彼"];
NSFetchRequest *testRequest = [[NSFetchRequest alloc] init];
[testRequest setPredicate:pred];
[testRequest setEntity:[NSEntityDescription entityForName:#"WordProgress" inManagedObjectContext:progressContext]];
NSArray *results = [progressContext executeFetchRequest:testRequest error:&error];
It's not a Unicode problem, it's an NSPredicate error that would affect any string. You have:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"kanji = '%#'", #"彼"];
The single quotes in there are the problem. You're creating a predicate that looks for a literal %# in the data. The single quotes prevent substituting the #"彼" for the %#. Take the single quotes out and it should work as expected:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"kanji = %#", #"彼"];
My god, I'm completely retarded, sorry. Doing some more playing I saw the line...
newWordProgress.kanji = kanji;
newWordProgress.kanji = kana;
Doh! It was completely overwriting my key field. It should have read...
newWordProgress.kanji = kanji;
newWordProgress.kana = kana;
Thanks for the replies, guys. Sorry!

Addition between Label and Textfield

I am trying to add the value of my textfield plus the value of my label and place it in another label.
-(IBAction)finalTipTotalSelection:(id)sender
{
NSString *billFinalAmount = [billAmountTextField text];
float billFinalAmountFloat = [billFinalAmount floatValue];
NSString *tipTotalAmount = [resultLabel text];
float tipTotalAmountFloat = [tipTotalAmount floatValue];
float finalAmountShow = billFinalAmountFloat + tipTotalAmountFloat;
NSString *finalResult = [NSString stringWithFormat:#"$ %0.2f", finalAmountShow];
[finalTotalLabel setText:finalResult];
}
I am creating floatValues for the Strings and then in a float adding the other floatValues together, and finally displaying it in a label. The only issues is when I run this code the finalTotalLabel (shows the final amount) only shows the value of the billAmountTextField. So if the billAmountTextField = 187.82 and the tipTotalAmount was 10, the finalTotalLabel would show 187.82 (not 197.82). I cant seem to find my mistake. Thanks for your help!
It is caused by the tipTotalAmount having the $ character at the beginning of the string. The resulting float value for the tip amount will be 0.0 because:
floatValue... returns 0.0 if the receiver doesn’t begin with a valid
text representation of a floating-point number.
You can take a look at the class reference of NSString for the explanation of the return value of floatValue.
Try to filter out the non decimal and dot character first from the NSString instance before passing the message floatValue to it, for example:
NSMutableCharacterSet *_alnum = [NSMutableCharacterSet characterSetWithCharactersInString:#"."];
[_alnum formUnionWithCharacterSet:[NSCharacterSet decimalDigitCharacterSet]];
NSString *newTipTotalAmount = [[tipTotalAmount componentsSeparatedByCharactersInSet:
[_alnum invertedSet]]
componentsJoinedByString:#""];
float tipTotalAmountFloat = [newTipTotalAmount floatValue];
Here the newTipTotalAmount will be "39.19" compared to the tipTotalAmount which is "$ 39.19" and passing the floatValue message to newTipTotalAmount will give you the correct float value.

NSDictionary and plist

I have a plist file with string keys and number values. I think I managed to fill an NSDictionary object with the plist contents just fine with the code:
NSBundle* bun = [NSBundle mainBundle];
NSString* path = [bun pathForResource:#"Tempos" ofType:#"plist"];
tempos = [NSDictionary dictionaryWithContentsOfFile:path];
Now, here's the part I don't understand.
id object = [tempos objectForKey:#"Allegro"];
NSLog(#"bpm: %#", object);
Outputs the desired number, 168.
NSInteger beats = (NSInteger)[tempos objectForKey:#"Allegro"];
NSLog(#"bpm: %ld", beats);
Instead outputs, 43203.
More importantly, when I try
bpm = (NSInteger)[tempos objectForKey:#"Allegro"];
I get 43203 assigned to bpm. How do I get 168 assigned to bpm instead??
I think using this should work:
int beats = [[tempos objectForKey:#"Allegro"] intValue];
NSLog(#"bpm: %i", beats);

Core Data: fetching items is slow with predicate

For my iPhone application I set up a data model for Core Data. It contains one entity Words and its attributes are language : String, length : Integer16 and word : String.
I prefilled my model's SQLite database with a word list (200k items) writing a separate iPhone application using the identical data model and coping the filled database to the main application.
Now using NSFetchedRequest I can query for managed objects as I like, but the results come in slow. I use the following method:
- (NSString *)getRandomWordLengthMin:(int)minLength max:(int)maxLength
{
NSString *word = #"";
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Words"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSString *predicateString = #"length >= %d AND length <= %d";
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString,
minLength, maxLength];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
int entityCount = [context countForFetchRequest:fetchRequest error:&error];
[fetchRequest setFetchLimit:1];
if(entityCount != 0)
{
[fetchRequest setFetchOffset:arc4random()%entityCount];
}
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if([fetchedObjects count] != 0)
{
Words * test = [fetchedObjects objectAtIndex:0];
word = [NSString stringWithFormat:#"%#", [test word]];
}
return word;
}
Using an SQLite editor I already set an index manually on column zLength, but this didn't bring any speedup. Where is the bottleneck?
EDIT:
I figured out that getting int entityCount = ... is slow. But even getting all objects and then selecting one random word is slow:
Words * test = [fetchedObjects objectAtIndex:arc4random()%[fetchedObjects count]];
You are effectively running two fetches here, one to get the fetch count and then one to fetch the actual object. That will slow things down.
Your predicate is "backwards." Compound predicates evaluate the first expression e.g. length >= %d and then evaluate the second e.g. length <= %d only against the results of the first. Therefore you should put the test that eliminates the most objects first. In this case, length <= %d probably eliminates more objects so it should come first in the predicate.
Since you don't actually need the entire Words managed object but just the word string, you can set the fetch return type to NSDictionaryResultType and then set the property to fetch to just the word attribute. That will speed things up considerably.
Part of your problem here is that Core Data is designed to managed a structured object graph and you are using a random/unstructured graph so you are cutting against the grain of Core Data's optimizations.
Do not use the SQLite editor to edit the SQLite backing store for a Core Data storage. The internals of the database is private and subject to change.
Instead go the the model editor in Xcode and simply put a checkmark on the "indexed" option for the entity attribute you want indexed.
Not sure but maybe this predicate is easier to optimize:
NSString *predicateString = #"length BETWEEN (%d, %d)";

CoreData - NSPredicate formated with time range (NSTimeInterval)

I'm trying to find out how to go through my CoreData information and find objects that have a createdAt (part of my object as an NSDate) that is within a NSTimeInterval. How do I set this up?
I've looked on the documentation at:
http://developer.apple.com/documentation/Cocoa/Conceptual/Predicates/predicates.html
But I'm not finding anything there.
Do I need to create two time stamps and use SQL's BETWEEN?
Any help would be wonderful.
First of all, it doesn't make sense to check if an NSDate is within an NSTimeInterval, because NSTimeInterval just specifies a length of time, not its location. Instead, you want to use two separate NSDates specifying the beginning and end of your intervals.
Here's what it would look like (beginningTime and endTime are NSDates).
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"YourEntityName" inManagedObjectContext:yourContext];
NSPredicate *beginningPredicate = [NSPredicate predicateWithFormat:#"createdAt >= %#", beginningTime];
NSPredicate *endPredicate = [NSPredicate predicateWithFormat:#"createdAt <= %#", endTime];
request.predicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:beginningPredicate, endPredicate, nil]];
NSArray *results = [yourContext executeFetchRequest:request error:NULL];

Resources