1. 程式人生 > >iOS程式碼重構(二)CoreData多執行緒(支援執行緒安全)

iOS程式碼重構(二)CoreData多執行緒(支援執行緒安全)

CoreData對多執行緒的支援比較奇怪(按照一般的思路來說),CoreData的NSPersistentStoreCoordinator和NSManagedObjectContext物件都是不能跨執行緒使用的,NSManagedObject也不行,有人想加鎖不就完了。

前提描述

     原專案中已有CoreData封裝,但是執行緒不完全的,而且應用的地方較多,參考了網上的一些文章,如果按主流的搞個三層上下文saveMOC,mainMOC,newPrivateMOC,應用Block來實現非同步。但專案改動較大。而且經測試,程式碼健壯性不是很好,多執行緒操作時,

有崩潰現象。原專案中的資料庫檔案,是按使用者,分別建立的。

    基本方案:應用MagicRecord部分API,實現Core執行緒安全, 改動控制在CoreDataManager內

MagicRecord實現的是三層結構,

[NSManagedObjectContextMR_rootSavingContext] 根MOC

[NSManagedObjectContextMR_defaultContext] 對應MainMOC,主MOC,它的父是rootSavingContext

[NSManagedObjectContextMR_context] 對應privateMoc,私有MOC,它的父是defualtContext,每次呼叫都會新建立一個MOC



直接上程式碼吧

1 初始化操作

AppDelegate.m

NSString *userId = [[PublicObjectpublicObjectInstance] getUserId];

if (userId) {//登入後再初始化本地資料庫

        [[CoreDataManagershareInstance] setupCoreDataStack];

        [MagicalRecordsetLoggingLevel:MagicalRecordLoggingLevelAll];

    }

2 CoreDataManager部分函式

- (void) setupCoreDataStack

{

if ([NSPersistentStoreCoordinatorMR_defaultStoreCoordinator] !=nil) return;

NSPersistentStoreCoordinator *coordinator = [selfpersistentStoreCoordinator];

    [NSPersistentStoreCoordinatorMR_setDefaultStoreCoordinator:coordinator];

    [NSManagedObjectContextMR_initializeDefaultContextWithCoordinator:coordinator];

}

// Returns the managed object model for the application.

// If the model doesn't already exist, it is created from the application's model.

- (NSManagedObjectModel *)managedObjectModel {

if (!_managedObjectModel) {

NSURL *modelURL = [[NSBundlemainBundle] URLForResource:@"ModelObject"withExtension:@"momd"];

_managedObjectModel = [[NSManagedObjectModelalloc] initWithContentsOfURL:modelURL];

    }

return_managedObjectModel;

}

// Returns the persistent store coordinator for the application.

// If the coordinator doesn't already exist, it is created and the application's store added to it.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (!_persistentStoreCoordinator) {

NSURL* storeURL = [NSURLfileURLWithPath:[FileHelperinfodbFilePath]];//Lib目錄/使用者ID/info.db

NSError *error =nil;

_persistentStoreCoordinator = [[NSPersistentStoreCoordinatoralloc] initWithManagedObjectModel:[selfmanagedObjectModel]];

NSDictionary *options =@{NSMigratePersistentStoresAutomaticallyOption : [NSNumbernumberWithBool:YES],

NSInferMappingModelAutomaticallyOption : [NSNumbernumberWithBool:YES]};

if (![_persistentStoreCoordinatoraddPersistentStoreWithType:NSSQLiteStoreTypeconfiguration:nilURL:storeURL options:optionserror:&error]) {

NSLog(@"Unresolved error %@, %@", error, [erroruserInfo]);

abort();

        }

    }

return_persistentStoreCoordinator;

}

-(BOOL) save:(NSError **)error{

    [[NSManagedObjectContextMR_defaultContext] MR_saveToPersistentStoreAndWait];

returnYES;

}

- (void)removeObjectsWithPredicate:(NSPredicate*)predicate inEntity:(NSString*)entityName {

NSManagedObjectContext *context = [NSManagedObjectContextMR_context];

NSFetchRequest *request = [[NSFetchRequestalloc] init];

    request.predicate = predicate;

    request.includesPropertyValues =NO;

    request.entity = [NSEntityDescriptionentityForName:entityNameinManagedObjectContext:context];

    [context performBlockAndWait:^{

NSError *error;

NSArray *objects = [contextexecuteFetchRequest:requesterror:&error];

if (!error && objects.count) {

for (NSManagedObject *objin objects) {

                [context deleteObject:obj];

            }

        }

    }];

    [context MR_saveToPersistentStoreAndWait];

}

- (NSMutableArray*)findObjectsIn:(NSString*)entityName withPredicate:(NSPredicate*)predicate andSortDescriptors:(NSArray*)sortDescriptors andObjectClass:(Class)objClass {

NSManagedObjectContext *context = [NSManagedObjectContextMR_context];

NSFetchRequest *request = [[NSFetchRequestalloc] init];

    request.predicate = predicate;

    request.sortDescriptors = sortDescriptors;

    request.entity = [NSEntityDescriptionentityForName:entityNameinManagedObjectContext:context];

__blockNSMutableArray *results =nil;

    [context performBlockAndWait:^{

NSError *error =nil;

NSArray *objects = [contextexecuteFetchRequest:requesterror:&error];

if (objects ==nil)

        {

NSLog(@"%@",error);

return ;

        }

        results = [NSMutableArrayarrayWithCapacity:objects.count];

if (!error && objects.count) {

for (id entityin objects) {

id obj = [[objClassalloc] initWithEntity:entity];

                [results addObject:obj];

            }

        }

    }];

return results;

}

//插入

- (void)insertProgressAndAttachments:(NSArray *)progressArray

{

NSManagedObjectContext *context = [NSManagedObjectContextMR_context];

for (Progress *progressin progressArray) {

Progress* entity = (Progress*)[NSEntityDescriptioninsertNewObjectForEntityForName:TBProgress

inManagedObjectContext:context];

        entity.projectId        = progress.projectId;

        entity.buildingId       = progress.buildingId;

        entity.progressId       = progress.progressId;

        entity.createdDate      = progress.createdDate;

        entity.createdBy        = progress.createdBy;

        entity.lastModifiedDate = progress.lastModifiedDate;

        entity.lastModifiedBy   = progress.lastModifiedBy;

        entity.occurredDate     = progress.occurredDate;

        entity.progressDesc     = progress.progressDesc;

        entity.version          = progress.version;

        entity.progressStatus   = progress.progressStatus;

        entity.conflict         = progress.conflict;

        entity.weather          = progress.weather;

        entity.temperature      = progress.temperature;

        entity.windPower        = progress.windPower;

for (ProgressAttachment *attachin progress.attachments) {

            [selfinsertProgressAttachment:attach];

        }

for (ProgressWorkType *workTypein progress.workTypes) {

            [selfinsertProgressWorkType:workType];

        }

for (ProgressDelayReason *delayReasonin progress.delayReasons) {

            [selfinsertProgressDelayReason:delayReason];

        }

    }

    [context MR_saveToPersistentStoreAndWait];

}

//查詢

- (Progress*)findProgressById:(NSString *)progressId {

return [selffindFirstObjectIn:TBProgress

withPredicate:[NSPredicatepredicateWithFormat:@"progressId = %@", progressId]

andSortDescriptors:nil

andObjectClass:[Progressclass]];

}

//刪除

// 刪除一個專案的所有進度附件

- (void)removeAllProgressAttachmentByProject:(NSString*)projectId {

    [selfremoveObjectsWithPredicate:[NSPredicatepredicateWithFormat:@"projectId = %@", projectId]

inEntity:TBProgressAttachment];

}


參考文章:

原始碼

原理-知識

認識CoreData—多執行緒

iOS開發中一些常見的並行處理

對應Demo

在多執行緒環境中使用CoreData

英文版

不再替Core Data多執行緒程式設計而頭疼

Magical Record 全面解析

MagicalRecord初始化,資料遷移與提前預製資料庫邏輯