Основные данные - JSON (TouchJSON) на iPhone - PullRequest
1 голос
/ 04 мая 2010

У меня есть следующий код, который, кажется, продолжается до бесконечности, пока приложение не падает. Похоже, это происходит с рекурсией в методе datastructureFromManagedObject. Я подозреваю, что этот метод:

1) просматривает первый управляемый объект и рекурсивно следует за любым свойством отношения. 2) исследует объект на другом конце отношений, найденных в точке 1, и повторяет процесс.

Возможно ли, что если управляемый объект A имеет отношение ко многим с объектом B , и это отношение является двусторонним (т.е. обратным к-одному отношение к A от B - например, в одном отделе много сотрудников, но у каждого сотрудника только один отдел), что следующий код застревает в бесконечной рекурсии как оно следует отношениям к-одному от объекта B обратно к объекту A и т. д.

Если это так, может ли кто-нибудь предоставить исправление для этого, чтобы я мог преобразовать весь свой граф объектов управляемых объектов в JSON.

#import "JSONUtils.h"


@implementation JSONUtils

- (NSDictionary*)dataStructureFromManagedObject:(NSManagedObject *)managedObject {

    NSDictionary *attributesByName = [[managedObject entity] attributesByName];
    NSDictionary *relationshipsByName = [[managedObject entity] relationshipsByName];

    //getting the values correspoinding to the attributes collected in attributesByName
    NSMutableDictionary *valuesDictionary = [[managedObject dictionaryWithValuesForKeys:[attributesByName allKeys]] mutableCopy];

    //sets the name for the entity being encoded to JSON
    [valuesDictionary setObject:[[managedObject entity] name] forKey:@"ManagedObjectName"];

    NSLog(@"+++++++++++++++++> before the for loop");
    //looks at each relationship for the given managed object
    for (NSString *relationshipName in [relationshipsByName allKeys]) {
        NSLog(@"The relationship name = %@",relationshipName);
        NSRelationshipDescription *description = [relationshipsByName objectForKey:relationshipName];

        if (![description isToMany]) {
            NSLog(@"The relationship is NOT TO MANY!");
            [valuesDictionary setObject:[self dataStructureFromManagedObject:[managedObject valueForKey:relationshipName]] forKey:relationshipName];
            continue;
        }
        NSSet *relationshipObjects = [managedObject valueForKey:relationshipName];
        NSMutableArray *relationshipArray = [[NSMutableArray alloc] init];
        for (NSManagedObject *relationshipObject in relationshipObjects) {
            [relationshipArray addObject:[self dataStructureFromManagedObject:relationshipObject]];
        }
        [valuesDictionary setObject:relationshipArray forKey:relationshipName];
    }
    return [valuesDictionary autorelease];
}

- (NSArray*)dataStructuresFromManagedObjects:(NSArray*)managedObjects {

    NSMutableArray *dataArray = [[NSArray alloc] init];
    for (NSManagedObject *managedObject in managedObjects) {
        [dataArray addObject:[self dataStructureFromManagedObject:managedObject]];
    }
    return [dataArray autorelease];
}


//method to call for obtaining JSON structure - i.e. public interface to this class
- (NSString*)jsonStructureFromManagedObjects:(NSArray*)managedObjects {
    NSLog(@"-------------> just before running the recursive method");
    NSArray *objectsArray = [self dataStructuresFromManagedObjects:managedObjects];
    NSLog(@"-------------> just before running the serialiser");
    NSString *jsonString = [[CJSONSerializer serializer] serializeArray:objectsArray];
    return jsonString;
}

- (NSManagedObject*)managedObjectFromStructure:(NSDictionary*)structureDictionary withManagedObjectContext:(NSManagedObjectContext*)moc {

    NSString *objectName = [structureDictionary objectForKey:@"ManagedObjectName"];
    NSManagedObject *managedObject = [NSEntityDescription insertNewObjectForEntityForName:objectName inManagedObjectContext:moc];
    [managedObject setValuesForKeysWithDictionary:structureDictionary];

    for (NSString *relationshipName in [[[managedObject entity] relationshipsByName] allKeys]) {
        NSRelationshipDescription *description = [[[managedObject entity]relationshipsByName] objectForKey:relationshipName];
        if (![description isToMany]) {
            NSDictionary *childStructureDictionary = [structureDictionary objectForKey:relationshipName];
            NSManagedObject *childObject = [self managedObjectFromStructure:childStructureDictionary withManagedObjectContext:moc];
            [managedObject setValue:childObject forKey:relationshipName];
            continue;
        }
        NSMutableSet *relationshipSet = [managedObject mutableSetValueForKey:relationshipName];
        NSArray *relationshipArray = [structureDictionary objectForKey:relationshipName];
        for (NSDictionary *childStructureDictionary in relationshipArray) {
            NSManagedObject *childObject = [self managedObjectFromStructure:childStructureDictionary withManagedObjectContext:moc];
            [relationshipSet addObject:childObject];
        }
    }
    return managedObject;
}

//method to call for obtaining managed objects from JSON structure - i.e. public interface to this class
- (NSArray*)managedObjectsFromJSONStructure:(NSString *)json withManagedObjectContext:(NSManagedObjectContext*)moc {

    NSError *error = nil;
    NSArray *structureArray = [[CJSONDeserializer deserializer] 
                               deserializeAsArray:[json dataUsingEncoding:NSUTF32BigEndianStringEncoding] 
                               error:&error];

    NSAssert2(error == nil, @"Failed to deserialize\n%@\n%@", [error localizedDescription], json);
    NSMutableArray *objectArray = [[NSMutableArray alloc] init];

    for (NSDictionary *structureDictionary in structureArray) {
        [objectArray addObject:[self managedObjectFromStructure:structureDictionary withManagedObjectContext:moc]];
    }
    return [objectArray autorelease];
}


@end

Ответы [ 2 ]

1 голос
/ 18 июля 2010

Я просто хотел указать на небольшую опечатку, которая вызвала сбой кода, и надеюсь, это сэкономит вам несколько минут.

- (NSArray*)dataStructuresFromManagedObjects:(NSArray*)managedObjects {

    NSMutableArray *dataArray = [[NSArray alloc] init];
    for (NSManagedObject *managedObject in managedObjects) {
        [dataArray addObject:[self dataStructureFromManagedObject:managedObject]];
    }
    return [dataArray autorelease];
}

NSMutableArray * dataArray = [[NSArray alloc] init]; // Это должен быть NSMutableArray

действительно должно быть NSMutableArray * dataArray = [[NSMutableArray alloc] init];

это все.

спасибо

1 голос
/ 04 мая 2010

Я ответил на этот вопрос, когда вы разместили комментарий в исходной теме. Вам нужно внести некоторые изменения в работу рекурсии, чтобы она не зацикливалась. Есть много способов сделать это.

Например, вы можете изменить вызов, чтобы все отношения вместо этого вызывали метод в ваших подклассах NSManagedObject, который возвращает только отношения, которые являются нисходящими. В этом проекте ObjectA будет возвращать отношение ObjectB, но Object B не будет возвращать никакого (или отношения к ObjectC и т. Д.). Это создает древовидную иерархию для прохождения рекурсии.

Следуйте логике кода. Он обрабатывает объект или объекты, которые вы ему передаете, и затем проходит через каждый объект, связанный с этим первым набором объектов. Вы уже из своего поста показали, что понимаете, что это петля. Теперь вам нужно разорвать этот цикл в вашем коде с помощью логики, чтобы превратить его из цикла в дерево.

Кроме того, я понимаю, что это может звучать так, будто я сутенерствую свою книгу. Я объяснил, как избежать этого цикла в своей книге, в главе «Многопоточность» в разделе об экспорте рецептов.

Обновление NSDate

Это звучит как ошибка в анализаторе JSON, который вы используете, так как он должен уметь обрабатывать даты. Однако ваш обходной путь жизнеспособен, за исключением того, что вам нужно конвертировать его с обеих сторон, что является PITA. Я бы посмотрел на ваш парсер и понял, почему он неправильно переводит даты, поскольку это довольно большое упущение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...