CoreData - NSPredicate formated with time range (NSTimeInterval) - sqlite

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];

Related

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

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];

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!

How can I change (modify) video frame rate and bit rate?

I need re-encoding a video file from photo library for web site service.
I tried below code but it has occurred error like 'video composition must have composition instructions'.
(code)
AVAsset *anAsset = [[AVURLAsset alloc] initWithURL:videoFileUrl options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:anAsset];
if ([compatiblePresets containsObject:AVAssetExportPresetMediumQuality]) {
self.exportSession = [[AVAssetExportSession alloc]
initWithAsset:anAsset presetName:AVAssetExportPresetPassthrough];
AVMutableComposition* mixComposition = [[AVMutableComposition alloc] init];
AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, anAsset.duration) ofTrack:[[anAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];
AVMutableVideoCompositionLayerInstruction *FirstlayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:firstTrack];
AVMutableVideoCompositionInstruction * MainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
MainInstruction.layerInstructions = [NSArray arrayWithObjects:FirstlayerInstruction,nil];
AVMutableVideoComposition *MainCompositionInst = [AVMutableVideoComposition videoComposition];
MainCompositionInst.frameDuration = CMTimeMake(1, 30); // bit rate
MainCompositionInst.renderSize = CGSizeMake(640, 480); // frame rate
[self.exportSession setVideoComposition:MainCompositionInst];
NSURL *furl = [NSURL fileURLWithPath:self.tmpVideoPath];
self.exportSession.outputURL = furl;
self.exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTime start = CMTimeMakeWithSeconds(self.startTime, anAsset.duration.timescale);
CMTime duration = CMTimeMakeWithSeconds(self.stopTime-self.startTime, anAsset.duration.timescale);
CMTimeRange range = CMTimeRangeMake(start, duration);
self.exportSession.timeRange = range;
self.trimBtn.hidden = YES;
self.myActivityIndicator.hidden = NO;
[self.myActivityIndicator startAnimating];
[self.exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([self.exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(#"Export failed: %#", [[self.exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
break;
default:
NSLog(#"NONE");
dispatch_async(dispatch_get_main_queue(), ^{
[self.myActivityIndicator stopAnimating];
self.myActivityIndicator.hidden = YES;
self.trimBtn.hidden = NO;
[self playMovie:self.tmpVideoPath];
});
break;
}
}];
}
}
without the changing frame rate and bit rate, it works perfectly.
Please give me any advise.
Thanks.
Framerate I'm still looking for, but bitrate has been solved by this drop in replacement for AVAssetExportSession: https://github.com/rs/SDAVAssetExportSession
Not sure but some things to look at. Unfortunatley the error messages dont tell you much in these cases in AVFoundation.
In general, I would make things simple and slowly add functionality.To start, make sure all layers start at zero and then end at the final duration. Do the same for the main composition. Invalid times may give you an error like this. For your instruction, make sure that it starts at the same time and ends at the same time too.

Declaring an NSDictionary with an NSString as its name

Ok, so I would like to create an NSDictionary, but the pointer should be followed by the value of an NSString that has been put in by the user. Is this possible? I imagine it would be something along the lines of this...
someNSString = _someTextField.text;
NSDictionary * {someNSString} = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:someUnimportantVariable], #"someUnimportantKey",...nil]
Thanks in advance, I realize that this is either completely not possible or there is a pretty simple solution. Either way, I'm sorry if I wasted your time.
you could try creating a "dictionary of dictionaries". something to the effect of:
someNSString = _someTextField.text;
NSDictionary *myDictionary = [[NSDictionary alloc] init];
[myDictionary setObject:[NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:someUnimportantVariable], #"someUnimportantKey",...nil] forKey:someNSString];
and if you wanted to get back that dictionary
NSDictionary someNSStringDictionary = [myDictionary objectForKey:someNSString];
let me know if it helps in any way.

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)";

Resources