52 votes

iPhone : Enregistrer un booléen dans Core Data

J'ai configuré l'un de mes attributs de données de base comme un booléen. Maintenant, j'ai besoin de le définir, mais XCode continue à me dire qu'il peut ne pas répondre à setUseGPS.

[ride setUseGPS: useGPS.on];

Quelle est la méthode permettant de définir un booléen dans les données de base ? Tous mes autres attributs sont définis de cette manière, et ils fonctionnent parfaitement. Je ne sais donc pas pourquoi un booléen ne peut pas être défini de cette manière.

133voto

RickiG Points 6348

Les données de base "n'ont pas" un type booléen (elles en ont un, mais c'est un NSNumber).

Donc pour définir l'équivalent de useGPS = YES.

[entity setUseGPS:[NSNumber numberWithBool:YES]];

Et dans l'autre sens :

BOOL isGPSOn = [[entity useGPS] boolValue];

Mise à jour : Comme l'a souligné SKG, avec les littéraux dans Objetive-C vous pouvez maintenant le faire d'une manière plus simple :

[entity setUseGPS:@YES];

BOOL isGPSOn = entity.useGPS.boolValue;

9 votes

Vous pouvez également définir les valeurs de cette manière : object.isGPSOn = @YES;

0 votes

Apparemment, je peux effectivement voir le type booléen dans la liste déroulante lorsque je crée un nouvel attribut dans l'éditeur de données principal. Qu'en est-il ?

18voto

paulkmoore Points 887

Comme approche alternative à la réponse acceptée, vous pouvez simplement changer le typage d'un NSNumber* à un BOOL dans la définition de l'interface de l'objet géré, comme suit :

@property (nonatomic) BOOL useGPS;   // Notice that the 'retain' is also removed as we're now dealing with a scalar rather than an NSObject

Différentes approches alternatives sont discutées aquí pero Chris Hanson La réponse de l'auteur a été très éclairante pour moi, en particulier :

Si vous avez un attribut numérique (y compris un attribut booléen) qui est requis, vous pouvez simplement le saisir comme un scalaire à la place, et Core Data fera la bonne chose :

@property (nonatomic) BOOL isDone ;

Même si l'attribut est facultatif, cela fonctionnera toujours - il faudra juste simplement confondre "non présent" et "faux".

et pour une mise en œuvre plus alignée de Cocoa :

Une autre chose que vous pourriez vouloir faire est de nommer la propriété "done" et juste spécifier le getter comme "isDone". C'est la convention de nommage habituelle de Cocoa :

@property (nonatomique, getter=isDone) BOOL fait ;

Vous pouvez alors écrire "if (item.done) { ... }" ou "item.done = NO ;" et le compilateur générera toujours compilateur générera toujours -isDone pour les accès à la propriété.

Merci Chris, et j'espère que cela aidera quelqu'un.

1 votes

Je constate un plantage sur iOS 4.x lorsque j'essaie cette méthode. Voici le message : "La propriété 'bar' est un type scalaire sur la classe 'Foo'. Impossible de générer une méthode getter pour elle". J'ai essayé de définir le type d'attribut sur Boolean dans le modèle de données de base, et j'ai également essayé Integer 16. J'obtiens le même plantage dans les deux cas. Est-ce que quelque chose m'échappe ? Je vais peut-être revenir à l'utilisation de NSNumber.

2 votes

Pour autant que je sache, cela ne fonctionne pas sur les sous-classes de NSManagedObject.

2voto

Nicolás Carrasco Points 1495

Juste pour compléter la réponse de @RickiG, la façon de créer une NSNumber d'un Bool et vice-versa en Swift (au moins depuis la v4.2) est :

let nsNumberFromBool = NSNumber(booleanLiteral: true) // or false
let boolFromNSNumber = nsNumberFromBool.boolValue

0voto

Adam Points 17726

La "solution" à ce problème (selon moi, il s'agit d'un bug du SDK d'Apple) consiste à ajouter le code suivant à votre classe générée par CoreData. NB : si vous faites cela dans une catégorie, dans un fichier séparé, vous n'aurez pas à le recopier/coller à chaque fois que vous régénérerez les classes CoreData dans Xcode.

- (BOOL)useGPS
{
    [self willAccessValueForKey:@"useGPS"];
    BOOL myuseGPS = [[self primitiveUseGPS] boolValue];
    [self didAccessValueForKey:@"useGPS"];
    return myuseGPS;
}

- (void)setUseGPS:(BOOL)newValue
{
    [self willChangeValueForKey:@"useGPS"];
    [self setPrimitiveUseGPS:[NSNumber numberWithBool:newValue]];
    [self didChangeValueForKey:@"useGPS"];
}

0 votes

Cela conduit à des types contradictoires lorsque je compile. Devrais-je modifier les types des propriétés NSNumber existantes ?

0 votes

@Daniel Wood - ne changez pas les types existants : CoreData exige qu'ils soient des NSNumber. Les avertissements de compilation sont irritants - la solution facile est de renommer les deux méthodes ci-dessus en "useGPSAsBool" et "setUseGPSAsBool". NB : vous pouvez toujours accéder à la propriété, mais elle s'appelle maintenant "GPSAsBool", par exemple "if( myCoreDataObject.GPSAsBool )".

0 votes

Après avoir lu ce qui suit dans les docs, j'ai décidé de ne pas m'embêter avec tout cela et de simplement convertir à partir de NSNumber dans mon code : "Les avantages de permettre à Core Data de gérer son propre stockage l'emportent généralement sur les avantages d'interagir directement avec des valeurs scalaires." developer.apple.com/library/iOS/#documentation/Cocoa/Conceptual/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X