0

現在、アプリケーション内の managedObjectContext でスレッドの問題が発生しています。現在、バックグラウンドで実行する必要があるバックグラウンド スレッドを実行していますが、同時に managedObjectContext にアクセスしています。別の ViewController は、次に示すメソッド processAllApplications を呼び出し、次に checkCompletedApplicationsFor24HourExpiration を呼び出し、さらに getAppsWithStatus を呼び出します。スレッドは現在ロックされているようで、以下の警告がある場所でこの操作が停止します。私はこれを処理する方法が必要であり、コア データに関しては非常に初心者です。どなたかアドバイスいただけないでしょうか。managedObject の複数のインスタンスを作成してそれらをマージする必要があるかもしれないと読んでいました。その場合、どうすればいいですか?

AppDelegate:

- (NSManagedObjectContext *)managedObjectContext
{

    [__managedObjectContext lock];
    if (__managedObjectContext != nil) {

        [__managedObjectContext unlock];
        return __managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        __managedObjectContext = [[NSManagedObjectContext alloc] init];
        [__managedObjectContext setPersistentStoreCoordinator:coordinator];
    }

    [__managedObjectContext unlock];
    return __managedObjectContext;

}
    - (NSMutableArray*)getAppsWithStatus:(int)intStatus {


    NSLog(@"%i on main thread getAppsWithStatus", [NSThread currentThread].isMainThread);
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Application" inManagedObjectContext:self.managedObjectContext];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDescription];

    // Set example predicate and sort orderings...
    NSNumber *status = [NSNumber numberWithInt:intStatus];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = %@ && username = %@", status, [[NSUserDefaults standardUserDefaults] objectForKey:@"username"]];
    #warning FAILS HERE INTO ABYSS
    [request setPredicate:predicate];

    NSError *error = nil;

    NSMutableArray* applications = [[NSMutableArray alloc] initWithArray:[self.managedObjectContext executeFetchRequest:request error:&error]];
    for (Application* eachApp in applications)
        eachApp.applicationNumber = nil;
    [self saveDB];
    return applications;
}

    - (void)processAllApplications:(id)userInfo {
    [self.processApplicationsLock lock];

    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"username"] == nil) return;    // Not logged in
    NSLog(@"processing");
    [self checkCompletedApplicationsFor24HourExpiration];
    [self alertFor12HourCompletedApplications];
    [self alertForExpiredDraftApplications];

    if ([DeleteAllDraftApplicationsForCurrentApplicationYear isSatisifiedByDate:[DateTimeFactory currentApplicationDate]]) {
        [self deleteExpiredApps];
    }

    [self performSelector:@selector(sendApplications:) withObject:nil afterDelay:3];

    [self.processApplicationsLock unlock];
}

- (void)checkCompletedApplicationsFor24HourExpiration {

    NSLog(@"OutboxSender - (void)checkCompletedApplicationsFor24HourExpiration");
    NSLog(@"%i on main thread checkCompletedApplicationsFor24HourExpiration", [NSThread currentThread].isMainThread);
    NSArray* completedApps = [self getAppsWithStatus:STATUS_COMPLETED];
    NSDate* targetDate = [self offsetDate:[DateTimeFactory currentApplicationDate] withDay:-1 withMonth:0 withHour:0];

    for (Application* theApplication in completedApps) {
        if ([MoveCompletedApplicationToDraftApplicationSpec isSatisfiedByApplication:theApplication cutOffDate:targetDate]) {
            NSLog(@"Sending To draft with date: %@", theApplication.submittedDate);
            theApplication.status = [NSNumber numberWithInt:STATUS_DRAFT];
            [self deleteSignatures:theApplication];
        }
    }

    NSString* message = [NSString stringWithFormat:@"%i completed application/s have been sent to drafts", [completedApps count]];
    echo_Alert(@"", message);

    [self saveDB];
}
4

1 に答える 1

1
create separate managed object context

+(NSManagedObjectContext *)getManagedObjectContext
{
    NSManagedObjectContext *managedObjectContext;
    @try {
        NSPersistentStoreCoordinator * coordinator = [self persistentStoreCoordinator];
        if (coordinator != nil) {
            managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
            [managedObjectContext setPersistentStoreCoordinator: coordinator];
        }

    }
    @catch (NSException *exception) {
        NSLog(@"Exception occur %@",exception);
    }
    return managedObjectContext;

Use this separate managed object context in your fetching method,

    - (NSMutableArray*)getAppsWithStatus:(int)intStatus {

NSMutableArray * mutableObjects;
    NSLog(@"%i on main thread getAppsWithStatus", [NSThread currentThread].isMainThread);
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Application" inManagedObjectContext:[self getManagedObjectContext]]; // Here use separate managed object context
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entityDescription];

    // Set example predicate and sort orderings...
    NSNumber *status = [NSNumber numberWithInt:intStatus];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"status = %@ && username = %@", status, [[NSUserDefaults standardUserDefaults] objectForKey:@"username"]];
    #warning FAILS HERE INTO ABYSS
    [request setPredicate:predicate];

    NSError *error = nil;

    NSMutableArray* applications = [[NSMutableArray alloc] initWithArray:[[self getManagedObjectContext] executeFetchRequest:request error:&error]];

 NSMutableArray * resultedArray = [applications mutableCopy];
        NSMutableArray * objectIds = [[NSMutableArray alloc] initWithCapacity:[resultedArray count]];
        for (NSManagedObject *obj in resultedArray) {
            [objectIds addObject:obj.objectID];
        }

        mutableObjects = [[NSMutableArray alloc] initWithCapacity:[objectIds count]];
        for (NSManagedObjectID * objectID in objectIds) {
            NSManagedObject * obj = [self.managedObjectContext
 objectWithID:objectID]; // Here use self.managedObjectContext in which you already created.
            [mutableObjects addObject:obj];
        }

    for (Application* eachApp in mutableObjects)
        eachApp.applicationNumber = nil;
    [self saveDB];
    return mutableObjects;
}
于 2013-08-23T05:37:09.683 に答える