我们的应用程序使用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?
有什么想法吗?