У меня есть следующий код, который, кажется, продолжается неограниченно долго до сбоев приложения. Это, кажется, происходит с рекурсией в datastructureFromManagedObject методе. Я подозреваю что этот метод:
1) взгляды на первый управляемый объект и следуют за любым свойством отношений рекурсивно. 2) исследует объект в другом конце отношений, найденных в точке 1, и повторяет процесс.
Действительно ли возможно что, если управляемый объект A имеет к - многие отношения с объектом B и что отношения являются двухсторонними (т.е. инверсия к - отношения к от B - например, один отдел имеют многих сотрудников, но у каждого сотрудника есть только один отдел), что следующий код застревает в бесконечной рекурсии, поскольку это следует к - отношения от объекта B назад для возражения и так далее.
Если так, может любой обеспечивать фиксацию для этого так, чтобы я мог получить свой целый граф объектов управляемых объектов, преобразованных в 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
Я ответил на этот вопрос, когда вы оставили комментарий в оригинальной теме. Вам нужно внести некоторые изменения в то, как работает рекурсия, чтобы она не зацикливалась. Есть много способов сделать это.
Например, вы можете изменить вызов для получения всех отношений, чтобы вместо этого вызвать метод в ваших подклассах NSManagedObject
, который возвращает только те отношения, которые находятся ниже по течению. В такой конструкции ObjectA будет возвращать отношения ObjectB, но Object B не будет возвращать никаких отношений (или отношений с ObjectC и т.д.). Это создает древовидную иерархию для работы рекурсии.
Следуйте логике кода. Он обрабатывает объект или объекты, которые вы ему передаете, а затем проходит по каждому объекту, связанному с этим первым набором объектов. Вы уже показали своим сообщением, что понимаете, что это цикл. Теперь вам нужно разорвать этот цикл в коде с помощью логики, чтобы превратить его из цикла в дерево.
Также, я понимаю, что это может показаться, что я рекламирую свою книгу, я объяснил, как избежать этого цикла в моей книге в главе "Многопоточность" в разделе об экспорте рецептов.
Это похоже на ошибку в парсере JSON, который вы используете, поскольку он должен уметь работать с датами. Однако ваш обходной путь жизнеспособен, за исключением того, что вам нужно конвертировать его с обеих сторон, что является хлопотным делом. Я бы посмотрел на ваш парсер и выяснил, почему он не переводит даты правильно, поскольку это довольно большое упущение.
Я просто хотел указать на небольшую опечатку, которая привела к сбою кода, и, надеюсь, это сэкономит вам несколько минут.
- (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];
вот и все.
спасибо