migratePersistentStore: causes duplicate data when destination URL exists - cocoa

Just encountered a scenario that I thought I'd share. When using NSPersistentStoreCoordinator migratePersistentStore: with a destination URL that already exists, the resulting data is merged. My scenario is that I'm creating dated backups whenever my app closes and it's possible that multiple launches in the same day will backup so the same file.

I solved the issue by using NSFileManager fileExistsAtPath: and removeItemAtPath: to remove the existing file before calling migratePersistentStore:. This seems to have solved the duplication issue.
I couldn't find documentation that this is a feature but maybe it is.
UPDATED
I've added some example code for Jim. The flag for disabling journal_mode was very important for my use case. See here for more info
if ([[NSFileManager defaultManager] fileExistsAtPath: backupPath])
[[NSFileManager defaultManager] removeItemAtPath: backupPath
error: nil];
return [BRManagedObject.persistentStoreCoordinator
migratePersistentStore: store
toURL: [NSURL fileURLWithPath: backupPath]
options: #{
NSSQLiteManualVacuumOption : #(YES)
#ifndef SQLITE_USES_WRITE_AHEAD_LOG
, NSSQLitePragmasOption : #{ #"journal_mode" : #"DELETE" }
#endif
}
withType: persistentStoreType
error: nil];

Related

Can't see DataBase in device after copied in bundle

I finished my App for a distance calculation. I'll update my database before to copy it.
I did some tests and when I'm moving my database (DataBase.sqlite) into "Copy Bundle Ressources" and running App on my device, I can't see my data.
Looks like the device is using his own database with same name (DataBase.sqlite).
(DataBase will update a TableView during launch)
I created a AddButton to see if I can update my DataBase from an iPhone and it works.
I mean is I closed the App an re launched it, I can see the created data from the AddButton.
Have you any idea?
When you include the database into your bundle via Xcode's "Copy Bundle Resources", it's part of the bundle, i.e. you get the path via:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:#"DataBase" ofType:#"sqlite"];
If you want to copy that to your Documents folder so that you can use it, you get the Documents path via:
NSString *documentsFolder = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *documentsPath = [documentsFolder stringByAppendingPathComponent:#"DataBase.sqlite"];
So, you might check for existence in Documents, and if not there, copy from bundle to Documents:
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:documentsPath]) {
NSError *error = nil;
BOOL success = [fileManager copyItemAtPath:bundlePath toPath:documentsPath error:&error];
NSAssert(success, #"%s: copyItemAtPath failed: %#", __FUNCTION__, error);
}
You can now open the database in the Documents folder (e.g. using documentsPath).
Now, if you ever attempted to open a database in Documents without first copying from the bundle, the standard sqlite3_open will create a blank database. So, you probably want to delete the app from the device/simulator and then reinstall, to get rid of that blank database in Documents (otherwise the above logic, testing for the existence of the database in Documents, will result in false positive).

Is Core Data Lightweight Migration, on Lion, not saving a backup file?

Previously, when you did a lightweight migration, core data created a backup file in the same folder like ~yourFile. But using Lion, I can't find this backup file. Is the file hided somewhere? I did look the documentation, but without success.
Any help would be appreciated.
Many thanks
Mario
It seems the ˜file is no more automatically created. So the solution I found is to create the file programatically.
So, I'm posting my solution
// Determine if a migration is needed
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:url error:&error];
NSManagedObjectModel *destinationModel = [persistentStoreCoordinator managedObjectModel];
BOOL pscCompatibile = [destinationModel isConfiguration:nil compatibleWithStoreMetadata:sourceMetadata];
// if migration is needed, copy the file appending OLD to the original name
if (pscCompatibile == 0) {
NSLog(#"doing migration");
NSURL *urlOld = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: #"AudioStManDataOLD"]];
[[NSFileManager defaultManager] copyItemAtURL:url toURL:urlOld error:&error];
}
tx
Mario

How to properly save a QTMovie after editing using QTKit?

I am making minor edits to a QTMovie in an application using NSDocument architecture (such as adding a track, as shown below). After the edit, I want to save to the original file. However, I keep getting a 'file is busy' error. I assume this is due to some oversight I made in the handling of the files, or a failure in how I am using NSDocument. Any tips would be helpful! Here is (some of) the relevant code:
// open file that has the track I want to add to my movie
QTMovie* tempMovie = [QTMovie movieWithURL:outputFileURL error:nil];
// Use old API to add the track
AddMovieSelection([movie quickTimeMovie], [tempMovie quickTimeMovie]);
// get the filename from the NSDocument
NSString *filename = [[self fileURL] path];
NSLog(#"writing to filename: %#", filename);
// FLATTEN the movie file so I don't get external references
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:1];
[attributes setObject:[NSNumber numberWithBool:YES] forKey:QTMovieFlatten];
// attempt to write
NSError *error;
// this is where I get the "file is busy"
if (![movie writeToFile:filename withAttributes:attributes error:&error]) {
NSLog(#"Error: %#", [error localizedDescription]);
NSRunAlertPanel(#"Error", [error localizedDescription], nil, nil, nil);
}
Do I have to first release the movie in my NSDocument? What is the "proper" way to do that? Keep in mind, I am not necessarily finished with this document, I am not closing it. I have just finished this operation, and I want the file on disk to reflect my changes. I would love to use [movie updateMovieFile], but that call doesn't seem to flatten the movie. I don't want any external references in my file.
I am not too familiar with the QuickTime C API, so I honestly can't tell you anything about what is going wrong there. Absolute guesswork: Maybe a call to EndMediaEdits is missing?
Though that shouldn't be required by AddMovieSelection, you said "[...] such as adding a track [...]". So maybe there is something else going on, like AddMediaSample or something similar?
That said, if you don't need to target anything below 10.5 and all you need to do is add some segment from another movie, you can achieve that without dropping down to the C API:
Have a look at
-[QTMovie insertSegmentOfTrack:fromRange:scaledToRange:]
and
-[QTMovie insertSegmentOfMovie:fromRange:scaledToRange:], if you want to have the inserted segment "overlayed" (temporally speaking).
-[QTMovie insertSegmentOfMovie:timeRange:atTime:] and -[QTMovie insertSegmentOfTrack:timeRange:atTime:], if you want { movieA.firstPart, movieB, movieA.secondPart }.
Do I have to first release the movie in my NSDocument?
You mean in order to write it to disk? No: That should even result in a crash.
The role of release is to handle memory-management. It doesn't have much to do with the busy-state of a file.
Turns out I just wasn't using the NSDocument architecture properly. When I changed it to use Save/SaveAs properly, this problem went away.

how to pass local path to NSXMLParser

how to pass local path to NSXMLParser
like this
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:storePath];
where storepath is a local path like this:
/var/mobile/Applications/56EEB906-2B73-493C-9BE7-2732440CDB69/Documents/xml1.php
and my code is like this:
//NSURL *urla = [[NSURL alloc] initWithString:storePath];
NSURL *urla = [[[NSURL alloc] init] fileURLWithPath:storePath];
//NSData *dataa = [NSData dataWithContentsOfURL:urla];
NSLog(#"urls ois %#",urla);
help me why i am getting null value
Hey THis all some what not fair.
i suggest this, very simple
NSString *path=#"/Users/farshore/Desktop/prasanna/XMLParsing/Books-6.xml"; //this is ur path of xml file
NSURL *url = [[NSURL alloc] initFileURLWithPath:path];
Try this one:
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask, YES
);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSURL *urla = [NSURL fileURLWithPath:[documentsDirectory
stringByAppendingString:#"/xml1.php"]];
More details at iPhone Application Programming Guide: Getting Paths to Application Directories.
Update: There's a common misunderstanding what stringByTrimmingCharactersInSet. It does not replace all whitespace in the string, it only removes leading and trailing whitespace.
If you want to get rid of the spaces, you need to replace them yourself by using something like stringByReplacingCharactersInRange:withString:.
However:
I am not sure what you would replace those strings with to get a valid path. As far as I know, on the simulator the path to the application's Documents folder actually has spaces in it (which accidentally is called out in the document I linked).
I am not sure why would the spaces bother you. That string is a valid path (as long as you actually have created the <app>/Documents/xml1.php file, of course); and according to NSXMLParser documentation, initWithContentsOfUrl accepts any fully qualified URL with scheme supported by NSURL, and file:// is supported scheme.
If there's a particular error the NSXMLParser is returning, add it to your question (or ask another one), so we can help you with the actual problem.
My guess would be because you're reading the PHP file directly instead of passing it through PHP so the output isn't XML.

How do I download contents into an NSData using a Secure URL?

I'm starting with the following snip to download an image
NSError *error = nil;
NSString *url = #"https://...";
[NSData dataWithContentsOfURL:[NSURL urlWithString:url] options:nil error:&error];
When this code runs, the error instance contains an error without a whole lot of information in the userInfo. It's just the secure url that was attempted.
Given the results, I'm pretty sure these methods don't handle secure URLs.
My question:
Is there an easy way (like these
methods, or some option) to set the
dataWithContentsOfURL: method to download over a secure url?
Try running your URL through this first

Resources