我编写了下面的方法来处理文件的下载。
- (void)downloadFileFromURL:(NSURL *)url {
if (url != nil) {
if ([url pathExtension] != nil) {
RLMRealm *realm = [Utilities getRealm];
RLMResults<Download *> *results = [[Download allObjectsInRealm:realm] sortedResultsUsingKeyPath:@"id" ascending:NO];
Download *oldestDownload = [results firstObject];
Download *download = [[Download alloc] init];
download.id = oldestDownload.id+1;
download.name = [url path];
download.type = @"html";
download.state = DownloadStateNew;
download.token = [Utilities generateToken];
download.url = [url absoluteString];
[realm beginWriteTransaction];
[realm addObject:download];
self.current = download;
[realm commitWriteTransaction];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:download.name];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"text/html", @"application/json", @"image/png", nil];
[manager GET:[NSString stringWithFormat:@"%@", url]
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSData *data = [[NSData alloc] initWithData:responseObject];
[data writeToFile:path atomically:YES];
NSLog(@"successful download to %@", path);
RLMRealm *realm = [Utilities getRealm];
[realm beginWriteTransaction];
self.current.state = DownloadStateDone;
[realm commitWriteTransaction];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
RLMRealm *realm = [Utilities getRealm];
[realm beginWriteTransaction];
self.current.state = DownloadStateCancelled;
[realm commitWriteTransaction];
}];
}
}
}
然而,这不断抛出从错误的线程访问Realm的错误。我不知道是什么造成了这种情况。有什么想法吗?
答案 0 :(得分:1)
从AFNetworking代码判断,看起来success
和failure
块将在单独的调度队列上调用,而不是最初用于启动请求的调度队列。
为了保证ACID合规性,Realm对象受线程限制,如果您尝试将其传递给另一个线程然后访问其任何属性,则会触发您看到的异常。
我们最近在Realm Objective-C和Realm Swift中添加了一个功能,可以传递表示Realm对象的线程安全引用,然后可以使用这些引用查询新线程上的同一对象:
// Do work with `self.current`
RLMThreadSafeReference *currentReference = [RLMThreadSafeReference referenceWithThreadConfined:self.current];
AFHTTPRequestOperationManager *manager =[AFHTTPRequestOperationManager manager];
//Configure `manager`
[manager GET:[NSString stringWithFormat:@"%@", url]
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
MyCurrentClass *threadCurrent = [RLMRealm resolveThreadSafeReference:currentReference];
[threadCurrent.realm beginWriteTransaction];
threadCurrent.state = DownloadStateDone;
[threadCurrent.realm commitWriteTransaction];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Handle `threadReference` here too if needed
}];