2010-06-04 18 views
65

में कस्टम सेटर विधियों को मुझे NSManagedObject के मेरे सबक्लास में एक फ़ील्ड के लिए एक कस्टम सेटर विधि लिखनी होगी (हम इसे foo पर कॉल करेंगे)। foo को डेटा मॉडल में परिभाषित किया गया है और एक्सकोड ने क्रमश: .h और .m फ़ाइलों में @property और @dynamic फ़ील्ड को स्वत: उत्पन्न किया है।कोर-डेटा

अगर मैं इस तरह मेरी सेटर लिखें:

- (void)setFoo: (NSObject *)inFoo { 
    [super setFoo: inFoo]; 
    [self updateStuff]; 
} 

तो मैं super को फोन पर एक संकलक चेतावनी मिलती है।

वैकल्पिक रूप से, अगर मैं ऐसा करते हैं:

- (void)setFoo: (NSObject *)inFoo { 
    [super setValue: inFoo forKey: inFoo]; 
    [self updateStuff]; 
} 

तो मैं अनंत लूप में खत्म हो।

तो NSManagedObject के उप-वर्ग के लिए कस्टम सेटर लिखने का सही तरीका क्या है?

उत्तर

1

यहाँ NSManagedObject गुण अधिभावी (KVO को तोड़ने के बिना) अपने में, एप्पल तरीका है।मी:

@interface Transaction (DynamicAccessors) 
- (void)managedObjectOriginal_setDate:(NSDate *)date; 
@end 

@implementation Transaction 
@dynamic date; 

- (void)setDate:(NSDate *)date 
{ 
    // invoke the dynamic implementation of setDate (calls the willChange/didChange for you) 
    [self managedObjectOriginal_setDate:(NSString *)date; 

    // your custom code 
} 

managedObjectOriginal_propertyName एक अंतर्निहित जादू विधि तुम सिर्फ के लिए परिभाषा जोड़ने के लिए है। जैसा कि इस पृष्ठ के नीचे देखा गया है What's New in Core Data in macOS 10.12, iOS 10.0, tvOS 10.0, and watchOS 3.0

+0

अच्छी जगह @malhal - मुझे आईओएस 10 में इस बदलाव से अवगत नहीं था। –

100

the documentation के अनुसार, यह होगा:

- (void) setFoo:(NSObject *)inFoo { 
    [self willChangeValueForKey:@"foo"]; 
    [self setPrimitiveValue:inFoo forKey:@"foo"]; 
    [self didChangeValueForKey:@"foo"]; 
} 

यह वह जगह है, जाहिर है, इस तथ्य की अनदेखी कि NSManagedObjects केवल चाहते विशेषताओं के रूप में NSNumbers, NSDates, NSDatas, और NSStrings

हालांकि, यह सबसे अच्छा तरीका नहीं हो सकता है। चूंकि आप कुछ ऐसा करना चाहते हैं जब आपके foo संपत्ति का मूल्य बदलता है, क्यों न केवल Key Value Observing के साथ इसका निरीक्षण करें? इस मामले में, यह "केवीओ जाने का रास्ता" जैसा लगता है।

+0

धन्यवाद डेव। खेद है कि क्षेत्र वास्तव में 'एनएसएनंबर *' के रूप में परिभाषित किया गया है, लेकिन मैं समस्या को सामान्य करने की कोशिश कर रहा था। मैंने ऊपर जो सुझाव दिया है, मैंने कोशिश की है, लेकिन मुझे एक कंपाइलर चेतावनी मिलती है कि मेरी कक्षा '-setPrimitivePositionX:' का जवाब नहीं दे सकती है। कोई विचार? अच्छा विचार फिर से। KVO। पंजीकरण करने के लिए सबसे अच्छी जगह कहां होगी? '- (शून्य) जागृत करेंप्रोन्सइंटर '? मैं '- (शून्य) dealloc' सही में पंजीकरण करना होगा? –

+0

ठीक है, मैंने .m फ़ाइल में एक निजी '@ इंटरफ़ेस' अनुभाग जोड़ा और चेतावनी को ठीक किया, लेकिन कोड अभी भी अपेक्षित व्यवहार नहीं कर रहे हैं। मुझे इसे डीबग करने की ज़रूरत है! –

+0

आगे की जांच पर जब मैं स्पष्ट रूप से ऑब्जेक्ट पर मान निर्धारित करता हूं तो सेटटर को सही ढंग से कॉल किया जा रहा है, लेकिन जब मैं एनएसयूंडो मैनेजर का उपयोग वापस करने के लिए उपयोग करता हूं तो इसे कॉल नहीं किया जाता है। किस मामले में मैं अनुमान लगा रहा हूं कि केवीओ एक बेहतर ऑल-राउंड दृष्टिकोण है। –

17

मुझे लगता है कि एक मामूली गलती है: उपयोग

[self setPrimitiveValue:inFoo forKey:@"foo"]; 

[self setPrimitiveFoo:inFoo]; 

के बजाय यह मेरे लिए काम करता है।

+0

धन्यवाद मार्टिन। जैसा कि आप कहते हैं, केवीओ जाने का रास्ता है (मैं '- (शून्य) जागृत हो रहा हूं फ्रॉमफैच' और '- (शून्य) डेलोक' में पंजीकरण नहीं कर रहा हूं और अब मैंने इसे कार्यान्वित किया है और यह पूर्ववत के साथ काम करता है। –

+7

उपयोग नहीं करते - (शून्य) अनियंत्रित करने के लिए डेलोक, अनियंत्रित अवलोकन - (शून्य) willTurnIntoFault इसके बजाए। अन्यथा जब आप किसी ऑब्जेक्ट को गलती में बदलते हैं तो आपको अनावश्यक अधिसूचनाएं मिलेंगी। नई ऑब्जेक्ट्स डाली गई नहीं है - (शून्य) जागृत करें FromFetch संदेश उपयोग करें - (शून्य) जागरूक भी करें। –

+1

@Andrew Ebling, कृपया अपने स्वयं के प्रश्न का उत्तर दें और अपने समाधान का स्रोत कोड शामिल करें। (चर नामों को बदलने के लिए स्वतंत्र महसूस करें, आदि, लेकिन कृपया इसे अच्छा रखें।) मैं काम कर रहा हूं यह सही काम कर रहा हूं। मैं इसे केवीसी पर लिंक पढ़कर समझ रहा हूं, लेकिन आपका समाधान देखकर बहुत उपयोगी होगा! :) – ma11hew28

19

यहां मैं Photo : NSManagedObject की विशेषता पर केवीओ कर रहा हूं। अगर फोटो की आईडी बदलती है, तो नई तस्वीर डाउनलोड करें।

#pragma mark NSManagedObject 

- (void)awakeFromInsert { 
    [self observePhotoId]; 
} 

- (void)awakeFromFetch { 
    [self observePhotoId]; 
} 

- (void)observePhotoId { 
    [self addObserver:self forKeyPath:@"id" 
       options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change 
         context:(void *)context { 
    if ([keyPath isEqualToString:@"id"]) { 
     NSString *oldValue = [change objectForKey:NSKeyValueChangeOldKey]; 
     NSString *newValue = [change objectForKey:NSKeyValueChangeNewKey];   
     if (![newValue isEqualToString:oldValue]) { 
      [self handleIdChange]; 
     } 
    } 
} 

- (void)willTurnIntoFault { 
    [self removeObserver:self forKeyPath:@"id"]; 
} 

#pragma mark Photo 

- (void)handleIdChange { 
    // Implemented by subclasses, but defined here to hide warnings. 
    // [self download]; // example implementation 
} 
+0

यदि कोई ऑब्जेक्ट हटा दिया जाता है, तो संदर्भ सहेजा जाता है (ऑब्जेक्ट एक्टू सहयोगी deallocated), पूर्ववत आवंटित, अवलोकन गायब हो जाएगा। 10.6+ में आप awakeFromSnapshotEvents में देखरेख भी स्थापित कर सकते हैं। पिछली संगतता के लिए https://github.com/mbrugger/CoreDataDependentProperties पर एक नज़र डालें, यह वास्तव में इन सभी समस्याओं को हल करता है। –

+2

सेब के दस्तावेज़ों से, आपको "awakeFromFetch" और "awakeFromInsert" पर सुपर कॉल करना चाहिए – Fervus

+0

[newValue isEqualToString: oldValue] परीक्षण अनावश्यक है क्योंकि अधिसूचना केवल तभी आग लग जाएगी जब वे समान नहीं हैं। –

0

यहाँ कैसे आप इसे 1-एन करते हैं (और मैं एन-मीटर अनुमान) रिश्तों:

मान संबंध नाम "छात्रों" एक वस्तु "स्कूल" कहा जाता है में कहा जाता है की सुविधा देता है।

सबसे पहले आपको एनएसएमयूटेबलसेट के लिए आदिम एक्सेसर विधियों को परिभाषित करने की आवश्यकता है। एक्सकोड स्वचालित रूप से आपके लिए इन्हें उत्पन्न नहीं करेगा।

@interface School(PrimitiveAccessors) 
- (NSMutableSet *)primitiveStudents; 
@end 

अगला आप अपनी एक्सेसर विधि को परिभाषित कर सकते हैं। यहां मैं सेटर को ओवरराइड करने जा रहा हूं।

- (void)addStudentsObject:(Student *)student 
{ 
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&student count:1]; 

    [self willChangeValueForKey:@"students" 
       withSetMutation:NSKeyValueUnionSetMutation 
       usingObjects:changedObjects]; 

    [[self primitiveStudents] addObject:value]; 

    [self didChangeValueForKey:@"students" 
      withSetMutation:NSKeyValueUnionSetMutation 
       usingObjects:changedObjects]; 
}