iOS 网络请求Json自动转存到CoreData(一)

余生长醉 提交于 2020-03-06 14:05:51

奉上地址一枚:GitHub 并自带demo~

项目需求:从网络获取Json后,将Json自动转存到CoreData中。

本次任务:对CoreData封装,完成基本的增删改查,多线程操作。


我们总是在跌跌撞撞中,不断成长。

CoreDataActivity.h

//
//  CoreDataActivity.h
//  QGLCoreDataPlugin
//
//  Created by Guicai.Li on 14-10-16.
//  Copyright (c) 2014年 Guicai Li. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "DEBUG.h"
#import "NSFetchRequest+helper.h"
#import "NSManagedObject+helper.h"
#import "NSManagedObjectModel+helper.h"
#import "NSPersistentStoreCoordinator+helper.h"


@import CoreData;

@interface CoreDataActivity : NSObject
// Parent Context
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
// Child Context
@property (strong, nonatomic) NSManagedObjectContext *childManagedObjectContext;

@property (strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

+ (CoreDataActivity *)shareInstance;

- (NSManagedObjectContext *)createChildManagedObjectContext;

- (void)saveContext;

- (void)deleteWithEntity:(NSString *)entityName attributeName:(NSString *)attributeName value:(id)value;

- (void)updateWithEntity:(NSString *)entityName attributeName:(NSString *)attributeName oldValue:(id)oldValue newValue:(id)newValue;

- (NSArray *)attributeForEntity:(NSString *)entityName;
- (NSArray *)attributeForEntity:(NSString *)entityName sortByAttributeName:(NSString *)sortDescriptorName;



@end


CoreDataActivity.m

//
//  CoreDataActivity.m
//  QGLCoreDataPlugin
//
//  Created by Guicai.Li on 14-10-16.
//  Copyright (c) 2014年 Guicai Li. All rights reserved.
//

// References:
// http://cutecoder.org/featured/asynchronous-core-data-document/
// http://www.touchwonders.com/fast-and-non-blocking-core-data-back-end-programming/

#import "CoreDataActivity.h"


#warning mark - Change your CoreDataFileName
#define CoreDataFileName @"QGLCoreDataPlugin"


static CoreDataActivity *coreDataActivity = nil;

@implementation CoreDataActivity

#pragma mark - SingleInstance
+ (CoreDataActivity *)shareInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        coreDataActivity = [[CoreDataActivity alloc] init];
        [coreDataActivity initCoreData];
    });
    return coreDataActivity;
}

#pragma mark - Init for CoreData
- (void)initCoreData {
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator) {
        _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
        
        _childManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [_childManagedObjectContext setParentContext:_managedObjectContext];
    }
}

#pragma mark - Creating the parent context
// Just create your
// NSManagedObjectModel
// and
// NSPersistentStoreCoordinator
// as before

// Initialize the parent
// NSManagedObjectContext
// by setting its concurrency type to
// NSMainQueueConcurrencyType

//Set the persistentStoreCoordinator of the newly created context
- (NSManagedObjectContext *)managedObjectContext {
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _managedObjectContext;
}

- (NSManagedObjectModel *)managedObjectModel {
    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:[NSManagedObjectModel URLForManagedObjectModelName:CoreDataFileName]];
    return model;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSURL *storeURL = [NSPersistentStoreCoordinator URLForNSPersistentStoreCoordinatorName:CoreDataFileName];
    NSError *error = nil;
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        DLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    return persistentStoreCoordinator;
}

#pragma mark - Creating the child context

// Create a new
// NSManagedObjectContext
// with concurrency type
// NSPrivateQueueConcurrencyType

// Set its parentContext (setParentContext:) to the above created
// NSManagedObjectContext

- (NSManagedObjectContext *)childManagedObjectContext {
    if (_childManagedObjectContext) {
        return _childManagedObjectContext;
    }
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator) {
        _childManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [_childManagedObjectContext setPersistentStoreCoordinator:coordinator];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(childMergeChangesFromContextDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:_childManagedObjectContext];
    }
    return _childManagedObjectContext;
}

- (void)childMergeChangesFromContextDidSaveNotification:(NSNotification *)notification
{
    DLog(@"ChildContext did save.");
    [self performSelectorOnMainThread:@selector(mainMergeChangesFromContextDidSaveNotification:)
                           withObject:notification
                        waitUntilDone:YES];
}

- (void)mainMergeChangesFromContextDidSaveNotification:(NSNotification *)notification {
    [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}


- (NSManagedObjectContext *)createChildManagedObjectContext {
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [context setParentContext:_managedObjectContext];
    return context;
}

#pragma mark -SaveContext
//MARK:Consider about synchronous or asynchronous
/*
 When you cannot guarantee to conform to thread confinement (or you just want to be sure). One can pass a block which does some heavy work using the desired managedObjectContext and Core Data will automatically schedule the block for execution and uses the correct thread. Depending on which function is called the operation will be synchronous (
 performBlockAndWait:
 ) or asynchronous (
 performBlock:
 ).
 */

- (void)saveContext {
//TODO:First sava childManagedObjectContext and then save the main Quene's managedObjectContext.

//    NSError *error = nil;
//    if ([_managedObjectContext hasChanges] && ![_managedObjectContext save:&error]) {
//        ELog(error);
//        abort();
//    }
    
//BETTER:It's better using performBlock rather than performBlockAndWait.Or you will wait for the block to be performed.
    [self.childManagedObjectContext performBlock:^{
        NSError *error = nil;
        [self.childManagedObjectContext save:&error];
        
        [self.managedObjectContext performBlock:^{
            NSError *parentError = nil;
            [self.managedObjectContext save:&parentError];
        }];
    }];
}

/*
 ========================================================================================================================
Things to remember:

After creating or modifying a
NSManagedObject
save to its managedObjectContext to keep everything in sync!
Objects created in one managedObjectContext cannot be used in another managedObjectContext without triggering an exception. Always convert them to the managedObjectContext you want to use them in. Check out the github link down below for some sample code.
 ========================================================================================================================
*/

// Normal Operation

- (void)deleteWithEntity:(NSString *)entityName attributeName:(NSString *)attributeName value:(id)value {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K = %@", attributeName, value];
    NSFetchRequest *fetchRequst = [NSFetchRequest fetchRequestWithManagedObjectContext:self.managedObjectContext EntityName:entityName SortByAttributeName:attributeName Predicate:predicate];
    NSError *error = nil;
    NSArray *resultArray = [self.managedObjectContext executeFetchRequest:fetchRequst error:&error];
    if (error) {
        ELog(error);
    }
    if ([resultArray count]) {
        for (id obj in resultArray) {
            [self.managedObjectContext deleteObject:obj];
        }
    }
    [self saveContext];
}

- (void)updateWithEntity:(NSString *)entityName attributeName:(NSString *)attributeName oldValue:(id)oldValue newValue:(id)newValue {
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K = %@", attributeName, oldValue];
    NSFetchRequest *fetchRequst = [NSFetchRequest fetchRequestWithManagedObjectContext:self.managedObjectContext EntityName:entityName SortByAttributeName:attributeName Predicate:predicate];
    NSError *error = nil;
    NSArray *resultArray = [self.managedObjectContext executeFetchRequest:fetchRequst error:&error];
    if (error) {
        ELog(error);
    }
    if ([resultArray count]) {
        for (int i = 0; i < [resultArray count]; i ++) {
            [[resultArray objectAtIndex:i] setValue:newValue forKey:attributeName];
        }
    }
    [self saveContext];
}

- (NSArray *)attributeForEntity:(NSString *)entityName {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:entityName];
    return [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
}

- (NSArray *)attributeForEntity:(NSString *)entityName sortByAttributeName:(NSString *)sortDescriptorName {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithManagedObjectContext:self.managedObjectContext EntityName:entityName SortDescriptorName:sortDescriptorName];
    return [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
}



@end


对NSFetchRequest扩展:

NSFetchRequest+helper.h

//
//  NSFetchRequest+helper.h
//  QGLCoreDataPlugin
//
//  Created by Guicai.Li on 14-10-17.
//  Copyright (c) 2014年 Guicai Li. All rights reserved.
//

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

@interface NSFetchRequest (helper)

//TODO:

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName;

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName SortDescriptorName:(NSString *)sortDescriptorName;


//TODO:Using NSPredicate

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName Predicate:(NSPredicate *)predicate;

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName Predicate:(NSPredicate *)predicate Offset:(NSInteger)offset;

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName Predicate:(NSPredicate *)predicate Limit:(NSInteger)limit;

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName Predicate:(NSPredicate *)predicate Offset:(NSInteger)offset Limit:(NSInteger)limit;

//TODO:Using NSPredicate and SortDescriptorName

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName SortByAttributeName:(NSString *)sortDescriptorName Predicate:(NSPredicate *)predicate;

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName SortByAttributeName:(NSString *)sortDescriptorName Predicate:(NSPredicate *)predicate Offset:(NSInteger)offset;

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName SortByAttributeName:(NSString *)sortDescriptorName Predicate:(NSPredicate *)predicate Limit:(NSInteger)limit;

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName SortByAttributeName:(NSString *)sortDescriptorName Predicate:(NSPredicate *)predicate Offset:(NSInteger)offset Limit:(NSInteger)limit;
@end


NSFetchRequest+helper.m

//
//  NSFetchRequest+helper.m
//  QGLCoreDataPlugin
//
//  Created by Guicai.Li on 14-10-17.
//  Copyright (c) 2014年 Guicai Li. All rights reserved.
//

#import "NSFetchRequest+helper.h"

@implementation NSFetchRequest (helper)


+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName {
    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:contect];
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:entity];
    
    [fetchRequest setReturnsObjectsAsFaults:NO];
    
    return fetchRequest;
}

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName SortDescriptorName:(NSString *)sortDescriptorName {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithManagedObjectContext:contect EntityName:entityName];
    if (sortDescriptorName && ![sortDescriptorName isEqualToString:@""]) {
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortDescriptorName ascending:YES];
        NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
        [fetchRequest setSortDescriptors:sortDescriptors];
    }
    return fetchRequest;
}

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName Predicate:(NSPredicate *)predicate {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithManagedObjectContext:contect EntityName:entityName];
    [fetchRequest setPredicate:predicate];
    return fetchRequest;
}

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName Predicate:(NSPredicate *)predicate Offset:(NSInteger)offset {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithManagedObjectContext:contect EntityName:entityName Predicate:predicate];
    if (offset > 0) {
        [fetchRequest setFetchOffset:offset];
    }
    return fetchRequest;
}

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName Predicate:(NSPredicate *)predicate Limit:(NSInteger)limit {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithManagedObjectContext:contect EntityName:entityName Predicate:predicate];
    if (limit > 0) {
        [fetchRequest setFetchLimit:limit];
    }
    return fetchRequest;
}

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName Predicate:(NSPredicate *)predicate Offset:(NSInteger)offset Limit:(NSInteger)limit {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithManagedObjectContext:contect EntityName:entityName Predicate:predicate];
    if (offset > 0) {
        [fetchRequest setFetchOffset:offset];
    }
    if (limit > 0) {
        [fetchRequest setFetchLimit:limit];
    }
    return fetchRequest;
}

//TODO:Using NSPredicate and SortDescriptorName

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName SortByAttributeName:(NSString *)sortDescriptorName Predicate:(NSPredicate *)predicate {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithManagedObjectContext:contect EntityName:entityName Predicate:predicate];
    if (sortDescriptorName && ![sortDescriptorName isEqualToString:@""]) {
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortDescriptorName ascending:YES];
        NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
        [fetchRequest setSortDescriptors:sortDescriptors];
    }
    return fetchRequest;
}

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName SortByAttributeName:(NSString *)sortDescriptorName Predicate:(NSPredicate *)predicate Offset:(NSInteger)offset {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithManagedObjectContext:contect EntityName:entityName SortByAttributeName:sortDescriptorName Predicate:predicate];
    if (offset > 0) {
        [fetchRequest setFetchOffset:offset];
    }
    return fetchRequest;
}

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName SortByAttributeName:(NSString *)sortDescriptorName Predicate:(NSPredicate *)predicate Limit:(NSInteger)limit {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithManagedObjectContext:contect EntityName:entityName SortByAttributeName:sortDescriptorName Predicate:predicate];
    if (limit > 0) {
        [fetchRequest setFetchLimit:limit];
    }
    return fetchRequest;
}

+ (NSFetchRequest *)fetchRequestWithManagedObjectContext:(NSManagedObjectContext *)contect EntityName:(NSString *)entityName SortByAttributeName:(NSString *)sortDescriptorName Predicate:(NSPredicate *)predicate Offset:(NSInteger)offset Limit:(NSInteger)limit {
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithManagedObjectContext:contect EntityName:entityName SortByAttributeName:sortDescriptorName Predicate:predicate];
    if (offset > 0) {
        [fetchRequest setFetchOffset:offset];
    }
    if (limit > 0) {
        [fetchRequest setFetchLimit:limit];
    }
    return fetchRequest;
}
@end


对NSManagedObject的扩展:

NSManagedObject+helper.h

//
//  NSManagedObject+helper.h
//  QGLCoreDataPlugin
//
//  Created by Guicai.Li on 14-10-16.
//  Copyright (c) 2014年 Guicai Li. All rights reserved.
//

#import <Foundation/Foundation.h>

@import CoreData;

@interface NSManagedObject (helper)

+ (id)createNSManagedObjectForName:(NSString *)name;

+ (void)deleteNSManagedObject:(id)object;


@end

//
//  NSManagedObject+helper.m
//  QGLCoreDataPlugin
//
//  Created by Guicai.Li on 14-10-16.
//  Copyright (c) 2014年 Guicai Li. All rights reserved.
//


#import "NSManagedObject+helper.h"
#import "CoreDataActivity.h"

@implementation NSManagedObject (helper)

+ (id)createNSManagedObjectForName:(NSString *)name {
//TODO:To judge whether the Main Thread. This is importmeng!
    CoreDataActivity *coreDateActivity = [CoreDataActivity shareInstance];
    NSManagedObjectContext *context = [NSThread mainThread] ? coreDateActivity.managedObjectContext : coreDateActivity.childManagedObjectContext;
    
    return [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:context];
}

+ (void)deleteNSManagedObject:(id)object {
    [[CoreDataActivity shareInstance].managedObjectContext deleteObject:object];
}

@end


对NSManagedObjectModel的扩展:

NSManagedObjectModel+helper.h

//
//  NSManagedObjectModel+helper.h
//  QGLCoreDataPlugin
//
//  Created by Guicai.Li on 14-10-16.
//  Copyright (c) 2014年 Guicai Li. All rights reserved.
//

#import <Foundation/Foundation.h>

@import CoreData;

@interface NSManagedObjectModel (helper)

+ (NSURL *)URLForManagedObjectModelName:(NSString *)modelName;

//+ (NSManagedObjectModel *)URLForMananagedObjectModel:(NSString *)urlStr;

@end

//
//  NSManagedObjectModel+helper.m
//  QGLCoreDataPlugin
//
//  Created by Guicai.Li on 14-10-16.
//  Copyright (c) 2014年 Guicai Li. All rights reserved.
//

#import "NSManagedObjectModel+helper.h"

@implementation NSManagedObjectModel (helper)

+ (NSURL *)URLForManagedObjectModelName:(NSString *)modelName {
    NSURL *modelUrl = [[NSBundle mainBundle] URLForResource:modelName withExtension:@"momd"];
    return modelUrl;
}


//+ (NSManagedObjectModel *)URLForMananagedObjectModel:(NSString *)urlStr {
//    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:[NSManagedObjectModel URLForManagedObjectModelName:urlStr]];
//    return model;
//}

@end


对NSPersistentStoreCoordinator的扩展:

NSPersistentStoreCoordinator+helper.h

//
//  NSPersistentStoreCoordinator+helper.h
//  QGLCoreDataPlugin
//
//  Created by Guicai.Li on 14-10-16.
//  Copyright (c) 2014年 Guicai Li. All rights reserved.
//

#import <Foundation/Foundation.h>

@import CoreData;

@interface NSPersistentStoreCoordinator (helper)

+ (NSURL *)URLForNSPersistentStoreCoordinatorName:(NSString *)fileName;

@end

//
//  NSPersistentStoreCoordinator+helper.m
//  QGLCoreDataPlugin
//
//  Created by Guicai.Li on 14-10-16.
//  Copyright (c) 2014年 Guicai Li. All rights reserved.
//

#import "NSPersistentStoreCoordinator+helper.h"

@implementation NSPersistentStoreCoordinator (helper)

+ (NSURL *)URLForNSPersistentStoreCoordinatorName:(NSString *)fileName {
    NSString *dbFileName = [NSString stringWithFormat:@"%@.sqlite", fileName];
    return [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:dbFileName];
}

@end


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!