2011-08-19 5 views
9

मुझे कोर डेटा में व्यस्त संबंधों के साथ एक बहुत ही अजीब समस्या है, और मैंने विंडो टेम्पलेट के आधार पर एक्सकोड में एक नई परियोजना से शुरू होने पर, मेरी समस्या को कम से कम उदाहरण में कम करने में कामयाब रहा है कोर डेटा के समर्थन के साथ (यानी, वहां बहुत कम है)।उलटा संबंध सेट नहीं है (केवीओ हैंडलर में)

मान लीजिए कि हमारे पास तीन इकाइयों के साथ कोर डेटा मॉडल है: विभाग, कर्मचारी, और विभागसमरी (कुछ प्रकार की इकाई विभाग के बारे में कुछ आंकड़ों का प्रतिनिधित्व करती है)। सादगी के लिए, हमारे पास केवल एक-से-एक संबंध हैं:

DepartmentSummary Department  Employee 
--------------------------------------------------------- 
        employee <----> department 
department <----> summary 

यह सब मॉडल में है। application:didFinishLaunchingWithOptions: में हम एक कर्मचारी और एक विभाग और KVO सेट अप बनाने के लिए:

NSManagedObject* employee = 
[NSEntityDescription 
    insertNewObjectForEntityForName:@"Employee" 
    inManagedObjectContext:[self managedObjectContext]]; 
[employee addObserver:self forKeyPath:@"department" options:0 context:nil]; 

NSManagedObject* department = 
    [NSEntityDescription 
    insertNewObjectForEntityForName:@"Department" 
    inManagedObjectContext:[self managedObjectContext]]; 
[department setValue:employee forKey:@"employee"]; 

KVO हैंडलर के उद्देश्य के रूप में जल्द ही कर्मचारी के विभाग की स्थापना की है विभाग के लिए एक सारांश बनाने के लिए है:

- (void) observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context 
{ 
    [self createSummary:object]; 
} 

createSummary सरल है: यह एक नया सारांश वस्तु बनाता है और विभाग के साथ यह संबद्ध करेगा और तो जाँच करता है सारांश वस्तु के लिए विभाग से उलटा संबंध भी सेट कर दिया जाता है कि:

- (void) createSummary:(NSManagedObject*)employee 
{ 
    NSManagedObject* department = [employee valueForKey:@"department"]; 
    NSManagedObject* summary = 
    [NSEntityDescription 
     insertNewObjectForEntityForName:@"DepartmentSummary" 
     inManagedObjectContext:[self managedObjectContext]]; 

    [summary setValue:department forKey:@"department"]; 

    NSAssert([department valueForKey:@"summary"] == summary, 
      @"Inverse relation not set"); 
} 

यह दावा विफल रहता है। वास्तव में, अगर हम विभाग और सारांश वस्तुओं प्रिंट के बाद सारांश के विभाग स्थापित किया गया है, हम

entity: DepartmentSummary; 
    id: ..DepartmentSummary/..AA14> ; 
    data: { 
    department = "..Department/..AA13>"; 
    } 
सारांश के लिए

मिलता है, के रूप में उम्मीद है, लेकिन

entity: Department; 
    id: ..Department/..AA13> ; 
    data: { 
    employee = "..Employee/..AA12>"; 
    summary = nil; 
    } 
(एक nil साथ विभाग के लिए

सारांश)। यदि फिर भी हम createSummary करने के लिए कॉल में देरी यह runloop की अगले चरण तक नहीं चलता है तो यह है कि:

- (void) observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context 
{ 
    [self performSelector:@selector(createSummary:) 
       withObject:object 
       afterDelay:0]; 
} 

तो सब कुछ उम्मीद के रूप में काम करता है। उलटा संबंध वास्तव में, यदि आप डेटाबेस को बचाने के लिए थे वस्तु ग्राफ में निर्धारित करते हैं, करता है, हालांकि यह डेटाबेस में तैयार हो जाओ (नहीं मिलता है और पुन: प्रारंभ:

अभिकथन बजाय करता नहीं मदद में देरी ऐप, अब अचानक अचानक उलटा संबंध दिखाई देता है)।

क्या यह कोर डेटा में एक बग है? क्या यह दस्तावेज व्यवहार है जिसे मैंने याद किया है? क्या मैं कोर डेटा का उपयोग ऐसे तरीके से कर रहा हूं जिसका इरादा नहीं था?

ध्यान दें कि KVO हैंडलर कहा जाता हो जाता है, जबकि कोर डाटा (स्वतः) है की स्थापना एक (अन्य) उलटा: हम स्वयं विभाग के employee क्षेत्र निर्धारित करते हैं, कोर डेटा स्वचालित रूप कर्मचारी की department फ़ील्ड सेट करता है, और कहा कि बदले में चलाता है केवीओ हैंडलर। शायद यह है कि कोर डेटा को संभालने के लिए के लिए :) दरअसल जब हम सेट

[employee setValue:department forKey:@"department"]; 

बजाय, सब कुछ फिर से अपेक्षा के अनुरूप काम करता है बहुत ज्यादा है।

किसी भी पॉइंटर्स की सराहना की जाएगी।

+0

क्या होगा यदि आप तुरंत सारांश सेट करते हैं, लेकिन अगले * रनरॉप तक * आपके * दावे * में देरी करें? – jtbandes

+0

उत्कृष्ट सवाल। मैं इसका जवाब देने के लिए प्रश्न संपादित करूंगा - मूल रूप से, दावे में देरी से मदद नहीं मिलती है। – edsko

+0

हाय, मैंने वही देखा, यह पहले काम कर रहा था ... – RolandasR

उत्तर

4

यह एक क्लासिक कोर डेटा समस्या है। डॉक्स विशेष रूप से राज्य:

के बाद से कोर डाटा आप के लिए वस्तु ग्राफ स्थिरता रखरखाव का ख्याल रखता है, आप केवल एक रिश्ते के एक छोर बदलने की जरूरत है और अन्य सभी पहलुओं आप के लिए प्रबंधित कर रहे हैं।

हालांकि, व्यावहारिक रूप से यह एक गंजा चेहरा वाला झूठ है, जिसमें यह अविश्वसनीय है।

मेरे जवाब अपने प्रश्नों के इस प्रकार है:

इस कोर डेटा में एक बग है?

हाँ।

इस प्रलेखित व्यवहार जो मैं चूक गया है?

सं।

एम आई मायनों में कोर डेटा का उपयोग कर यह इरादा नहीं था?

सं।

आप पहले से ही आपकी समस्या, एक ही समाधान है जो मुझे हर बार मुझे लगता है मैं कर हर एक कोर डाटा अनुप्रयोग में संबंध मूल्यों को बदल उपयोग करने के लिए 'सही' समाधान प्रदान की है। सचमुच मामलों के सैकड़ों के लिए, की सिफारिश की पैटर्न है:

[department setValue:employee forKey:@"employee"]; 
[employee setValue:department forKey:@"department"]; 

यानी, सेट संबंध अपने आप को उलटा जब भी आप रिश्ते बदल जाते हैं।

किसी के पास इस विषय पर अधिक प्रकाश हो सकता है, या आपके मुद्दे के आसपास काम करने के लिए एक और कैनन फॉर्म हो सकता है, लेकिन मेरे अनुभव में यह गारंटी देने का कोई तरीका नहीं है कि एक रिश्ते सक्रिय रूप से तब तक उपलब्ध हो जब तक कि यह मैन्युअल रूप से स्थापित न हो (आपकी समस्या दिखाती है)। सबसे महत्वपूर्ण बात यह है कि इस समाधान में दो अन्य लाभ भी हैं:

  1. यह 100% समय काम करता है।
  2. यह कोड को और अधिक पठनीय बनाता है।

अंतिम बिंदु जवाबी सहज है। एक तरफ, यह कोड को जटिल करता है और दस्तावेज़ों के अनुसार, एक छोटी, एक-पंक्ति कॉल के अनुसार, जो कुछ भी हो सकता है, जोड़कर इसे लंबा बना देता है। लेकिन मेरे अनुभव में यह प्रोग्रामर द्वारा कोर डेटा संपादक को दृष्टि से शिकार करने और मॉडल संबंधों की पुष्टि करने के लिए एक यात्रा बचाता है, जो समय-समय पर अधिक मूल्यवान है। रिश्ते को बदलने के दौरान क्या होता है, इसका एक मानसिक मॉडल होने के स्पष्ट और स्पष्ट होना बेहतर होता है।

मैं भी NSManagedObject के लिए एक सरल श्रेणी जोड़ने का सुझाव देते हैं:

@interface NSManagedObject (inverse) 

- (void)setValue:(id)value forKey:(NSString *)key inverseKey:(NSString *)inverse; 

@end 

@implementation NSManagedObject (inverse) 

- (void)setValue:(id)value forKey:(NSString *)key inverseKey:(NSString *)inverse { 
    [self setValue:value forKey:key]; 
    [value setValue:self forKey:inverse]; 
} 

@end 

के रूप में:

[department setValue:employee forKey:@"employee" inverse:@"department"]; 

कुछ ऐसे मामले हैं कि श्रेणी उनका विस्तार करना है, लेकिन मैं उदाहरण के लिए, संभाल होता है, पूरी तरह से एक अलग फैशन में हटाना।

संक्षेप में:हर समय स्पष्ट रूप से अपने सभी रिश्तों को संभाल लें। कोर डेटा इस संबंध में भरोसेमंद नहीं है।

+0

हम्म। दिलचस्प। मैंने पाया है कि हालांकि संबंध स्थापित करते समय यह अधिक है। रिकॉर्ड हटाने पर भी इसी तरह की समस्या होती है; उलटा संबंध शून्य पर सेट नहीं किया जा सकता है। क्या आप इसे मैन्युअल रूप से भी सौदा करते हैं? मुझे चिंता होगी कि मैं लापता मामलों को शुरू करूंगा। अभी के लिए, मैंने यह सुनिश्चित कर लिया है कि मैंने किसी केवीओ हैंडलर में ऑब्जेक्ट ग्राफ़ को कभी नहीं बदला; मैं गणना करता हूं कि क्या करने की आवश्यकता है और फिर इसे रनलोप के अगले पुनरावृत्ति के लिए शेड्यूल करें। यह काम करता है, लेकिन मुझे यह आउट-ऑफ-ऑर्डर निष्पादन स्वीकार करना होगा कोड को और अधिक जटिल बनाता है। – edsko

+0

हां, हटाते समय, मैं हमेशा रिश्ते को मैन्युअल रूप से सेट करता हूं। मेरे अनुभव में कोर डेटा विश्वसनीय रूप से दस्तावेज़ों में बताए गए नियमों के अनुसार हटाने के लिए ऑब्जेक्ट शेड्यूल करता है, इसलिए यह कोई समस्या नहीं है। स्पष्टीकरण के लिए, कोर डेटा वास्तव में यह बताता है कि यह सबकुछ करता है, केवल यह कि जब आप अपने कोड में खोजते हैं, तो "अभी" के बजाय यह "सुविधाजनक" होने पर कुछ संचालन करता है। यदि आपको एपैप उपलब्ध रिश्ते की ज़रूरत है, तो आपको इसे स्वयं सेट करना चाहिए। यदि आपको केवल अगली बार रनूओप आपके यूआई को सेट करने की आवश्यकता है, तो स्वचालित सिस्टम इसे संभाल लें। – SG1

+0

इसके अलावा, अगर मैं आप थे, तो मैं केवीओ हैंडलरों में रिश्तों को बदलने के लिए वापस जाऊंगा। यह पूरी तरह से सामान्य है। मैं कोर डेटा परिवर्तन प्रचार के लिए अपने रनटाइम का आविष्कार करने के बारे में नहीं जाऊंगा *। यहां वास्तविक अंतर्दृष्टि यह समझ रही है कि आपको रिश्तों को मैन्युअल रूप से प्रबंधित करने की आवश्यकता है, न कि आपको "प्रतीक्षा करें" और फिर बाद में परिवर्तनों को संभालने की आवश्यकता है। – SG1

0

सम्मिलित करने के बाद प्रबंधित प्रबंधित ऑब्जेक्ट कॉन्टेक्स्ट को सहेजने के बारे में कैसे?

+0

न तो एमओसी को सहेजना और न ही कॉलिंग प्रक्रिया करना: चेंजिंग: मदद करता है। – edsko

संबंधित मुद्दे