0

I'm using UIManagedDocument to reading and writing to CoreData. I have Document class. This is a document from some tutorial:

.h

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

typedef void (^OnDocumentReady) (UIManagedDocument *document);

@interface Document : NSObject

@property (strong, nonatomic) UIManagedDocument *document;

+ (Document *)sharedDocument;
- (void)performWithDocument:(OnDocumentReady)onDocumentReady;

@end

.m

@interface Document ()
- (void)objectsDidChange:(NSNotification *)notification;
- (void)contextDidSave:(NSNotification *)notification;
@end;

@implementation Document

@synthesize document = _document;

static Document*_sharedInstance;

+ (Document *)sharedDocument
{
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        _sharedInstance = [[self alloc] init];
    });

    return _sharedInstance;
}

- (id)init {
    self = [super init];
    if (self) {
        NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
        url = [url URLByAppendingPathComponent:@"Document"];
        self.document = [[UIManagedDocument alloc] initWithFileURL:url];

        NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                                 [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
        self.document.persistentStoreOptions = options;

        // Register for notifications
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(objectsDidChange:)
                                                     name:NSManagedObjectContextObjectsDidChangeNotification
                                                   object:self.document.managedObjectContext];

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(contextDidSave:)
                                                     name:NSManagedObjectContextDidSaveNotification
                                                   object:self.document.managedObjectContext];
    }
    return self;
}

- (void)performWithDocument:(OnDocumentReady)onDocumentReady
{
    void (^OnDocumentDidLoad)(BOOL) = ^(BOOL success) {
        onDocumentReady(self.document);
    };

    if (![[NSFileManager defaultManager] fileExistsAtPath:[self.document.fileURL path]]) {
        [self.document saveToURL:self.document.fileURL
                forSaveOperation:UIDocumentSaveForCreating
               completionHandler:OnDocumentDidLoad];
    } else if (self.document.documentState == UIDocumentStateClosed) {
        [self.document openWithCompletionHandler:OnDocumentDidLoad];
    } else if (self.document.documentState == UIDocumentStateNormal) {
        OnDocumentDidLoad(YES);
    }
}

- (void)objectsDidChange:(NSNotification *)notification
{
#ifdef DEBUG
    NSLog(@"NSManagedObjects did change.");
#endif
}

- (void)contextDidSave:(NSNotification *)notification
{
#ifdef DEBUG
    NSLog(@"NSManagedContext did save.");
#endif
}

@end

Then in ViewController i have NSURLConnection:

-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
    DataParser *parser = [[DataParser alloc] init];
    [parser startParsingData:self.myMutableData withContext:self.moc];
}

and i open the document here:

-(void)initDocument {
    if (!self.moc) {
        [[Document sharedDocument] performWithDocument:^(UIManagedDocument *document) {
            self.moc = document.managedObjectContext;
            [[NSNotificationCenter defaultCenter] postNotificationName:UIDocumentStateChangedNotification object:self];

            NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"someURL"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60];
            [NSURLConnection connectionWithRequest:request delegate:self];
        }];
    }
}

Then i try to parse data:

-(void)startParsingData:(NSData*)data withContext:(NSManagedObjectContext*)context {
    self.moc = context;
    self.startDate = [NSDate date];
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    parser.delegate = self;
    [parser parse];
}

ant try to load it in core data after XML parsing:

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if([elementName isEqualToString:@"Item"]) {
            [self.moc performBlockAndWait:^{
                TestEntity *te = [NSEntityDescription insertNewObjectForEntityForName:@"TestEntity" inManagedObjectContext:self.moc];
                te.surname = @"5433fds";
                te.name = @"5342fdsfsd";
            }];
    }
}

And i see the logs:

2014-01-24 16:21:21.692 Ce[85149:70b] NSManagedObjects did change.
2014-01-24 16:21:36.696 Ce[85149:70b] NSManagedContext did save.

So i assume that this should be in sqlite file, but when I try to read it is completely empty. awl file have some bigger size, but persistentStore have 0 rows. Why?

Jakub
  • 13,712
  • 17
  • 82
  • 139
  • You gave us much information but I think it's missing how do you actually save parsed data (after -parser:didEndElement:…). – ppm Jan 25 '14 at 03:36

2 Answers2

3

What happens when you launch the app a second time, can you see the data in your app?

In iOS 7, SQLite now has journaling turned on. I wonder if the journalling is causing a confusion (data is there but not in the sqlite file yet).

I would also question why you are using a UIManagedDocument. It appears you are using Core Data in a Singleton pattern (which is bad) and then using UIManagedDocument in that singleton pattern (worse).

UIManagedDocument is intended for document based apps. You are probably running foul of some of the "automated" features inside of that class that would be easily cleared up if you built a standard Core Data stack instead.

You might consider turning Journaling off, adding a vacuum option to your NSPersistentStoreCoordinator or switch to a standard Core Data stack.

Marcus S. Zarra
  • 46,571
  • 9
  • 101
  • 182
  • Sorry for off topic question, but do you advise to avoid using singleton for CoreDataManager (some class that holds Core Data stack) at all? If so - what patter/approach you would recommend instead? Thanks in advance. – A.S. Jan 24 '14 at 18:35
  • Would be also interested in your approach. In this post http://www.cimgf.com/2011/01/07/passing-around-a-nsmanagedobjectcontext-on-the-iphone/ you are providing few examples, but what would be a good approach with UIManagedDocument? – Arthur Shinkevich Jan 24 '14 at 18:47
  • Don't use `UIManagedDocument`. There is no reason to use it unless you are writing a document based application. It *hurts* your development and introduces unknowns if you use it. – Marcus S. Zarra Jan 24 '14 at 19:28
  • @A.S. The best way to avoid using a singleton, Dependency Injection is the answer. See http://www.cimgf.com/2011/01/07/passing-around-a-nsmanagedobjectcontext-on-the-iphone/ that Arcanfel linked to. – Marcus S. Zarra Jan 24 '14 at 19:29
0

This is likely because of a new SQLite journal mode used in iOS 7. If you set it to the old mode as shown in the answer to the following SO question you should see your data again.

How to disable WAL journal mode

Community
  • 1
  • 1
Jesse
  • 1,667
  • 12
  • 16
  • Disabling Journal mode is not a silver bullet. If the application is working and the OP is just confused as to why he is not seeing the rows in SQLite *yet* then there is absolutely no reason to disable it. – Marcus S. Zarra Jan 24 '14 at 19:30
  • @MarcusS.Zarra True, but I'm finding that it's usually the cause with developers I work with. And it's also not widely understood. For example journaling needs to be disabled temporarily before creating seed stores. – Jesse Jan 24 '14 at 23:13