iphone - أفضل طريقة لتنفيذ Enums مع البيانات الأساسية




objective-c cocoa cocoa-touch core-data (8)

ما هي أفضل طريقة لربط كيانات البيانات الأساسية بقيم التعداد بحيث يمكنني تعيين خاصية نوع للكيان؟ وبعبارة أخرى ، لدي كيان يسمى Item مع خاصية itemType أريد أن itemType ، ما هي أفضل طريقة للقيام بذلك.


Answers

نهج بديل أفكر في عدم الإعلان عن التعداد على الإطلاق ، ولكن بدلاً من ذلك ، أعلن القيم كطرق الفئات على NSNumber.


يعمل الرمز الذي تم لصقه أدناه لي ، وقد أضفته كمثال عملي كامل. أود أن أسمع آراء حول هذا النهج ، حيث أخطط لاستخدامها على نطاق واسع عبر تطبيقاتي.

  • لقد تركتdynamic في المكان ، حيث أنه راض بعد ذلك عن طريق getter / setter المسمى في الخاصية.

  • وفقا للإجابة عن طريق iKenndac ، لم أكن تجاوزت أسماء getter / setter الافتراضية.

  • لقد قمت بتضمين بعض التحقق من النطاق عبر NSAssert على القيم الصالحة لـ typedef.

  • لقد قمت أيضًا بإضافة طريقة للحصول على قيمة سلسلة لـ typedef المحدد.

  • أقوم بادئة الثوابت مع "c" بدلاً من "k". أعرف السبب وراء "k" (أصول الرياضيات ، التاريخية) ، لكنني أشعر وكأنني أقرأ شفرة ESL بها ، لذلك استخدم "c". مجرد شيء شخصي.

هناك سؤال مماثل هنا: typedef كنوع بيانات أساسية

وسأكون ممتنا أي إدخال على هذا النهج.

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

بما أن التعدادات مدعومة باختصار قياسي ، فلا يمكنك أيضًا استخدام الغلاف NSNumber وتعيين الخاصية مباشرة كقيمة قياسية. تأكد من تعيين نوع البيانات في نموذج البيانات الأساسية على أنه "Integer 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];

يمكنك القيام بهذه الطريقة ، بطريقة أبسط:

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

@property (nonatomic) Types_t itemType;

وفي النموذج الخاص بك ، قم بتعيين itemType ليكون رقمًا 16 بت. كله تمام. لا حاجة لرمز إضافي. وضعت للتو في المعتاد الخاص بك

@dynamic itemType;

إذا كنت تستخدم Xcode لإنشاء فئة فرعية NSManagedObject ، فتأكد من تحديد إعداد " استخدام قيم قياسية لأنواع البيانات البدائية ".


لقد فعلت هذا كثيرًا واعثر على النموذج التالي ليكون مفيدًا:

// 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"
}

نظرًا لأن ذلك قد يكون شاقًا بالنسبة لنماذج البيانات المعقدة ، فقد كتبت مولدًا برمجيًا يستهلك MOM / الكيانات لبث كل التعيينات. ينتهي مداخلتي إلى أن تكون قاموسًا من جدول / صف إلى نوع التعداد. بينما كنت في ذلك ، ولدت أيضا رمز التسلسل JSON. لقد فعلت ذلك لطرازات معقدة للغاية ، وتبين أنها موفرة الوقت الكبيرة.


سيتعين عليك إنشاء أدوات وصول مخصصة إذا كنت ترغب في تقييد القيم على التعداد. لذا ، أولاً ، يمكنك إعلان تعداد ، مثل:

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

ثم ، أعلن وجنتس وسيط لممتلكاتك. إنها فكرة سيئة لتجاوز الموجودة منها ، لأن المحكّلات القياسية تتوقع كائن NSNumber بدلاً من نوع قياسي ، وستواجه مشكلة إذا حاول أي شيء في الارتباطات أو أنظمة KVO الوصول إلى القيمة الخاصة بك.

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

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

وأخيرًا ، يجب تنفيذ + keyPathsForValuesAffecting<Key> حتى تحصل على إشعارات KVO لـ itemTypeRaw عند تغيير itemType.

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

إذا كنت تستخدم mogenerator ، فألق نظرة على هذا: https://github.com/rentzsch/mogenerator/wiki/Using-enums-as-types . يمكنك الحصول على سمة Integer 16 تسمى itemType ، مع قيمة attributeValueScalarType في معلومات المستخدم. ثم ، في معلومات المستخدم للكيان الخاص بك ، قم بتعيين additionalHeaderFileName إلى اسم الرأس الذي تم تعريف تعداد Item . عند إنشاء ملفات رأسك ، سيقوم mogenerator تلقائيًا بجعل الخاصية تحتوي على نوع Item .


If you want to send data from one to another viewController, here's a way to it:

Say we have viewControllers: ViewController and NewViewController.

in ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
}

@property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;

-(IBAction)goToNextScreen:(id)sender;

@end

in ViewController.m

#import "ViewController.h"

#import "NewViewController.h"

@implementation ViewController
@synthesize mytext1,mytext2,mytext3,mytext4;

-(IBAction)goToNextScreen:(id)sender
{
    NSArray *arr = [NSArray arrayWithObjects:mytext1.text,mytext2.text,mytext3.text,mytext4.text, nil];


    NewViewController *newVc = [[NewViewController alloc] initWithNibName:@"NewViewController" bundle:nil];

    newVc.arrayList = arr;

    [self.navigationController pushViewController:newVc animated:YES];

}

In NewViewController.h

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

    NSString *name,*age,*dob,*mobile;

}

@property(nonatomic, retain)NSArray *arrayList;

@end

In NewViewController.m

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [arrayList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];      
    }
    // Configure the cell...
    cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
    return cell;


}

@end

So this way we can pass the data from one viewcontroller to another view controller...





iphone objective-c cocoa cocoa-touch core-data