objective-c - 从核心数据中获取数组

标签 objective-c ios core-data

我建立了一个包含几个字符串字段和几个数组字段的模型。模型这样保存:

- (void)saveLevel:(NSString*)level traps:(NSArray*)traps whirls:(NSArray*)whirls accels:(NSArray*)accels walls:(NSArray*)walls dest:(NSString*)dest jupiter:(NSString*)jupiter rating:(NSNumber*)pRating;
{   
    if (m_pMOC == nil) 
       // Retrieves the managed object context

    NSManagedObject* pNewLevel = [NSEntityDescription insertNewObjectForEntityForName:@"Level" inManagedObjectContext:m_pMOC];

    NSDate* pDate = [NSDate date];

    // Must have these four attributes
    [pNewLevel setValue:level forKey:@"Level_ID"];
    [pNewLevel setValue:jupiter forKey:@"Ball"];
    [pNewLevel setValue:pDate forKey:@"Creation_Date"];
    [pNewLevel setValue:dest forKey:@"Destination"];
    [pNewLevel setValue:pRating forKey:@"Rating"];

    // Optional attributes
    if ([traps count] != 0) 
        [pNewLevel setValue:traps forKey:@"Traps"];
    if ([whirls count] != 0) 
        [pNewLevel setValue:whirls forKey:@"Whirls"];
    if ([accels count] != 0) 
        [pNewLevel setValue:accels forKey:@"Accelerators"];
    if ([walls count] != 0) 
        [pNewLevel setValue:walls forKey:@"Walls"];

    NSError* pError;
    if (![m_pMOC save: &pError]) 
    // etc...
}

我有一个 DataManager 类,它处理从 Core Data 获取/保存到 Core Data,并且在 Manager 内部我已经验证当我获取一个实体时,数组被获取,但是当它返回到正在调用的类时它,数组为零(另一方面,字符串到达​​得很好)。这是获取代码和从获取中解析出返回值的代码:

- (NSArray*) getLevelWithID:(NSString*)level
{
    NSEntityDescription *pEntityDescription = [NSEntityDescription entityForName:@"Level" inManagedObjectContext:m_pMOC];
    NSFetchRequest *pRequest = [[[NSFetchRequest alloc] init] autorelease];
    [pRequest setEntity:pEntityDescription];
    NSPredicate* pPredicate = [NSPredicate predicateWithFormat:@"Level_ID == %@", level];
    [pRequest setPredicate: pPredicate];

    NSError* pError;
    NSArray* pLevels = [m_pMOC executeFetchRequest:pRequest error:&pError];
    if (pLevels == nil) 
    {
        NSLog(@"Could not find the level with Level_ID = %@",level);
        abort();
    }

    NSArray* pAccels = [pLevels valueForKey:@"Accelerators"];
    NSArray* pTraps = [pLevels valueForKey:@"Traps"];
    NSArray* pWalls = [pLevels valueForKey:@"Walls"];
    NSArray* pWhirls = [pLevels valueForKey:@"Whirls"];

    return pLevels;
}

我在最后四个数组上设置了一个断点,它们中有对象,但在检索它们的函数中(如下所示),它们为 nil。

- (void) initLevel:(NSArray*)pLevelObjects
{
    Level* pLevel = [pLevelObjects objectAtIndex:0];

    NSString* pJupiter = pLevel.Ball;
    NSString* pDest = pLevel.Destination;

    NSArray* pAccels = [pLevel valueForKey:@"Accelerators"];
    NSArray* pTraps = [pLevel valueForKey:@"Traps"];
    NSArray* pWalls = [pLevel valueForKey:@"Walls"];
    NSArray* pWhirls = [pLevel valueForKey:@"Whirls"];
    ... (other initialization of the level) ...
}

我对此感到困惑。字符串值在那里,但数组不在。我最初尝试使用点表示法(NSArray* pAccels = pLevel.Accelerators 等),但结果相同。

想法?

编辑:从 View Controller 调用 initLevel:

- (void) startGameWithLevelID:(NSString*)pLevelID
{
    NSLog(@"MyViewController - beginGameWithLevelID");
    NSArray* pLevel = [[DataManager getDataManager] getLevelWithID:pLevelID];
    if (pLevel == nil || [pLevel count] == 0) 
    {
        NSLog(@"Didn't retrieve any level with id %@", pLevelID);
        abort();
    }
    else
    {
        CGRect newFrame = makeScreen([UIScreen mainScreen].applicationFrame);
        GameBoard* pGB = [[GameBoard alloc] initWithFrame: newFrame];
        pGB.m_pMyVC = self;
        [pGB initLevel: pLevel];
        [self.view addSubview: (UIView*)pGB];

        [pGB release];
    }
}

编辑:我最近将数组重构为与关卡具有一对一关系的独立实体;该级别与这些实体具有一对多关系。我还更改了名称以更好地遵守约定:所有属性和关系现在都以小写字母开头。我分别在属性和关系前面加上 a_ 和 r_。保存“-[NSCFString _isKindOfEntity:]: 无法识别的选择器发送到实例 0x4d83120”时出现错误。这不是很有帮助,但我会在发现问题时通知您。现在,保存代码如下所示:

- (void)saveLevel:(NSString*)level traps:(NSArray*)traps whirls:(NSArray*)whirls accels:(NSArray*)accels walls:(NSArray*)walls dest:(NSString*)dest jupiter:(NSString*)jupiter rating:(NSNumber*)pRating;
{   
    if (m_pMOC == nil) 
    { // Code to get the managed object context from the delegate
    }
    NSManagedObject* pNewLevel = [NSEntityDescription insertNewObjectForEntityForName:@"Level" inManagedObjectContext:m_pMOC];
    NSManagedObject* pNewBall = [NSEntityDescription insertNewObjectForEntityForName:@"Ball" inManagedObjectContext:m_pMOC];
    [pNewBall setValue:jupiter forKey:@"a_Bounds"];
    NSManagedObject* pNewDest = [NSEntityDescription insertNewObjectForEntityForName:@"Dest" inManagedObjectContext:m_pMOC];
    [pNewDest setValue:dest forKey:@"a_Bounds"];

    NSDate* pDate = [NSDate date];

    // Must have these four attributes
    [pNewLevel setValue:level forKey:@"a_Level_ID"];
    [pNewLevel setValue:pDate forKey:@"a_Creation_Date"];
    [pNewLevel setValue:pRating forKey:@"a_Rating"];
    [pNewLevel setValue:@"Bob Dole" forKey:@"a_CreatedBy"];

    [pNewLevel setValue:pNewBall forKey:@"r_Ball"];
    [pNewLevel setValue:pNewDest forKey:@"r_Dest"];

    // Optional attributes
    if ([traps count] != 0) 
        [[pNewLevel mutableSetValueForKey: @"r_Trap"] addObjectsFromArray: traps];
    if ([whirls count] != 0) 
        [[pNewLevel mutableSetValueForKey: @"r_Whirl"] addObjectsFromArray: whirls];
    if ([accels count] != 0) 
        [[pNewLevel mutableSetValueForKey: @"r_Accel"] addObjectsFromArray: accels];
    if ([walls count] != 0) 
        [[pNewLevel mutableSetValueForKey: @"r_Wall"] addObjectsFromArray: walls];

    NSError* pError;
    if (![m_pMOC save: &pError]) 
    { // Error saving
    }
    else
    { // Successfully saved
    }
}

再次感谢您的帮助,对于冗长的帖子深表歉意,但我希望这能帮助其他 Core Data 新手(比如我)学到一些东西。

最终编辑:好的,在重构之后,我终于找到了将数组保存为对象的解决方案(尽管我不确定这是否是最有效的方法)。下面只是添加一堆“陷阱”的代码。传递给函数的数组是 Trap 的边界,将被存储。然后与 Level 形成关系(注意它不必由 Trap 和 Level 设置,只需其中一个设置,因为 Core Data 负责另一种方式)。

if ([traps count] != 0) 
    {
        for (NSString* pBounds in traps) 
        {
            NSManagedObject* pNewTrap = [NSEntityDescription insertNewObjectForEntityForName:@"Trap" inManagedObjectContext:m_pMOC];
            [pNewTrap setValue:pBounds forKey:@"a_Bounds"];
            [pNewTrap setValue:pNewLevel forKey:@"r_Level"];
        }
    }

最佳答案

可能的数组误用

在您的第一个片段中,您在 NSArray 上调用 valueForKey:,结果是一个数组,因为该代码遍历 pLevels,将您的 valueForKey: 参数传递给内部的每个对象并组合这些值。

它是怎么来的NSArray implements Key-Value Coding .

在您的第二段代码中,您首先从数组中获取一个 pLevel,您在实体而非数组上执行 valueForKey: 选择器。所以结果就是那个特定对象中的内容。

可能您的一些实体具有这些字段,因此所有这些的组合结果具有一些值,但一些特定的实体没有。

可能的核心数据滥用

你说你在核心数据实体中保留了一个数组。你是怎样做的?没有特殊类型来保存数组,因此通常它必须存储为二进制数据,并使用 [NSKeyedArchiver archivedDataWithRootObject:array] 执行编码。可能是你的存储和获取不正确,因为你试图在非数组字段中存储数组。

您是否也遇到过任何崩溃?

关于objective-c - 从核心数据中获取数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11740942/

相关文章:

ios - Xcode 中异常的精确行

ios - 在iOS的顶部导航栏中添加多个按钮

ios - 在 iOS 中执行 'order by date' 查询所需的日期格式

ios - 核心数据 : Memory not released after manually faulting managed objects

objective-c - NSManagedObjectContext 异步或同步保存更改?

objective-c - @autoreleasepool 在@token 之前期望表达式

ios - 在 [NSString stringWithContentsOfURL :url]; 之后,选项卡 Controller 卡住并且手机变得迟钝

ios - UISlider 在 Anmation 运行时获取 Value

ios - Core Data 的线程错误

objective-c - 你如何抚摸 NSAttributedString 的_outside_?