RACScheduler在NSManagedObject上与EXC_BAD_ACCESS KERN_INVALID_ADDRESS崩溃

时间:2015-08-14 11:08:30

标签: ios objective-c core-data reactive-cocoa

我们的应用程序使用ReactiveCocoa 2.5

重新出现,很难重现崩溃

我们有一个后台调度程序,我们在应用程序的实时时间保留。每当我们进行网络呼叫(使用AFNetworking)时,我们都会在此后台调度程序上提供结果(大多数时候是JSON数据)。然后,我们将数据存储在后台核心数据上下文中,最终在原始调度程序(实际上是主调度程序)上完成。

代码中此流程的一个示例:

- (RACSignal *)example {
    NSString *path = _applicationConfiguration.competitionsPath;

    @weakify(self)
    RACSignal *networkCallSignal = [[RACSignal createSignal:^RACDisposable *(id <RACSubscriber> subscriber) {
        @strongify(self)
        NSURLSessionDataTask *task = [self _GETDataTaskWithSubscriber:subscriber path:path parameters:nil];
        return [RACDisposable disposableWithBlock:^{
            [task cancel];
        }];
    }] deliverOn:_backgroundScheduler];


    RACSignal *networkCallSignalToCoreDataSaveSignal = [[networkCallSignal flattenMap:^RACStream *(id result) {
        @strongify(self)
        NSError *error;
        Team *team = [self _saveJSONToCoreData:result error:&error];

        if (team) {
            return [RACSignal return:team.identifier];
        } else {
            return [RACSignal error:error];
        }
    }] subscribeOn:_backgroundScheduler];

    return [networkCallSignalToCoreDataSaveSignal deliverOn:[RACScheduler currentScheduler]];
}

- (Team *)_saveJSONToCoreData:(NSDictionary *)JSONData error:(NSError **)error {
    //naive implementation, for the sake of this example

    NSManagedObjectContext *context = ...;//context creation ommited for this example,
    NSEntityDescription *ed = [NSEntityDescription entityForName:@"Team" inManagedObjectContext:context];
    Team *team = [[Team alloc] initWithEntity:ed insertIntoManagedObjectContext:context];
    //setting properties on team from json dictionary here
    if ([context save:error]) {
        return team;
    } else {
        return nil;
    }
}

static id _afSessionManager;
- (NSURLSessionDataTask *)_GETDataTaskWithSubscriber:(id <RACSubscriber>)subscriber path:(NSString *)path parameters:(NSDictionary *)parameters {
    return [_afSessionManager GET:path parameters:parameters success:[self _succesBlock:subscriber path:path] failure:[self _failBlock:subscriber path:path]];
}

- (void (^)(NSURLSessionDataTask *, NSError *))_failBlock:(id <RACSubscriber>)subscriber path:(NSString *)path {
    return ^(NSURLSessionDataTask *t, NSError *error) {
        [subscriber sendError:error];
    };
}

- (void (^)(NSURLSessionDataTask *, id))_succesBlock:(id <RACSubscriber>)subscriber path:(NSString *)path {
    void (^success)(NSURLSessionDataTask *, id) = ^(NSURLSessionDataTask *t, id result) {
        [subscriber sendNext:result];
        [subscriber sendCompleted];
    };
    return success;
}    

崩溃发生在[RACScheduler performAsCurrentScheduler:]方法中,如此处所示(请参阅CRASHES HERE评论):

- (void)performAsCurrentScheduler:(void (^)(void))block {
  ...

  RACScheduler *previousScheduler = RACScheduler.currentScheduler;
  NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = self;

  @autoreleasepool {
    block(); //CRASHES HERE
  }

  ...
}

正如您在下面的崩溃日志中看到的那样,问题似乎是NSManagedObject上的一个版本。这种情况偶尔发生,因此难以重现,但始终具有相同的堆栈跟踪。

要完成,这是一个典型的崩溃日志:

Thread : Crashed: background.scheduler
0  libobjc.A.dylib                0x0000000196b17bd0 objc_msgSend + 16
1  CoreData                       0x0000000184fa6a00 -[NSManagedObject release] + 160
2  CoreData                       0x0000000184f9c490 -[_PFArray dealloc] + 100
3  libobjc.A.dylib                0x0000000196b1d724 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 564
4  exampleapp                     0x00000001000c0ec8 -[RACScheduler performAsCurrentScheduler:] (RACScheduler.m:203)
5  libdispatch.dylib              0x0000000197155994 _dispatch_call_block_and_release + 24
6  libdispatch.dylib              0x0000000197155954 _dispatch_client_callout + 16
7  libdispatch.dylib              0x00000001971600a4 _dispatch_queue_drain + 1448
8  libdispatch.dylib              0x0000000197158a5c _dispatch_queue_invoke + 132
9  libdispatch.dylib              0x0000000197162318 _dispatch_root_queue_drain + 720
10 libdispatch.dylib              0x0000000197163c4c _dispatch_worker_thread3 + 108
11 libsystem_pthread.dylib        0x000000019733522c _pthread_wqthread + 816
12 libsystem_pthread.dylib        0x0000000197334ef0 start_wqthread + 4

围绕该块的自动释放池是否会释放已发布的NSManagedObject?

有什么想法吗?

0 个答案:

没有答案