简体   繁体   中英

method for performing lot of read/write operations on a database

I am developing an iPad application where I would have to perform a lot of read/write operations on a database(i have to store the clicks on the view in a database nad based on the clicks make perform some operations). I am confused as to how to proceed in this case. Should I just create a SQLIte database and perform the read/writes(will this slow down the response time of the app??) or is there some other technique(i have heard of Core data but not sure if this work for my case). Please help me

Thanks

Ajith

If you are only going to save them in order, and then read them back in the same order, maybe a regular file would be best. If, however, you are going to do anything else, use CoreData. It is not just a relational database. It allows persistent object graphs. Also, if you use UIManagedDocument, or your own parent/child NSManagedObjectContext arrangement, you will not even see the database hit, because it will all happen in a background thread.

Go ahead, and test it out. Override the begin/move/end touches, and throw objects into the database on every touch. If you are doing it as I describe, you won't even notice the database hit.

Assumes two entities in the model, MyTouchEvent and MyTouch, where MyTouchEvent has one-to-many relationship with MyTouch.

// Call this from touchesBegan, touchesMoved, and touchesEnded...
- (void) saveTouches:(NSSet*)touches kind:(NSString*)kind
{
    NSManagedObjectContext *moc = self.document.managedObjectContext;
    MyTouchEvent *myTouchEvent = [NSEntityDescription insertNewObjectForEntityForName:@"MyTouchEvent" inManagedObjectContext:moc];
    myTouchEvent.kind = kind;
    for (UITouch *touch in touches) {
        CGPoint touchPoint = [touch locationInView:self];
        MyTouch *myTouch = [NSEntityDescription insertNewObjectForEntityForName:@"MyTouch" inManagedObjectContext:moc];
        myTouch.x = [NSNumber numberWithFloat:touchPoint.x];
        myTouch.y = [NSNumber numberWithFloat:touchPoint.y];
        [myTouchEvent addTouchesObject:myTouch];
    }
    [self.document updateChangeCount:UIDocumentChangeDone];
}

If your object creation is expensive, you can add a method to create a private context, and do all the work in there, with two options. You can parent it to the main context of the document, in which case, all you have to do is embed the code in a block, and call save on the MOC...

- (NSManagedObjectContext*)moc
{
    if (!_moc) {
        _moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        _moc.parentContext = self.document.managedObjectContext;
    }
    return _moc;
}
- (void) saveTouches:(NSSet*)touches kind:(NSString*)kind
{
    NSManagedObjectContext *moc = self.moc;
    [self.moc preformBlock:^{
        MyTouchEvent *myTouchEvent = [NSEntityDescription insertNewObjectForEntityForName:@"MyTouchEvent" inManagedObjectContext:moc];
        myTouchEvent.kind = kind;
        for (UITouch *touch in touches) {
            CGPoint touchPoint = [touch locationInView:self];
            MyTouch *myTouch = [NSEntityDescription insertNewObjectForEntityForName:@"MyTouch" inManagedObjectContext:moc];
            myTouch.x = [NSNumber numberWithFloat:touchPoint.x];
            myTouch.y = [NSNumber numberWithFloat:touchPoint.y];
            [myTouchEvent addTouchesObject:myTouch];
        }
        NSError *error = nil;
        [moc save:&error];
    }];
}

Or, you could make it a sibling, in which case none of the DB stuff runs on the main thread at all (the main context of a UIManagedDocument runs on the main thread, so in the above case, the main thread will pass the objects to the context that does the save). However, in this case, your document.managedObjectContext will have to do a FETCH to get anything that was put into the database. However, it causes no performance to the main thread during the storage.

- (NSManagedObjectContext*)moc
{
    if (!_moc) {
        _moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        _moc.parentContext = self.document.parentContext;
    }
    return _moc;
}

Now, these will go to the database, but if your document wants to see them, it will have to perform a fetch. Pick which is best based on your use-case. I imagine you will be just fine with the first example, though.

If there are a lot of clicks, you definitely don't want to write each of them to the database separately. Perhaps, it would be a good compromise to accumulate mouse actions and save them on -mouseUp: event.

Core Data may help a bit here by simplifying the procedure. It lets you create objects pretty fast and defer saving them to the persistent store. However you can achieve the same effect with SQLite if you install a CFRunLoopObserver , wait until there are no events and write a batch of data to the database.

Whatever you choose, the strategy is to accumulate clicks and save them in batches.

Your best bet is to stream your actions to a file on the file system. Then you can either leave it there or if you really need to, upload it into SQLite via Core Data. The reason for this is that if you commit your ManagedObjectContext for every even, things will run really really slow.

Use: backingFile = [NSFileHandle fileHandleForUpdatingAtPath:eventsFilePath]; to append your events to using [backingFile writeData:...];

Remember that the primary purpose of a relational database is to 'search' through the data. If you're not going to search through your UI click events (which I doubt you would), then streaming to a file is your best bet.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM