[core-data] كيف يمكنني معرفة ما إذا كان قد تم حذف `NSManagedObject`؟



Answers

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

- (BOOL)hasManagedObjectBeenDeleted:(NSManagedObject *)managedObject {
    /*
     Returns YES if |managedObject| has been deleted from the Persistent Store, 
     or NO if it has not.

     NO will be returned for NSManagedObject's who have been marked for deletion
     (e.g. their -isDeleted method returns YES), but have not yet been commited 
     to the Persistent Store. YES will be returned only after a deleted 
     NSManagedObject has been committed to the Persistent Store.

     Rarely, an exception will be thrown if Mac OS X 10.5 is used AND 
     |managedObject| has zero properties defined. If all your NSManagedObject's 
     in the data model have at least one property, this will not be an issue.

     Property == Attributes and Relationships

     Mac OS X 10.4 and earlier are not supported, and will throw an exception.
     */

    NSParameterAssert(managedObject);
    NSManagedObjectContext *moc = [self managedObjectContext];

    // Check for Mac OS X 10.6+
    if ([moc respondsToSelector:@selector(existingObjectWithID:error:)])
    {
        NSManagedObjectID   *objectID           = [managedObject objectID];
        NSManagedObject     *managedObjectClone = [moc existingObjectWithID:objectID error:NULL];

        if (!managedObjectClone)
            return YES;                 // Deleted.
        else
            return NO;                  // Not deleted.
    }

    // Check for Mac OS X 10.5
    else if ([moc respondsToSelector:@selector(countForFetchRequest:error:)])
    {
        // 1) Per Apple, "may" be nil if |managedObject| deleted but not always.
        if (![managedObject managedObjectContext])
            return YES;                 // Deleted.


        // 2) Clone |managedObject|. All Properties will be un-faulted if 
        //    deleted. -objectWithID: always returns an object. Assumed to exist
        //    in the Persistent Store. If it does not exist in the Persistent 
        //    Store, firing a fault on any of its Properties will throw an 
        //    exception (#3).
        NSManagedObjectID *objectID             = [managedObject objectID];
        NSManagedObject   *managedObjectClone   = [moc objectWithID:objectID];


        // 3) Fire fault for a single Property.
        NSEntityDescription *entityDescription  = [managedObjectClone entity];
        NSDictionary        *propertiesByName   = [entityDescription propertiesByName];
        NSArray             *propertyNames      = [propertiesByName allKeys];

        NSAssert1([propertyNames count] != 0, @"Method cannot detect if |managedObject| has been deleted because it has zero Properties defined: %@", managedObject);

        @try
        {
            // If the property throws an exception, |managedObject| was deleted.
            (void)[managedObjectClone valueForKey:[propertyNames objectAtIndex:0]];
            return NO;                  // Not deleted.
        }
        @catch (NSException *exception)
        {
            if ([[exception name] isEqualToString:NSObjectInaccessibleException])
                return YES;             // Deleted.
            else
                [exception raise];      // Unknown exception thrown.
        }
    }

    // Mac OS X 10.4 or earlier is not supported.
    else
    {
        NSAssert(0, @"Unsupported version of Mac OS X detected.");
    }
}

الإجابة القديمة / غير الضرورية:

كتبت طريقة أفضل قليلا. self هو فئة البيانات الأساسية / تحكم.

- (BOOL)hasManagedObjectBeenDeleted:(NSManagedObject *)managedObject
{
    // 1) Per Apple, "may" be nil if |managedObject| was deleted but not always.
    if (![managedObject managedObjectContext])
        return YES;                 // Deleted.

    // 2) Clone |managedObject|. All Properties will be un-faulted if deleted.
    NSManagedObjectID *objectID             = [managedObject objectID];
    NSManagedObject   *managedObjectClone   = [[self managedObjectContext] objectWithID:objectID];      // Always returns an object. Assumed to exist in the Persistent Store. If it does not exist in the Persistent Store, firing a fault on any of its Properties will throw an exception.

    // 3) Fire faults for Properties. If any throw an exception, it was deleted.
    NSEntityDescription *entityDescription  = [managedObjectClone entity];
    NSDictionary        *propertiesByName   = [entityDescription propertiesByName];
    NSArray             *propertyNames      = [propertiesByName allKeys];

    @try
    {
        for (id propertyName in propertyNames)
            (void)[managedObjectClone valueForKey:propertyName];
        return NO;                  // Not deleted.
    }
    @catch (NSException *exception)
    {
        if ([[exception name] isEqualToString:NSObjectInaccessibleException])
            return YES;             // Deleted.
        else
            [exception raise];      // Unknown exception thrown. Handle elsewhere.
    }
}

كما ذكر James Huddleston في إجابته ، تحقق لمعرفة ما إذا كان NSManagedObject's'sagedagedObjectContext تقوم بإرجاع nil هي طريقة "جيدة جدًا" لمعرفة ما إذا تم حذف NSManagedObject مخزنة مؤقتًا / قديمة من مخزن Persistent ، ولكنها ليست دقيقة دائمًا كما تنص Apple في مستندات:

قد ترجع هذه الطريقة لا شيء إذا تم حذف المتلقي من السياق الخاص به.

متى لا يعود نيل؟ إذا حصلت على NSManagedObject مختلفة باستخدام NSManagedObject's -objectID المحذوفة مثل:

// 1) Create a new NSManagedObject, save it to the Persistant Store.
CoreData        *coreData = ...;
NSManagedObject *apple    = [coreData addManagedObject:@"Apple"];

[apple setValue:@"Mcintosh" forKey:@"name"];
[coreData saveMOCToPersistentStore];


// 2) The `apple` will not be deleted.
NSManagedObjectContext *moc = [apple managedObjectContext];

if (!moc)
    NSLog(@"2 - Deleted.");
else
    NSLog(@"2 - Not deleted.");   // This prints. The `apple` has just been created.



// 3) Mark the `apple` for deletion in the MOC.
[[coreData managedObjectContext] deleteObject:apple];

moc = [apple managedObjectContext];

if (!moc)
    NSLog(@"3 - Deleted.");
else
    NSLog(@"3 - Not deleted.");   // This prints. The `apple` has not been saved to the Persistent Store yet, so it will still have a -managedObjectContext.


// 4) Now tell the MOC to delete the `apple` from the Persistent Store.
[coreData saveMOCToPersistentStore];

moc = [apple managedObjectContext];

if (!moc)
    NSLog(@"4 - Deleted.");       // This prints. -managedObjectContext returns nil.
else
    NSLog(@"4 - Not deleted.");


// 5) What if we do this? Will the new apple have a nil managedObjectContext or not?
NSManagedObjectID *deletedAppleObjectID = [apple objectID];
NSManagedObject   *appleClone           = [[coreData managedObjectContext] objectWithID:deletedAppleObjectID];

moc = [appleClone managedObjectContext];

if (!moc)
    NSLog(@"5 - Deleted.");
else
    NSLog(@"5 - Not deleted.");   // This prints. -managedObjectContext does not return nil!


// 6) Finally, let's use the method I wrote, -hasManagedObjectBeenDeleted:
BOOL deleted = [coreData hasManagedObjectBeenDeleted:appleClone];

if (deleted)
    NSLog(@"6 - Deleted.");       // This prints.
else
    NSLog(@"6 - Not deleted.");

ها هي النسخة المطبوعة:

2 - Not deleted.
3 - Not deleted.
4 - Deleted.
5 - Not deleted.
6 - Deleted.

كما ترون ، لن ترجع دوماً سيبيريدوبيككونتيكست نيل إذا تم حذف NSManagedObject من مخزن Persistent.

Question

لدي NSManagedObject تم حذفه ، وتم حفظ السياق الذي يحتوي على هذا الكائن المدار. أتفهم أنه تم إرجاع "إرجاع" YES إذا طلبت Core Data من المخزن الدائم حذف الكائن أثناء عملية الحفظ التالية. ومع ذلك ، منذ حدوث الحفظ بالفعل ، يتم إرجاع isDeleted NO .

ما هي الطريقة الجيدة لمعرفة ما إذا كان قد تم حذف NSManagedObject بعد حفظ السياق المحتوي الخاص به؟

(في حال كنت تتساءل عن السبب في أن الكائن الذي يشير إلى الكائن المدار المحذوف ليس مدركًا بالفعل للحذف ، فذلك بسبب بدء الحذف وحفظ السياق من خلال مؤشر ترابط الخلفية الذي أجرى عملية الحذف وحفظ باستخدام performSelectorOnMainThread:withObject:waitUntilDone: .)




تم التحقق منه في Swift 3، Xcode 7.3

يمكنك أيضًا ببساطة PRINT مراجع الذاكرة لكل سياق والتحقق منها

(a) if the context exists,
(b) if the contexts of 2 objects are different

على سبيل المثال :( كتاب وعضو يجري 2 كائنات مختلفة)

 print(book.managedObjectContext)
 print(member.managedObjectContext)

ستقوم بطباعة شيء كهذا إذا كانت السياقات موجودة ولكنها مختلفة

0x7fe758c307d0
0x7fe758c15d70



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

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

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

هذا هو ... لمزيد من المعلومات ، وإعطاء فرصة لدليل أبل برمجة البيانات الأساسية ، والتزامن مع الفصل البيانات الأساسية. هناك قسم "تعقب التغييرات في مؤشرات الترابط الأخرى باستخدام إعلامات" ، ولكن لا تنس التحقق من السابقة "استخدام خيط التتابع لدعم التوافق".




Related