user2226125
user2226125

Reputation: 29

Core Data with Array Attribute

The following is the entity Player header file.

@interface Player : NSManagedObject

@property (nonatomic, retain) NSNumber * experience;
@property (nonatomic, retain) id items;
@property (nonatomic, retain) NSNumber * level;

@end

@interface items : NSValueTransformer
@end

items is essentially an NSMutableArray with NSNumber elements. And inside one function, I'm updating this array:

- (void)itemWasDropped:(ItemIndex)item
{ // _player has been correctly retrieved from the database
    // the current number of this item
    int nNum = [[_player.items objectAtIndex:item] intValue];
    // to increment the number
    [_player.items replaceObjectAtIndex:item withObject:[NSNumber numberWithInt:nNum + 1]];
}

This function gets called perfectly. I save the context in the viewWillDisappear function.

- (void)viewWillDisappear:(BOOL)animated
{ // _moc is an NSManagedObjectContext instance that has been correctly initialised.
    // to update the database
    NSError* err = nil;
    BOOL bSucc = [_moc save:&err];
    if (err || !bSucc)
    {
        ...
    }
}

The problem is that the updates are visible in other views as long as I do not shut down the app in the task bar. What's the problem? Anyone can help?

Upvotes: 0

Views: 2971

Answers (2)

Mundi
Mundi

Reputation: 80265

Core data can store arrays, but you will have to use a "transformable" attribute. In general it is not very good design. One easy solution is to transform your numbers array into something that can be stored. For example, in many cases it is sufficient to just use a string.

Encode:

player.items = [numbers componentsJoinedByString:@","];
// Swift
player.items = numbers.joinWithSeparator(",")

Decode:

NSMutableArray* numbers = [NSMutableArray array];
for (NSString *s in [player.items componentsSeparatedByString:@","]) {
  [numbers addObject:@([s integerValue])];
}
// Swift
let numbers = player.items.characters.split { $0 == "," } .map { Int($0!) }

Upvotes: 2

user2226125
user2226125

Reputation: 29

Just solved it. In order to update an array attribute inside a Core Data entity, that array has to be assigned to another @property array in the view controller class or, and update the @property array. Before database updating, the @property array has to be assigned back to the entity attribute.

// to hold the player items
// _player.items cannot be directly updated
@property (strong, nonatomic) NSMutableArray* items;

- (void)viewDidLoad
{
    [super viewDidLoad];
    ...
    NSError* err = nil;
    NSMutableArray* results = [[_moc executeFetchRequest:fr error:&err] mutableCopy];
    if (err || results.count == 0)
    {
        ...
    } else
    {
        _player = [results objectAtIndex:0];
        _items = _player.items;
    }
}

// events
- (void)itemWasDropped:(ItemIndex)item
{
    // the current number of this item
    int nNum = [[_items objectAtIndex:item] intValue];
    // to increment the number
    [_items replaceObjectAtIndex:item withObject:[NSNumber numberWithInt:nNum + 1]];
}

- (void)viewWillDisappear:(BOOL)animated
{
    // to update the database
    _player.items = _items;
    NSError* err = nil;
    BOOL bSucc = [_moc save:&err];
    if (err || !bSucc)
    {
         ...
    }
}

Upvotes: 0

Related Questions