Сбой iPhone Core Data с ARC - PullRequest
       1

Сбой iPhone Core Data с ARC

2 голосов
/ 29 ноября 2011

Я впервые пытаюсь использовать как ARC, так и Core Data. Я не могу понять, почему мой код падает.

в .h у меня есть:

@interface Foo : NSObject {
}
@property (nonatomic,strong) NSString *name;
@property (nonatomic,strong) NSString *email;
@property (nonatomic) BOOL myBool;
@property (nonatomic) float myFloat;

в .м

@implementation User

@dynamic name;
@dynamic email;
@dynamic myBool;
@dynamic myFloat;

User *user = (User *)[NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:[appDelegate managedObjectContext]];

[user setName:[[[dictionary objectForKey:@"user"] objectForKey:@"user"]objectForKey:@"name"]];
[user setEmail:[[[dictionary objectForKey:@"user"] objectForKey:@"user"]objectForKey:@"email"]];
[user setAuthorisation_token:[[[dictionary objectForKey:@"user"] objectForKey:@"user"]objectForKey:@"authentication_token"]];
[user setMyFloat:5]; <------ crash when set to anything other than 0 (eg,setting to FALSE will crash it).
[user setMyBool:FALSE]; <---- crash when set this to anything other than 0.

Обычно, когда я пытаюсь использовать тип, отличный от строки, в этой конкретной строке происходит сбой EXEC. Когда я использую строки для всего, это нормально. В файле my.xcdatamodeld для myFloat установлено значение FLOAT, а для myBool установлено значение BOOLEAN

kill
error while killing target (killing anyway): warning: error on line 2184 of "/SourceCache/gdb/gdb-1708/src/gdb/macosx/macosx-nat-inferior.c" in function "void macosx_kill_inferior_safe()": (os/kern) failure (0x5x)
quit
Program ended with exit code: 0

1 Ответ

6 голосов
/ 29 ноября 2011

Вы не можете использовать @dynamic для примитивов (таких как float и BOOL), потому что Core Data не создаст для них реализации.

Поэтому причина, по которой ваш код падает, заключается в том, что при использовании @dynamic Вы говорите компилятору: «Я обещаю, что реализация для этих методов получения и установки будет доступна во время выполнения».Но поскольку Core Data их не создает, ваш код пытается вызвать методы, которых не существует.

Вместо этого вы можете сделать две вещи: использовать NSNumber для BOOL и float или реализовать свой.собственные методы получения и установки.

Использование NSNumber: Базовые данные используют только объекты, а не примитивы, но вы можете указать логическое значение или значение с плавающей точкой в ​​модели.Когда вы вызываете [user myFloat], вы фактически получите NSNumber со значением с плавающей точкой внутри него.Чтобы получить доступ к примитиву, вам нужно позвонить float f = [[user myFloat] floatValue];.То же самое относится и к логическому значению, оно также сохраняется в NSNumber.Поэтому, когда вы попытаетесь получить к нему доступ, вы получите NSNumber, который вам нужен для вызова BOOL b = [[user isMyBool] boolValue];, чтобы вернуть примитив.

То же самое происходит и наоборот, при установке myFloat и myBool вам нужночтобы хранить их внутри NSNumber, например, [user setMyFloat:[NSNumber numberWithFloat:f]]; и [user setMyBool:[NSNumber numberWithBool:b]];.

Чтобы использовать этот подход , вам придется изменить два последних свойства на

@property (nonatomic, strong) NSNumber *myBool;
@property (nonatomic, strong) NSNubmer *myFloat;

но вы можете оставить @dynamic для них обоих.

Реализация собственных методов получения и установки: Для вашего удобства вам может потребоваться, чтобы ваш пользовательский объект получал и устанавливал типы примитивов float и BOOL напрямую.В этом случае вы должны сохранить свойства как float и bool и в вашем файле реализации (.m) удалите строки @dynamic для myFloat и myBool.

Для реализации метода получения и установки вам нужно немного знатьо KVC / KVO и основных данных.Вкратце: вам нужно сообщить системе, когда вы собираетесь получить доступ к свойству или изменить его, а также когда вы закончите доступ к нему или его изменение, поскольку Core Data не сделает этого за вас.Между «будет доступ / изменение» и «сделал доступ / изменение» вы можете свободно извлекать или изменять свойства.Еще одно предостережение в том, что Core Data по-прежнему не может сохранять BOOL и напрямую перемещаться, поэтому их нужно упаковывать и распаковывать из NSNumbers при получении и настройке.

Кроме того, вы не можете вызвать [self setValue:ForKey:]; или [self valueForKey:@""];, потому что это приведет к тому, что метод, в котором вы находитесь, вызовет сам себя и бросит вас в бесконечный цикл.Core Data решает этот вариант использования, позволяя вам получить и установить значение, не затрагивая вашу собственную реализацию, вызывая [self setPrimitiveValue:ForKey:] и [self primiveValueForKey:]. Примечание: primiteValueForKey не имеет ничего общего с примитивными типами (int, float, BOOL), а является просто названием методов, которые вы используете для получения и установки значений в Core Data напрямую.

Реализация для вашего float и BOOL будет выглядеть примерно так:

- (float)myFloat 
{
    [self willAccessValueForKey:@"myFloat"];
    float f = [[self primitiveValueForKey:@"myFloat"] floatValue];
    [self didAccessValueForKey:@"myFloat"];
    return f;
}

- (void)setMyFloat:(float)f 
{
    [self willChangeValueForKey:@"myFloat"];
    [[self setPrimitiveValue:[NSNumber numberWithFloat:f] forKey:@"myFloat"];
    [self didChangeValueForKey:@"myFloat"];
}

- (BOOL)isMyBool 
{
    [self willAccessValueForKey:@"myBool"];
    BOOL b = [[self primitiveValueForKey:@"myBool"] boolValue];
    [self didAccessValueForKey:@"myBool"];
    return b;
}

- (void)setMyBool:(BOOL)b 
{
    [self willChangeValueForKey:@"myBool"];
    [[self setPrimitiveValue:[NSNumber numberWithBool:b] forKey:@"myBool"];
    [self didChangeValueForKey:@"myBool"];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...