JSON و Core Data على iPhone



Answers

أردت فقط أن أشير إلى خطأ مطبعي صغير ، تسبب في تعطل الشفرة ، ونأمل أن يؤدي ذلك إلى توفير بعض الدقائق.

- (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]; // This should be NSMutableArray NSMutableArray *dataArray = [[NSArray alloc] init]; // This should be NSMutableArray

يجب أن يكون NSMutableArray *dataArray = [[NSMutableArray alloc] init];

هذا كل شيء.

شكرا

Question

لدي رسم بياني أساسي لبيانات البيانات (يتكون من كيانين مرتبطين بعلاقة متعددة الأطراف).

لقد كنت فضولياً ، كمطور مطور لجهاز iPhone لا يمتلك الخبرة الكافية ، وما إذا كان أي شخص يمكنه التوصية بنهج ، وتطبيق JSON مناسب لجهاز iPhone ، مما يسمح لي بما يلي:

  1. تحويل سجلات البيانات الأساسية إلى سلسلة JSON (مع الحفاظ على العلاقة بين الكيانات) ؛ و

  2. تحويل سلسلة JSON مرة أخرى إلى كائنات البيانات الأساسية (مرة أخرى الحفاظ على العلاقة بين الكيانات).

لقد بحثت ، دون جدوى ، عن عينة تعليمي / رمز على هذه النقطة حتى أي مساعدة سيتم تلقي بامتنان.




لقد ألهمني ماركوس إس. زاررا لإحضار الفكرة المتكررة إلى نسخة عمل. في هذا الإصدار لا تحتاج إلى تعيين مفتاح في CoreData ويمكنك قصه ولصقه في مشروعك :-)

// MARK: - encoding and decoding CoreData entity to dictionary

func dataStructureFromManagedObject( managedObject:NSManagedObject?, parentEntity: NSEntityDescription? = nil) -> NSMutableDictionary {
    if (managedObject != nil) {
        var attributesByName: NSDictionary = managedObject!.entity.attributesByName
        var relationshipsByName: NSDictionary  = managedObject!.entity.relationshipsByName
        var valuesImmutableDictionary: NSDictionary = managedObject!.dictionaryWithValuesForKeys( attributesByName.allKeys)
        var valuesDictionary: NSMutableDictionary = valuesImmutableDictionary.mutableCopy() as NSMutableDictionary
        valuesDictionary.setObject( managedObject!.entity.name!, forKey: "ManagedObjectName")
        for relationshipNameObject in relationshipsByName.allKeys {
            var relationshipName: NSString = relationshipNameObject as  NSString
            var relationshipDescription: NSRelationshipDescription? = relationshipsByName.objectForKey( relationshipName) as? NSRelationshipDescription
            if !relationshipDescription!.toMany {
                // ono to one
                if parentEntity == nil || (relationshipDescription! as NSRelationshipDescription).destinationEntity != parentEntity! {
                    // no parent or relationship is "downward" -> object for relationship must be added
                    var relationshipObject: NSManagedObject? = managedObject!.valueForKey( relationshipName) as? NSManagedObject
                    var relationshipObjectDictionary: NSMutableDictionary = self.dataStructureFromManagedObject( relationshipObject, parentEntity: managedObject?.entity)
                    valuesDictionary.setObject( relationshipObjectDictionary, forKey: relationshipName)
                } else {
                    // relationship is "upward" -> nothing to do
                }
            } else {
                // one to many -> all objects must be added
                var relationshipObjects: NSSet = managedObject!.mutableSetValueForKey( relationshipName)
                var relationshipArray:NSMutableArray = []
                for relationshipObjectRaw in relationshipObjects {
                    var relationshipObject:NSManagedObject? = relationshipObjectRaw as? NSManagedObject
                    if relationshipObject != nil && !relationshipObject!.entity.isKindOfEntity( managedObject!.entity) {
                        relationshipArray.addObject(self.dataStructureFromManagedObject( relationshipObject, parentEntity: managedObject?.entity))
                    }
                }
                valuesDictionary.setObject( relationshipArray, forKey: relationshipName)
            }
        }
        return valuesDictionary
    } else {
        return NSMutableDictionary()
    }
}

func managedObjectFromStructure( structureDictionary: NSDictionary, moc: NSManagedObjectContext, parentObject: NSManagedObject? = nil) -> NSManagedObject {
    if structureDictionary.count > 0 {
        var objectName:NSString = structureDictionary.objectForKey( "ManagedObjectName") as NSString
        var managedObject:NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName( objectName, inManagedObjectContext: moc) as NSManagedObject
        var relationshipsByName: NSDictionary  = managedObject.entity.relationshipsByName
        var realObjectStructure:NSMutableDictionary = structureDictionary.mutableCopy() as NSMutableDictionary
        realObjectStructure.removeObjectForKey( "ManagedObjectName")
        for key in realObjectStructure.allKeys {
            // search for "ManagedObjectName" relationship entrys and delete them before filling the managedObject from this structure
            for relationshipName in relationshipsByName.allKeys {
                if relationshipName as NSString == key as NSString {
                    realObjectStructure.removeObjectForKey( key)
                }
            }
        }
        managedObject.setValuesForKeysWithDictionary( realObjectStructure)
        // the main object with attributes is created. Now care about the relationships
        for relationshipName in managedObject.entity.relationshipsByName.keys {
            var description:NSRelationshipDescription = relationshipsByName.objectForKey( relationshipName) as NSRelationshipDescription
            if !description.toMany {
                // to one relationship
                if parentObject == nil || description.destinationEntity != parentObject!.entity {
                    // no parent or relationship is "downward" -> recurse structure to add
                    var childStructureDictionary:NSDictionary = structureDictionary.objectForKey( relationshipName) as NSDictionary
                    if childStructureDictionary.count > 0 {
                        // dictionary not empty -> object must be created and added
                        var childObject:NSManagedObject? = self.managedObjectFromStructure( childStructureDictionary, moc: moc, parentObject: managedObject)
                        // validateForUpdate
                        var error:NSError?
                        if !managedObject.validateForUpdate( &error) {
                            println("Error: Object not in valid state for update!!! -> \(error)")
                        } else {
                            managedObject.setValue( childObject, forKey: relationshipName as NSString)
                        }
                    } else {
                        // relationship is "upward" -> nothing to do
                    }
                }
            } else {
                // to many relationship
                var relationshipSet:NSMutableSet = managedObject.mutableSetValueForKey( relationshipName as NSString)
                var relationshipArray:NSArray = structureDictionary.objectForKey( relationshipName as NSString) as NSArray
                for childStructureDictionary in relationshipArray {
                    if childStructureDictionary.count > 0 {
                        // dictionary not empty -> object must be created and added
                        var childObject:NSManagedObject = self.managedObjectFromStructure( childStructureDictionary as NSDictionary, moc: moc, parentObject: managedObject)
                        // validateForUpdate
                        var error:NSError?
                        if !managedObject.validateForUpdate( &error) {
                            println( "Error: Object not in valid state for update!!! -> \(error)")
                        } else {
                            relationshipSet.addObject( childObject)
                        }
                    } else {
                        // no object was behind the relationship -> nothing to do
                    }
                }
                // save set
                managedObject.setValue( relationshipSet, forKey: relationshipName as NSString)
            }
        }
        // final check validateForUpdate
        var error:NSError?
        if !managedObject.validateForUpdate( &error) {
            println( "Error: Object not in valid state for update although all previous check are passed!!! -> \(error)")
        }
        return managedObject
    } else {
        println( "Error: structure for object was empty. this should not happen at this point")
        var objectName:NSString = structureDictionary.objectForKey( "ManagedObjectName") as NSString
        var managedObject:NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName( objectName, inManagedObjectContext: moc) as NSManagedObject
        return managedObject
    }
}

func dataStructuresFromManagedObjects( managedObjects: NSArray) -> NSArray {
    var dataArray:NSMutableArray = []
    for managedObject in managedObjects {
        dataArray.addObject( self.dataStructureFromManagedObject(managedObject as? NSManagedObject))
    }
    return dataArray
}

المفتاح هنا هو تمرير الكيان الرئيسي كحجة للتكرار ، حتى نتمكن من تحديد العلاقة التي يجب أن نملأها بالبيانات. وبالتالي فإن كلا الوظيفتين: dataStructureFromManagedObject و managedObjectFromStructure يمكن ترميز وفك شفرة أي كائن كيان من CoreData إلى قاموس والعودة إلى كائن.




إذا كان لديك NSDate في الكائن المُدار ، كما هو مذكور أعلاه في أحد التعليقات ، فستواجه مشكلات في تسلسل الكائن الذي يحتوي على NSDate . إصلاح بسيط هو إضافة أسلوب JSONDataRepresentation إلى JSONDataRepresentation باستخدام الفئات JSONDataRepresentation -c.

أضف هذين الملفين إلى مشروعك:

NSdate.h:

#import <Foundation/Foundation.h>

@interface NSDate (jsondatarepresentation) 

- (NSData*) JSONDataRepresentation;

@end

NSDate.m:

#import "NSDate.h"

@implementation NSDate (jsondatarepresentation)

- (NSData*) JSONDataRepresentation {
    return [[[NSNumber numberWithDouble:[self timeIntervalSince1970]] stringValue] dataUsingEncoding:NSUTF8StringEncoding];
}

@end



جئت عبر هذا المنصب الذي يعمل بشكل جيد للغاية.

http://touchalicious.com/blog/2009/10/25/turn-core-data-models-into-json.html

وبما أن هذا الأمر تعاودي ، فستستمر العلاقات بين أطراف كثيرة في التكرار من خلال نفسها. لتجنب ذلك ، أضفت مفتاح "قابل للتقييم" إلى قاموس معلومات المستخدم للعلاقات في نموذج البيانات الأساسية. يمكنك بعد ذلك التحقق من هذا المفتاح واختيار عدم التكرار عبر العلاقات بدونه.

if ([property isKindOfClass:[NSRelationshipDescription class]])
    {
        NSRelationshipDescription *relationshipDescription = (NSRelationshipDescription *)property;

        if ([[[relationshipDescription userInfo] objectForKey:@"isExportable"] boolValue] == YES)
        {
            NSString *name = [relationshipDescription name];

            if ([relationshipDescription isToMany])
            {
                NSMutableArray *arr = [properties valueForKey:name];
                if (!arr)
                {
                    arr = [[NSMutableArray alloc] init];
                    [properties setValue:arr forKey:name];
                }

                for (NSManagedObject *o in [self mutableSetValueForKey:name])
                {
                    [arr addObject:[o propertiesDictionary]];
                }
            }
            else
            {
                NSManagedObject *o = [self valueForKey:name];
                [properties setValue:[o propertiesDictionary] forKey:name];
            }
        }
    }
}



Related