Core Data和NSFetchedResultsController的通用模型实现

时间:2016-01-31 15:21:49

标签: ios objective-c uitableview core-data

我是Core Data的新手。我把所有模型要求(关于MVC)放在一个NSFetchedResultsController类中,如下所示:

标题文件:

#import <CoreData/CoreData.h>

@interface GeneralModel : NSFetchedResultsController

@property (nonatomic, strong) NSManagedObjectContext *context;
@property (nonatomic, strong) NSManagedObjectModel *model;

- (NSString *)storagePath;
- (void)removeStorage;
- (void)truncateAllEntity;
- (void)truncateEntity:(NSString *)entityName;
- (void)addGroups:(NSDictionary *)insertData;
- (NSArray *)getEntity:(NSString *)entityName sortBy:(NSString *)sortAttribute;
- (id)getMaxValue:(NSString *)entityName forProperty:(NSString *)propertyName;
- (NSArray *)getEntity:(NSString *)entityName predicateBy:(NSPredicate *)predicate sortBy:( NSString * )sortAttribute;

@end

主档案:

#import "GeneralModel.h"
#import "GeneralHelper.h"

@implementation GeneralModel

- (instancetype)init
{
    self = [super init];
    if (self) {
        // Read in Model.xcdatamodeld
        _model = [NSManagedObjectModel mergedModelFromBundles:nil];
        NSPersistentStoreCoordinator *psc =
        [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_model];

        // Where does the SQLite file go?
        NSString *path = self.storagePath;
        NSURL *storeURL = [NSURL fileURLWithPath:path];
        NSError *error = nil;
        if (![psc addPersistentStoreWithType:NSSQLiteStoreType
                               configuration:nil
                                         URL:storeURL
                                     options:nil
                                       error:&error]) {
            @throw [NSException exceptionWithName:@"OpenFailure"
                                           reason:[error localizedDescription]
                                         userInfo:nil];
        }

        // Create the managed object context
        _context = [[NSManagedObjectContext alloc] init];
        _context.persistentStoreCoordinator = psc;

    }
    return self;
}

- (NSString *)storagePath
{
    NSArray *documentDirectories =
    NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                        NSUserDomainMask,
                                        YES);
    // Get one and only document directory from that list
    NSString *documentDirectory = [documentDirectories firstObject];
    return [documentDirectory stringByAppendingPathComponent:@"model.sqlite"];
}

- (void)removeStorage {

//    NSError *error2;
//    NSString *storagePath = [self storagePath];
//    
//    NSDictionary *options = @{NSPersistentStoreUbiquitousContentNameKey: @"model"};
//    bool removeResult = [NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:[NSURL URLWithString:storagePath] options:options error:&error2];
//    if (removeResult == NO) {
//        NSLog(@"Could not remove Storage. Reason: %@", error2.localizedFailureReason);
//    }


    NSPersistentStore *store = [self.context.persistentStoreCoordinator.persistentStores lastObject];
    NSError *error = nil;
    NSURL *storeURL = store.URL;
    BOOL isRemovePersistentStore = [self.context.persistentStoreCoordinator removePersistentStore:store error:&error];
    if (isRemovePersistentStore == NO) {
        NSLog(@"NO RemovePersistentStore. Reason: %@", error.localizedFailureReason);
    }

    BOOL isRemoveItemAtURL = [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
    if (isRemoveItemAtURL == NO) {
        NSLog(@"NO RemoveItemAtURL. Reason: %@", error.localizedFailureReason);
    }
}

- (void)truncateAllEntity {
    NSArray *entities = self.model.entities;
    for (NSEntityDescription *entityDescription in entities) {
        [self truncateEntity:entityDescription.name];
    }
}

- (void)truncateEntity:(NSString *)entityName {
    // delete all database
    if (IOS_VERSION >= 9) {
        NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:entityName];
        NSBatchDeleteRequest *delete = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request];

        NSError *deleteError = nil;
        [self.context.persistentStoreCoordinator executeRequest:delete withContext:self.context error:&deleteError];

    } else {
        NSFetchRequest *allItems = [[NSFetchRequest alloc] init];
        [allItems setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:self.context]];
        [allItems setIncludesPropertyValues:NO]; //only fetch the managedObjectID

        NSError *error = nil;
        NSArray *items = [self.context executeFetchRequest:allItems error:&error];

        //error handling goes here
        for (NSManagedObject *item in items) {
            [self.context deleteObject:item];
        }
        NSError *saveError = nil;
        [self.context save:&saveError];
        //more error handling here
    }
    [self.context rollback];

}

- (void)addGroups:(NSDictionary *)insertData {

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

    for (NSDictionary *response in insertData) {

        NSManagedObject *existingGroup = [self getEntity:@"Group" AtValue:response[@"groupId"]  forProperty:@"group_id" ];

        if (existingGroup) {
            NSLog(@"existingGroup");
            continue;
        }

        //        for (int i; i<=20; i++) {

        // set bullet
        NSManagedObject *object_bullet = [NSEntityDescription insertNewObjectForEntityForName:@"Group_bullet"
                                                                       inManagedObjectContext:self.context];
        NSData *bulletData = [[NSData alloc] initWithBase64EncodedString:response[@"bullet"] options:NSDataBase64DecodingIgnoreUnknownCharacters];
        [object_bullet setValue:bulletData forKey:@"bullet"];
        [object_bullet setValue:response[@"groupId"] forKey:@"group_id"];

        // set group
        NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:@"Group"
                                                                inManagedObjectContext:self.context];

        [object setValue:object_bullet forKey:@"relatedBullet"];

//        NSDate *createDate = [dateFormatter dateFromString:response[@"createDate"]];
//        [object setValue:createDate forKey:@"group_created_date"];

        NSNumber *createDate = response[@"createDate"];
        [object setValue:[NSDate dateWithTimeIntervalSince1970:[createDate doubleValue]] forKey:@"group_created_date"];

        [object setValue:response[@"groupId"] forKey:@"group_id"];

        [object setValue:[GeneralHelper getInteger:response[@"memberNumber"]] forKey:@"group_members_count"];

        [object setValue:response[@"name"] forKey:@"group_name"];

        [object setValue:[GeneralHelper getInteger:response[@"privacy"]] forKey:@"group_privacy"];

        [object setValue:@1 forKey:@"group_status"];

        [object setValue:response[@"imageName"] forKey:@"image_name"];


        [object setValue:response[@"lastMessageId"] forKey:@"last_message_id"];

        [object setValue:response[@"lastMessageText"] forKey:@"last_message_text"];
//        
//        NSDate *lastMessageDate = [dateFormatter dateFromString:response[@"lastMessageDate"]];
//        [object setValue:lastMessageDate forKey:@"last_time"];

        NSNumber *lastMessageDate = response[@"lastMessageDate"];
        [object setValue:[NSDate dateWithTimeIntervalSince1970:[lastMessageDate doubleValue]] forKey:@"last_time"];

        [object setValue:response[@"machineId"] forKey:@"machine_id"];

        NSNumber *timestamp = response[@"timestamp"];
        [object setValue:[NSDate dateWithTimeIntervalSince1970:[timestamp doubleValue]] forKey:@"timestamp"];

        [object setValue:[GeneralHelper getInteger:response[@"unreadCount"]] forKey:@"unread_count"];

        //        }


    }

    NSError *errorInsert;
    if (![self.context save:&errorInsert]) {
        NSLog(@"Failed to save - error: %@", [errorInsert localizedDescription]);
    }

    [self.context rollback];
}

- (id)getMaxValue:(NSString *)entityName forProperty:(NSString *)propertyName {

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName];

    fetchRequest.fetchLimit = 1;
    fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:propertyName ascending:NO]];
    NSError *error = nil;

    id maxValue = [self.context executeFetchRequest:fetchRequest error:&error].firstObject;

    if (maxValue == nil) {
        maxValue = @{propertyName : @0};
    }

    [self.context rollback];

    return [maxValue valueForKey:propertyName];
}

- (id)getEntity:(NSString *)entityName AtValue:(NSString *)indexValue forProperty:(NSString *)propertyName {


    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:self.context];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", propertyName, indexValue];

//    NSLog(@"predicate: %@", predicate);
    [request setEntity:entity];
    [request setPredicate:predicate];
    [request setFetchLimit:1];

    NSError *error;
    NSArray *results = [self.context executeFetchRequest:request error:&error];
    NSManagedObject *object = [results firstObject];

    //    if (object) {
    //        // there is at least one object matching you predicate
    //    } else {
    //        // there is no object matching your predicate in the moc
    //    }

    //    NSLog(@"results member %@", results);
//    [self.context rollback];

    return object;
}

然后我在UITableViewController中使用这个通用模型。

有没有更好的方法呢?或者我的实施是错误的和没用的?

1 个答案:

答案 0 :(得分:0)

它认为这是一个很好的方法,但它有一些缺点。 NSFetchedResultsController负责,顾名思义用于控制获取的结果。如果添加删除和修改内容等功能,则会产生一个责任太多的对象。 想象一下,有一个viewController在tableview中显示结果。它只需要fetchedresultscontroller功能,仅此而已。如果通过点击单元格进入可以进行编辑的新视图控制器,则不需要fetchedresultscontroller:您需要使用managedObject进行编辑。这个editViewController可以使用tableViewController的子上下文,这样在取消时,只需丢弃子上下文就可以丢弃所有编辑。

我建议没有NSFetchedResultsController的子类,而是实现NSObject的子类,您可以使用NSNMagedObjectContext进行初始化,该NSNMagedObjectContext可以执行适用于整个上下文的操作。像添加组一样,删除所有数据等。 然后使用composition:这个NSObject子类可以是viewController的一个属性,所以viewCOntroller有一种方法可以做这些事情而不需要特定于这个viewController的这个操作。

通常,首先考虑组合而不是子类化。这是因为将组合对象的小组件转换为某个子类的对象通常比较容易。

随意不同意:),但这是我从很多人在很长的代码库上工作的经验中学到的。