0

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?

3
  • is each view using its own Managed Object Context? Commented Oct 19, 2013 at 9:51
  • No, the context is the same. Every view asks the AppDelegate for the context. If the context hasn't been initialised, it's initialised and returned. If it has, the AppDelegate simply returns it. Commented Oct 19, 2013 at 10:08
  • 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 whatever, and update the @property array. Before database updating, the @property array has to be assigned back to the entity attribute. Commented Oct 19, 2013 at 11:29

2 Answers 2

2

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!) }
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks but Core Data can do it by Transformable. I've tried this and it works.
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 whatever, and update the @property array. Before database updating, the @property array has to be assigned back to the entity attribute.
If you've solved it, you should post your answer in detail so that others can read and understand your solution. Also, why didn't you use a one-to-many relationship with a different entity type?
The website said I can't answer my own questions within some tens of hours.Because the array has a predefined length and stores only predefined values, I didn't bother to make up a relationship.
0

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)
    {
         ...
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.