कोर डेटा के साथ एनम को लागू करने का सबसे अच्छा तरीका


109

मूल्यों को मानने के लिए कोर डेटा संस्थाओं को बाँधने का सबसे अच्छा तरीका क्या है ताकि मैं इकाई के लिए एक प्रकार की संपत्ति असाइन कर सकूं? दूसरे शब्दों में, मेरे पास एक संपत्ति के Itemसाथ एक इकाई है जिसे itemTypeमैं एक एनम के लिए बाध्य होना चाहता हूं, इस बारे में जाने का सबसे अच्छा तरीका क्या है।

जवाबों:


130

यदि आप किसी एनम के मान को प्रतिबंधित करना चाहते हैं, तो आपको कस्टम एक्सेसर्स बनाने होंगे। तो, पहले आप एक एनम की घोषणा करेंगे, जैसे:

typedef enum {
    kPaymentFrequencyOneOff = 0,
    kPaymentFrequencyYearly = 1,
    kPaymentFrequencyMonthly = 2,
    kPaymentFrequencyWeekly = 3
} PaymentFrequency;

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

- (PaymentFrequency)itemTypeRaw {
    return (PaymentFrequency)[[self itemType] intValue];
}

- (void)setItemTypeRaw:(PaymentFrequency)type {
    [self setItemType:[NSNumber numberWithInt:type]];
}

अंत में, आप को लागू करना चाहिए + keyPathsForValuesAffecting<Key>ताकि आप आइटम टाइप होने पर आइटम टाइप के लिए केवीओ सूचनाएं प्राप्त करें।

+ (NSSet *)keyPathsForValuesAffectingItemTypeRaw {
    return [NSSet setWithObject:@"itemType"];
}

2
धन्यवाद - बहुत बुरा कोर डेटा इस मूल का समर्थन नहीं करता है। मेरा मतलब है: Xcode वर्ग फ़ाइलों को उत्पन्न करता है, क्यों नहीं enum?
कॉन्सटेंटिनो ज़ारौहास

अंतिम कोड है यदि आप आइटम ItemTypeRaw का निरीक्षण करना चाहते हैं। हालाँकि, आप केवल आइटम आइटम का निरीक्षण कर सकते हैं आइटम के बजाय आइटम टाइप करें राइट?
अनाम सफेद

2
Xcode 4.5 के साथ आपको इसकी कोई आवश्यकता नहीं है। मेरे जवाब पर एक नजर। आपको बस एनम को एक के रूप में परिभाषित करने की आवश्यकता है int16_tऔर आप सेट हैं।
डैनियल एगर्ट

79

आप इस तरह से कर सकते हैं, सरल तरीका:

typedef enum Types_e : int16_t {
    TypeA = 0,
    TypeB = 1,
} Types_t;

@property (nonatomic) Types_t itemType;

और आपके मॉडल में, itemType16 बिट नंबर होना चाहिए। सब कुछ कर दिया। कोई अतिरिक्त कोड की आवश्यकता नहीं है। बस अपने सामान्य में डाल दिया

@dynamic itemType;

यदि आप अपना NSManagedObjectउपवर्ग बनाने के लिए Xcode का उपयोग कर रहे हैं , तो सुनिश्चित करें कि " आदिम डेटा प्रकारों के लिए स्केलर गुणों का उपयोग करें " सेटिंग जाँची गई है।


4
नहीं, इसका C ++ 11 से कोई लेना-देना नहीं है। यह ObjC के लिए एक निश्चित अंतर्निहित प्रकार के साथ 3.3 समर्थन Enumerations का हिस्सा है । Cf clang.llvm.org/docs/…
डैनियल एगर्ट

6
जब भी आप मॉडल वर्ग को पुन: उत्पन्न करते हैं, तो आप इस कोड को खोने से कैसे बचते हैं? मैं श्रेणियों का उपयोग कर रहा हूं ताकि कोर डोमेन इकाइयां पुनर्जीवित हो सकें।
रोब

2
यह retainस्मृति प्रबंधन से संबंधित है, कि यह डेटाबेस में संग्रहीत होता है या नहीं।
डैनियल एगर्ट

2
मैं रोब से सहमत हूँ। मैं यह नहीं चाहता कि इसे बार-बार पुनर्जीवित किया जाए। मुझे श्रेणी पसंद है।
काइल रेडफर्न

3
@Rob श्रेणियाँ ऐसा करने का एक तरीका है, लेकिन इसके बजाय आप mogenerator का उपयोग भी कर सकते हैं: github.com/rentzsch/mogenerator । मोगेनेटर प्रति इकाई 2 कक्षाएं उत्पन्न करेगा, जहां एक वर्ग हमेशा डेटा मॉडल परिवर्तन पर लिखा जाएगा और दूसरा उप-वर्ग जो कस्टम सामान के लिए वर्ग बनाता है और कभी भी अधिलेखित नहीं होता है।
टैपमॉन्की

22

मैं जिस वैकल्पिक दृष्टिकोण पर विचार कर रहा हूं, वह एनम को बिल्कुल घोषित नहीं करना है, बल्कि इसके बजाय NSNumber पर श्रेणी विधियों के रूप में मूल्यों की घोषणा करना है।


दिलचस्प। यह निश्चित रूप से उल्लेखनीय लगता है।
माइकल गेलॉर्ड

कमाल का विचार! db में टेबल बनाने की तुलना में बहुत आसान है, जब तक कि आपकी db किसी वेब सेवा से नहीं भरी जाती है, तब शायद db टेबल का उपयोग करना सबसे अच्छा है!
लर्नर

6
यहाँ एक उदाहरण है: renovatioboy.wordpress.com/2011/10/06/...
ardochhigh

मुझें यह पसंद है। मैं अपनी परियोजना में इस दृष्टिकोण का उपयोग करने जा रहा हूं। मुझे पसंद है कि मैं NSNumber श्रेणी के भीतर मेटा डेटा के बारे में अपनी अन्य सभी मेटा जानकारी शामिल कर सकता हूं। (यानी
एनम

वास्तव में महान विचार! स्ट्रिंग पहचानने वालों को जोड़ने के लिए बहुत उपयोगी है, सीधे JSON, कोर डेटा, आदि में उपयोग करना
अस्पष्ट

5

यदि आप mogenerator का उपयोग कर रहे हैं, तो इस पर एक नज़र डालें: https://github.com/rentzsch/mogenerator/wiki/Using-enums-as-types । आपके पास उपयोगकर्ता जानकारी में itemTypeएक attributeValueScalarTypeमान के साथ एक इंटेगर 16 विशेषता हो सकती है Item। फिर, अपनी इकाई के लिए उपयोगकर्ता जानकारी में, additionalHeaderFileNameउस शीर्ष लेख के नाम पर सेट करें जिसे ItemEnum परिभाषित किया गया है। अपनी हेडर फ़ाइलें बनाते समय, mogenerator स्वचालित रूप से संपत्ति का Itemप्रकार बना देगा।


2

मैंने विशेषता प्रकार को 16 बिट पूर्णांक के रूप में सेट किया है, फिर इसका उपयोग करें:

#import <CoreData/CoreData.h>

enum {
    LDDirtyTypeRecord = 0,
    LDDirtyTypeAttachment
};
typedef int16_t LDDirtyType;

enum {
    LDDirtyActionInsert = 0,
    LDDirtyActionDelete
};
typedef int16_t LDDirtyAction;


@interface LDDirty : NSManagedObject

@property (nonatomic, strong) NSString* identifier;
@property (nonatomic) LDDirtyType type;
@property (nonatomic) LDDirtyAction action;

@end

...

#import "LDDirty.h"

@implementation LDDirty

@dynamic identifier;
@dynamic type;
@dynamic action;

@end

1

चूंकि एनमेज़ एक मानक शॉर्ट द्वारा समर्थित हैं, इसलिए आप NSNumber रैपर का उपयोग नहीं कर सकते हैं और संपत्ति को सीधे स्केलर मान के रूप में सेट कर सकते हैं। कोर डेटा मॉडल में डेटा प्रकार "इंटेगर 32" के रूप में सेट करना सुनिश्चित करें।

MyEntity.h

typedef enum {
kEnumThing, /* 0 is implied */
kEnumWidget, /* 1 is implied */
} MyThingAMaBobs;

@interface myEntity : NSManagedObject

@property (nonatomic) int32_t coreDataEnumStorage;

कोड में कहीं और

myEntityInstance.coreDataEnumStorage = kEnumThing;

या JSON स्ट्रिंग से पार्स करना या फ़ाइल से लोड करना

myEntityInstance.coreDataEnumStorage = [myStringOfAnInteger intValue];

1

मैंने इसे बहुत कुछ किया है और निम्न रूप को उपयोगी पाया है:

// accountType
public var account:AccountType {
    get {
        willAccessValueForKey(Field.Account.rawValue)
        defer { didAccessValueForKey(Field.Account.rawValue) }
        return primitiveAccountType.flatMap { AccountType(rawValue: $0) } ?? .New }
    set {
        willChangeValueForKey(Field.Account.rawValue)
        defer { didChangeValueForKey(Field.Account.rawValue) }
        primitiveAccountType = newValue.rawValue }}
@NSManaged private var primitiveAccountType: String?

इस मामले में, एनम बहुत सरल है:

public enum AccountType: String {
    case New = "new"
    case Registered = "full"
}

और इसे पांडित्य कहते हैं, लेकिन मैं इस तरह से क्षेत्र के नाम के लिए एनम का उपयोग करता हूं:

public enum Field:String {

    case Account = "account"
}

चूंकि यह जटिल डेटा मॉडल के लिए श्रमसाध्य हो सकता है, मैंने एक कोड जनरेटर लिखा है जो सभी मैपिंग को थूकने के लिए एमओएम / संस्थाओं का उपभोग करता है। मेरे इनपुट्स टेबल / पंक्ति से एनम प्रकार तक का शब्दकोश हैं। जब मैं उस पर था, तो मैंने JSON क्रमांकन कोड भी तैयार किया। मैंने इसे बहुत जटिल मॉडल के लिए किया है और यह एक बड़ा समय बचाने वाला निकला है।


0

नीचे दिया गया कोड मेरे लिए काम करता है, और मैंने इसे पूर्ण कार्य उदाहरण के रूप में जोड़ा है। मैं इस दृष्टिकोण पर राय सुनना चाहता हूं, क्योंकि मेरी योजना है कि इसे अपने पूरे ऐप में बड़े पैमाने पर इस्तेमाल किया जाए।

  • मैंने जगह में @dynamic छोड़ दिया है, क्योंकि यह संपत्ति में नामित गेट्टर / सेटर द्वारा संतुष्ट है।

  • IKenndac के उत्तर के अनुसार, मैंने डिफ़ॉल्ट गेट्टर / सेटर के नामों को ओवरराइड नहीं किया है।

  • मैंने कुछ रेंज जाँच की है जिसमें एक NSAssert टाइप किए गए वैध मूल्यों पर जाँच कर रहा है।

  • मैंने दिए गए टाइपडिफ के लिए एक स्ट्रिंग मान प्राप्त करने के लिए एक विधि भी जोड़ी है।

  • मैं "k" के बजाय "c" वाले स्थिरांक को उपसर्ग करता हूं। मैं "के" (गणित की उत्पत्ति, ऐतिहासिक) के पीछे के तर्क को जानता हूं, लेकिन ऐसा लगता है कि मैं इसके साथ ईएसएल कोड पढ़ रहा हूं, इसलिए मैं "सी" का उपयोग करता हूं। बस एक निजी चीज।

यहां एक समान प्रश्न है: एक कोर डेटा प्रकार के रूप में टाइप करें

मैं इस दृष्टिकोण पर किसी भी इनपुट की सराहना करता हूं।

Word.h

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

typedef enum {
    cPresent            = 0,    
    cFuturProche        = 1,    
    cPasseCompose       = 2,    
    cImparfait          = 3,    
    cFuturSimple        = 4,    
    cImperatif          = 5     
} TenseTypeEnum;

@class Word;
@interface Word : NSManagedObject

@property (nonatomic, retain) NSString * word;
@property (nonatomic, getter = tenseRaw, setter = setTenseRaw:) TenseTypeEnum tense;

// custom getter & setter methods
-(void)setTenseRaw:(TenseTypeEnum)newValue;
-(TenseTypeEnum)tenseRaw;
- (NSString *)textForTenseType:(TenseTypeEnum)tenseType;

@end


Word.m


#import "Word.h"

@implementation Word

@dynamic word;
@dynamic tense;

// custom getter & setter methods
-(void)setTenseRaw:(TenseTypeEnum)newValue
{
    NSNumber *numberValue = [NSNumber numberWithInt:newValue];
    [self willChangeValueForKey:@"tense"];
    [self setPrimitiveValue:numberValue forKey:@"tense"];
    [self didChangeValueForKey:@"tense"];
}


-(TenseTypeEnum)tenseRaw
{
    [self willAccessValueForKey:@"tense"];
    NSNumber *numberValue = [self primitiveValueForKey:@"tense"];
    [self didAccessValueForKey:@"tense"];
    int intValue = [numberValue intValue];

    NSAssert(intValue >= 0 && intValue <= 5, @"unsupported tense type");
    return (TenseTypeEnum) intValue;
}


- (NSString *)textForTenseType:(TenseTypeEnum)tenseType
{
    NSString *tenseText = [[NSString alloc] init];

    switch(tenseType){
        case cPresent:
            tenseText = @"présent";
            break;
        case cFuturProche:
            tenseText = @"futur proche";
            break;
        case cPasseCompose:
            tenseText = @"passé composé";
            break;
        case cImparfait:
            tenseText = @"imparfait";
            break;
        case cFuturSimple:
            tenseText = @"futur simple";
            break;
        case cImperatif:
            tenseText = @"impératif";
            break;
    }
    return tenseText;
}


@end

0

ऑटो उत्पन्न वर्गों के लिए समाधान

Xcode के कोड जेनरेटर से (ios 10 और ऊपर)

यदि आप "YourClass" नामक इकाई बनाते हैं, तो Xcode स्वचालित रूप से "डेटा मॉडल इंस्पेक्टर" में कोडेन प्रकार को डिफ़ॉल्ट रूप में "क्लास डेफिनिशन" का चयन करेगा। यह नीचे कक्षाएं उत्पन्न करेगा:

स्विफ्ट संस्करण:

// YourClass+CoreDataClass.swift
  @objc(YourClass)
  public class YourClass: NSManagedObject {
  }

उद्देश्य-सी संस्करण:

// YourClass+CoreDataClass.h
  @interface YourClass : NSManagedObject
  @end

  #import "YourClass+CoreDataProperties.h"

  // YourClass+CoreDataClass.m
  #import "YourClass+CoreDataClass.h"
  @implementation YourClass
  @end

हम Xcode में "क्लास डेफिनिशन" के बजाय कोडजेन विकल्प से "श्रेणी / एक्सटेंशन" चुनेंगे।

अब, यदि हम एक एनम जोड़ना चाहते हैं, तो अपने ऑटो-जनरेट किए गए वर्ग के लिए एक और एक्सटेंशन बनाएं, और नीचे अपनी एनम परिभाषाएँ जोड़ें:

// YourClass+Extension.h

#import "YourClass+CoreDataClass.h" // That was the trick for me!

@interface YourClass (Extension)

@end


// YourClass+Extension.m

#import "YourClass+Extension.h"

@implementation YourClass (Extension)

typedef NS_ENUM(int16_t, YourEnumType) {
    YourEnumTypeStarted,
    YourEnumTypeDone,
    YourEnumTypePaused,
    YourEnumTypeInternetConnectionError,
    YourEnumTypeFailed
};

@end

अब, आप कस्टम एक्सेसर्स बना सकते हैं यदि आप मानों को एनम तक सीमित करना चाहते हैं। कृपया प्रश्न के स्वामी द्वारा स्वीकृत उत्तर की जाँच करें । या जब आप नीचे दिए गए कास्ट ऑपरेटर का उपयोग करके स्पष्ट रूप से रूपांतरण विधि के साथ सेट करते हैं, तो आप अपनी दुश्मनी को परिवर्तित कर सकते हैं:

model.yourEnumProperty = (int16_t)YourEnumTypeStarted;

यह भी देखें

Xcode स्वचालित उपवर्ग पीढ़ी

Xcode अब मॉडलिंग टूल में NSManagedObject उपवर्गों की स्वचालित पीढ़ी का समर्थन करता है। इकाई निरीक्षक में:

मैनुअल / कोई भी डिफ़ॉल्ट और पिछला व्यवहार नहीं है; इस स्थिति में, आपको अपना उपवर्ग लागू करना चाहिए या NSManagedObject का उपयोग करना चाहिए। श्रेणी / विस्तार, क्लासनेम + CoreDataGeneratedProperties नामक फ़ाइल में एक क्लास एक्सटेंशन उत्पन्न करता है। आपको मुख्य वर्ग को घोषित करने / लागू करने की आवश्यकता है (यदि ओब्ज-सी में, हेडर के माध्यम से एक्सटेंशन ClassName.h नाम का आयात कर सकता है)। क्लास डेफिनिशन, ClassName + CoreDataClass के साथ-साथ कैटेगरी / एक्सटेंशन के लिए जनरेट की गई फ़ाइलों की तरह सबक्लास फाइलें भी बनाता है। उत्पन्न फ़ाइलों को DerivedData में रखा जाता है और मॉडल के सहेजे जाने के बाद पहले बिल्ड पर फिर से बनाया जाता है। उन्हें Xcode द्वारा अनुक्रमित भी किया जाता है, इसलिए संदर्भों पर कमांड-क्लिक करना और फ़ाइलनाम कार्यों द्वारा तेजी से खोलना।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.