Я создаю приложение для отображения ресурсов (PDF, видео и т. д.).
Он начинается с загрузки JSON и его анализа в Core Data Objects ‹-- Эта часть работает нормально.
Эти объекты представляют собой иерархический набор узлов, отношения между которыми установлены в моей модели. каждый узел может быть либо ФАЙЛОМ, либо ПАПКОЙ. <-- Нет проблем.
Затем у меня есть методы экземпляра, встроенные в мои подклассы NSManagedObject, которые будут загружать файл, связанный с этим объектом (т.е. PDF). Затем он устанавливает
self.isAvailable = [NSNumber numberWithBool:YES];
Тем временем у меня есть UITableView, который отображает список активов. в конечном итоге он будет обновляться в режиме реального времени, но сейчас у меня проблема. Сначала у меня был контроллер представления, который хранил указатель на объект CoreData, представляющий отображаемую папку, но оказалось, что если контекст обновляется, указатель становится недействительным (т. е. не дает сбоя).
Основные данные не очень конкретны в том, в чем проблема или даже где она происходит, но, похоже, происходит сбой, когда я устанавливаю isAvailable с помощью
*** Terminating app due to uncaught exception 'NSObjectInaccessibleException', reason: 'CoreData could not fulfill a fault for '0x1d5f9e50 <x-coredata://EDE66B97-B142-4E87-B445-76CAB965B676/Node/p58>''
Я чувствую, что проблема в том, что я не должен просто хранить сильную ссылку на основной объект данных в качестве моей модели. Есть ли лучший (менее аварийный) способ сделать это?
Я начал играть с NSFetchedResultsController и вместо этого использовать objectID, но я еще ничего не добился.
- (void)populateChildren {
NSString * urlString = [NSString stringWithFormat:@"%@/%@", [CMPConstants hostURLString], self.SBUCode];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest * request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:self.downloadQueue completionHandler:^(NSURLResponse * response, NSData * data, NSError * error) {
if (data) {
NSDictionary * dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
[self processParsedObject:dict];
} else {
NSLog(@"%@", urlString);
}
}];
}
#pragma mark - Parse JSON into NSManagedObjects
- (void)processParsedObject:(id)object {
[self processParsedObject:object depth:0 parent:nil key:nil];
[[NSManagedObjectContext MR_contextForCurrentThread] MR_saveToPersistentStoreAndWait];
}
- (void)processParsedObject:(id)object depth:(int)depth parent:(Node *)parent key:(NSString*)key {
if ([object isKindOfClass:[NSDictionary class]]) {
if (depth == 0) {
// Grab content node if depth is 0;
object = [object valueForKey:@"content"];
}
// FIXME: Change this to a real primary key once we get one.
static NSString * primaryKey = @"name";
// Look for existing object
Node * testNode = [Node MR_findFirstByAttribute:primaryKey withValue:[object valueForKey:primaryKey]];
// Create new node pointer
Node * newNode;
if (testNode) {
// Update existing Node
newNode = testNode;
} else {
// Build a new Node Object
newNode = [Node MR_createEntity];
newNode.isAvailable = [NSNumber numberWithBool:NO];
}
// Get keys
NSArray * keys = @[@"name",
@"type",
@"index",
@"size",
@"videoDemensions",
@"videoId",
@"fileName",
@"fileType",
@"path"];
if ([[object valueForKey:@"type"] isEqual:[NSNull null]]) {
NSLog(@"%@", object);
}
// Loop to set value for keys.
for (NSString * key in keys) {
id value = [object valueForKey:key];
if (![[object valueForKey:key] isKindOfClass:[NSNull class]]) {
[newNode setValue:value forKey:key];
}
}
// Set calculated properties.
[newNode setSbu:[self SBUCode]];
[newNode setParent:parent];
[[NSManagedObjectContext MR_contextForCurrentThread] MR_saveToPersistentStoreAndWait];
// Sync local file.
if (!newNode.isAvailable.boolValue) {
[newNode aquireFileInQueue:self.downloadQueue];
}
// Process children
for(NSString * newKey in [object allKeys]) {
id child = [object objectForKey:newKey];
[self processParsedObject:child depth:depth+1 parent:newNode key:newKey];
}
} else if ([object isKindOfClass:[NSArray class]]) {
for(id child in object) {
[self processParsedObject:child depth:depth+1 parent:parent key:nil];
}
} else {
// Nothing here, this processes each field.
}
}
Этот метод является методом экземпляра класса Node.
- (void)aquireFileInQueue:(NSOperationQueue *)queue {
if ([self.type isEqualToString:@"VIDEO"]) {
// Videos are available, but not downloaded.
self.isAvailableValue = YES;
return;
}
if (self.path == nil || self.fileName == nil) {
NSLog(@"Path or Filename for %@ was nil", self.name);
return;
}
// Build the download URL !! MAKE SURE TO ADD PERCENT ESCAPES, this will protect against spaces in the file name
// Also make sure to slash-separate the path and fileName
NSURL * downloadURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@",
[self.path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[self.fileName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
// Build the download request
NSURLRequest * downloadRequest = [NSURLRequest requestWithURL:downloadURL];
// FIXME: Authentication Code for JSON service
// Show network activity indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
// Send Asynchronus Request for fileData
[NSURLConnection sendAsynchronousRequest:(NSURLRequest *)downloadRequest queue:queue completionHandler:^(NSURLResponse * response, NSData * data, NSError * error) {
// Hide network activity indicatior
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
// Cast URL Response to HTTPURLResponse
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
// If statusCode is 200 (successful) and data is not nil, save data
if (httpResponse.statusCode == 200 && data) {
[data writeToURL:[self fileURL] atomically:NO];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self setIsAvailable:[NSNumber numberWithBool:YES]];
}];
}
}];
}
- (void)prepareForDeletion {
// Remove file from Filesystem
[[NSFileManager defaultManager] removeItemAtURL:[self fileURL] error:nil];
}
- (NSURL *)fileURL {
// Return local file URL
return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", [Node applicationDocumentsDirectory], self.fileName]];
}
objectID
так же, как вы начинаете работать. NSFetchedResultsController — хороший способ, если вы хотите убедиться, что ваше табличное представление остается в курсе изменений, которые происходят в другом контексте/потоке. - person Chris Wagner   schedule 25.04.2013