I am using Core Data for the first time and was just curious if what I am seeing is correct. Each time I run the application via Xcode it reports that the database, exists, is closed, and is being opened. The next time I run the app the same happens ...
My question is, I am not closing the database myself and I was just curious if I have something wrong somewhere or if iOS is closing the database itself.
EDIT_001: Code Added.
- (void)viewDidLoad {
[super viewDidLoad];
if([self planetDatabase] == nil) {
// CREATE MANAGED DOCUMENT
NSLog(#"Database: Setup");
NSArray *userDocumentPath = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *databaseFileURL = [[userDocumentPath lastObject] URLByAppendingPathComponent:#"DefaultPlanetDatabase"];
[self setPlanetDatabase:[[UIManagedDocument alloc] initWithFileURL:databaseFileURL]];
// CHECK FOR EXISTING
if([[NSFileManager defaultManager] fileExistsAtPath:[databaseFileURL path]]) {
// OPEN IF CLOSED
if([[self planetDatabase] documentState] == UIDocumentStateClosed) {
NSLog(#"Database: Closed");
[[self planetDatabase] openWithCompletionHandler:^(BOOL success) {
if(success)[self doWhatsNext];
}];
// USE IF NORMAL
} else if([[self planetDatabase] documentState] == UIDocumentStateNormal) {
[self doWhatsNext];
}
// CREATE AND OPEN
} else {
[[self planetDatabase] saveToURL: [[self planetDatabase] fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
if(success)[self doWhatsNext];
}];
}
}
}
The first time I run this code from within Xcode the database is created "CREATE AND OPEN" the next time I run this code "OPEN IF CLOSED" is called. I assume this is correct, but am just trying to verify that Xcode does indeed close the open database between builds.
The SQLite database is not like, say MySQL. It's not a server running somewhere. It's just code inside your app. Hence, when you add a NSPersistenStore, the database is opened, and when your app shuts down, the database will be closed. That's how SQLite works.
Xcode doesn't do anything to your database. It's just your app touching it.
Related
http://www.fileconvoy.com/dfl.php?id=g021ae486d8d8acb3999343609097fcba7f7befa53
this is the link to an assignment app which i got for my homework it most of its concepts taken from the stanford cs193p course as iam studing that too, this app has 3 modules
1 camera
2 map
3 contacts
the camera and map modules are working fine not as hoped but fine cut in the contacts module I
am using core data model to store contacts from contacts directory which you'll see when you run the app.
Now the problem is that my view adds the contacts to the core data but they are not showing in the table so when i tried to debug the application i saw that the method
[self.managedObjectContext performBlockAndWait:^{}];
is not calling the block of code inside it thats why the data is not even getting saved in the data model let alone show in table.
very very thanks in advance...
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:#"Demo Document"];
UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:url];
if (![[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
[document saveToURL:url
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success) {
if (success) {
self.managedObjectContext = document.managedObjectContext;
}
}];
} else if (document.documentState == UIDocumentStateClosed) {
[document openWithCompletionHandler:^(BOOL success) {
if (success) {
self.managedObjectContext = document.managedObjectContext;
}
}];
} else {
self.managedObjectContext = document.managedObjectContext;
}
if(self.managedObjectContext==nil)
NSLog(#"nil object");
I am using CMIS(Content management interoperability services) to download data from the alfresco server. I am using the following code and it works fine to some extent but when the application goes to background, the network connection is lost and when the app comes to foreground, it tries to retry the download and fails saying connection error. As I am a newbie any help will be much appreciated.
- (void)testFileDownload
{
[self runTest:^
{
[self.session retrieveObjectByPath:#"/ios-test" completionBlock:^(CMISObject *object, NSError *error) {
CMISFolder *testFolder = (CMISFolder *)object;
STAssertNil(error, #"Error while retrieving folder: %#", [error description]);
STAssertNotNil(testFolder, #"folder object should not be nil");
CMISOperationContext *operationContext = [CMISOperationContext defaultOperationContext];
operationContext.maxItemsPerPage = 100;
[testFolder retrieveChildrenWithOperationContext:operationContext completionBlock:^(CMISPagedResult *childrenResult, NSError *error) {
STAssertNil(error, #"Got error while retrieving children: %#", [error description]);
STAssertNotNil(childrenResult, #"childrenCollection should not be nil");
NSArray *children = childrenResult.resultArray;
STAssertNotNil(children, #"children should not be nil");
STAssertTrue([children count] >= 3, #"There should be at least 3 children");
CMISDocument *randomDoc = nil;
for (CMISObject *object in children)
{
if ([object class] == [CMISDocument class])
{
randomDoc = (CMISDocument *)object;
}
}
STAssertNotNil(randomDoc, #"Can only continue test if test folder contains at least one document");
NSLog(#"Fetching content stream for document %#", randomDoc.name);
// Writing content of CMIS document to local file
NSString *filePath = [NSString stringWithFormat:#"%#/testfile", NSTemporaryDirectory()];
// NSString *filePath = #"testfile";
[randomDoc downloadContentToFile:filePath
completionBlock:^(NSError *error) {
if (error == nil) {
// Assert File exists and check file length
STAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath], #"File does not exist");
NSError *fileError = nil;
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&fileError];
STAssertNil(fileError, #"Could not verify attributes of file %#: %#", filePath, [fileError description]);
STAssertTrue([fileAttributes fileSize] > 10, #"Expected a file of at least 10 bytes, but found one of %d bytes", [fileAttributes fileSize]);
// Nice boys clean up after themselves
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&fileError];
STAssertNil(fileError, #"Could not remove file %#: %#", filePath, [fileError description]);
} else {
STAssertNil(error, #"Error while writing content: %#", [error description]);
}
self.testCompleted = YES;
} progressBlock:nil];
}];
}];
}];
}
The connection fail doesn't occurs when the user presses the home key. It fails only when the magnetic cover lid is closed or when there is a timeout.
When an app is moved to background, the OS gives the app 5s to finish what it is doing before it is suspended (keeps RAM, but stops the app receiving any messages or doing anything). If you have a task that needs to run to completion when the user presses the home button, you can use a background task. From apple's documentation:
Your app delegate’s applicationDidEnterBackground: method has
approximately 5 seconds to finish any tasks and return. In practice,
this method should return as quickly as possible. If the method does
not return before time runs out, your app is killed and purged from
memory. If you still need more time to perform tasks, call the
beginBackgroundTaskWithExpirationHandler: method to request background
execution time and then start any long-running tasks in a secondary
thread. Regardless of whether you start any background tasks, the
applicationDidEnterBackground: method must still exit within 5
seconds.
Note: The UIApplicationDidEnterBackgroundNotification notification is
also sent to let interested parts of your app know that it is entering
the background. Objects in your app can use the default notification
center to register for this notification.
From http://developer.apple.com/library/ios/#documentation/iphone/conceptual/iphoneosprogrammingguide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html
USE Reachability code Try this code to save data once downloaded:
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//try to access that local file for writing to it...
NSFileHandle *hFile = [NSFileHandle fileHandleForWritingAtPath:self.localPath];
//did we succeed in opening the existing file?
if (!hFile)
{ //nope->create that file!
[[NSFileManager defaultManager] createFileAtPath:self.localPath contents:nil attributes:nil];
//try to open it again...
hFile = [NSFileHandle fileHandleForWritingAtPath:self.localPath];
}
//did we finally get an accessable file?
if (!hFile)
{ //nope->bomb out!
NSLog("could not write to file %#", self.localPath);
return;
}
//we never know - hence we better catch possible exceptions!
#try
{
//seek to the end of the file
[hFile seekToEndOfFile];
//finally write our data to it
[hFile writeData:data];
}
#catch (NSException * e)
{
NSLog("exception when writing to file %#", self.localPath);
result = NO;
}
[hFile closeFile];
}
I am using Core Data to store a few simple strings related to each user. When the app first starts, everything seems to be fine. The database opens, and I am successfully able to save and retrieve data.
However, after some usage, sometimes the UIManagedDocument I use will just not open when the app starts. Here is the method I use for that (done in the app delegate):
-(void)initManagedDocument{
#try {
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:#"DataBase"];
self.managedDocument = [[UIManagedDocument alloc] initWithFileURL:url];
if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]]){
[self.managedDocument openWithCompletionHandler:^(BOOL success){
if (success) {
[self documentIsReady];
}else{
NSLog(#"Could not open document");
}
}];
}else{
[self.managedDocument saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){
if (success) {
[self documentIsReady];
}else{
NSLog(#"Could not create document");
}
}];
}
}
#catch (NSException *e) {
}
}
This code gets called from my app's didFinishLaunchingWithOptions. The saveToURL half of the if-statement gets called initially, and returns a success. Then in the following few calls the openWithCompletionHandler: gets called, and returns successfully.
However, at some point after using the app for awhile, the openWithCompletionHandler: returns success = FALSE. I am not sure why, or how the UIManagedDocument gets messed up. The URL still seems to be the same, and the fileExistsAtPath is still returning YES.
Does anyone know why this might be happening? Or if there is a way for me to debug and find out what the actual error is that is causing the open to fail?
I am working with a core database, it is working in IOS 6 but when I trying to test it on IOS 5. It does not do anything. Let me explain what I'm doing.
First I do this in my viewWillAppear.
- (void)viewWillAppear:(BOOL)animated
{
NSLog(#"view appeared");
[super viewWillAppear:animated];
if (!self.genkDatabase) {
NSLog(#"comes to here");
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:#"Default appGenk Database2"];
// url is now "<Documents Directory>/Default Photo Database"
self.genkDatabase = [[UIManagedDocument alloc] initWithFileURL:url]; // setter will create this for us on disk
NSLog(#"database created on disk");
}
}
Then it comes in the UseDocument method.
- (void)useDocument
{
NSLog(#"Comses in the use document");
if (![[NSFileManager defaultManager] fileExistsAtPath:[self.genkDatabase.fileURL path]]) {
// does not exist on disk, so create it
[self.genkDatabase saveToURL:self.genkDatabase.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
NSLog(#"create");
[self setupFetchedResultsController];
[self fetchGenkDataIntoDocument:self.genkDatabase];
}];
} else if (self.genkDatabase.documentState == UIDocumentStateClosed) {
NSLog(#"closed news");
// exists on disk, but we need to open it
[self.genkDatabase openWithCompletionHandler:^(BOOL success) {
[self setupFetchedResultsController];
}];
} else if (self.genkDatabase.documentState == UIDocumentStateNormal) {
NSLog(#"normal");
// already open and ready to use
[self setupFetchedResultsController];
}
}
And finally it goes into the setDatabase Method.
- (void)setGenkDatabase:(UIManagedDocument *)genkDatabase
{
if (_genkDatabase != genkDatabase) {
_genkDatabase = genkDatabase;
[self useDocument];
}
NSLog(#"Comes in the setdatabase methode.");
}
Doing all this gives the following log.
2012-10-22 10:42:47.444 RacingGenk[4786:c07] view appeared
2012-10-22 10:42:47.445 RacingGenk[4786:c07] comes to here
2012-10-22 10:42:47.459 RacingGenk[4786:c07] Comses in the use document
2012-10-22 10:42:47.460 RacingGenk[4786:c07] Comes in the setdatabase methode.
2012-10-22 10:42:47.461 RacingGenk[4786:c07] database created on disk
Like you can see it does not print the create log in my use document. So it isn't able to execute the method FetchDataIntoDocument.
Can anybody help me with this problem. I am searching at this problem for ages for now.
Many thanks in advace.
Stef
Are you testing with the simulator or on the device?
The simulator is case-insensitive - the device is case-sensitive on file access, remember that!
But beside from that the documentation for NSFileManager recommends not checking to see if files exist, and instead just trying to read the file and handle any errors gracefully (e.g. file not found error). So just try loading the file instead of checking to see if it exists.
And i don't see any file extension for your database file! It just states ""Default appGenk Database2".
Is this already the file name or jut another subdirectory so far?
EDIT:
You can try the following code:
- (void) setupStore {
NSString* storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"mydatabase.sqlite"];
// Set up the store.
NSFileManager* fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, create one.
if (![fileManager fileExistsAtPath: storePath]) {
// create your store here!
}
}
- (NSString*) applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
"mydatabase.sqlite" is the name of the database-file you expect to be present in your documents directory.
If you would like to see a full-fledged example on how to set-up a core data persistent store you could check out apples own iPhoneCoreDataRecipes example. Just take a look at the
RecipesAppDelegate.m
implementation.
I'm using iCloud with core data to sync data of my App.
I tried everything and finally It works perfectly.
but I have one question.
Is there any way that saying to iCloud to sync?
It sync when app begin, but the other time. It seems like that it sync randomly. I can't find the way to handle it myself.
any help?
Thanks.
I figured out how to force a core data store to sync to iCloud. You just need to "touch" any receipt files in the Data folder in the Ubiquity filesystem. The code below will do this. To force a sync, call the syncCloud method. For every "receipt" file it finds, it will update the files modification time stamp to the current time, essentially doing a "touch" on the file. As soon as this happens, iCloud will check and sync any core data files that need synchronization in iCloud. Near as I can tell, this is how the simulator or Xcode does it when you select the "Trigger iCloud Sync" option.
#property (strong, nonatomic) NSMetadataQuery *query;
-(void) init
{
self.query = [[NSMetadataQuery alloc] init];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(didFinishMetadataQuery)
name: NSMetadataQueryDidFinishGatheringNotification
object: self.query];
}
-(void) didFinishMetadataQuery
{
// Query completed so mark it as completed
[self.query stopQuery];
// For each receipt, set the modification date to now to force an iCloud sync
for(NSMetadataItem *item in self.query.results)
{
[[NSFileManager defaultManager] setAttributes: #{NSFileModificationDate:[NSDate date]}
ofItemAtPath: [[item valueForAttribute: NSMetadataItemURLKey] path]
error: nil];
}
}
-(void) syncCloud
{
// Look for files in the ubiquity container data folders
[self.query setSearchScopes:#[NSMetadataQueryUbiquitousDataScope]];
// Look for any files named "receipt*"
[self.query setPredicate:[NSPredicate predicateWithFormat:#"%K like 'receipt*'", NSMetadataItemFSNameKey]];
// Start the query on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
BOOL startedQuery = [self.query startQuery];
if (!startedQuery)
{
NSLog(#"Failed to start query.\n");
return;
}
});
}
You have to force any NSURL item to be cached in iCloud with this method:
- (BOOL)addBackupAttributeToItemAtURL:(NSURL *)URL
{
NSLog(#"URL: %#", URL);
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: NO]
forKey: NSURLIsExcludedFromBackupKey error: &error];
return success;
}
You're need to launch this method on every directory and file you're downloading/creating in Documents or Library directory.
I don't believe that you have any control over when the sync will occur when using iCloud and core-data. With UIDocument and iCloud I have used startDownloadingUbiquitousItemAtURL with varying degrees of success but for core-data I don't think there is any equivalent -- I would love to hear someone tell me otherwise however...