Mark Leonard
Mark Leonard

Reputation: 2096

Segmented Controller (Multiple Choices) with Core Data

I have a Core Data based application which is built around one main entity. There are several other entities which are connected to it, one of which is an Entity called "Notes".

This Notes entity has a Date (NSDate), a Description (NSString), and one other attribute. This attribute is to have 4 possible options, of which each entity will have at least 1 and possibly all 4.

I was thinking that when a Note is being created, there could be a Segmented Controller with the 4 possible options. (Is it even possible to select multiple buttons here?)

I further want to be able to sort all of these notes by this option. That is, to create a fetch request that returns only the Notes that had Option 3 selected, for example. (Even if they also had Option 2, or even all 4 options selected.)

Any suggestions on what the best way to implement this is?

Thanks.

Upvotes: 1

Views: 1878

Answers (3)

Alex Reynolds
Alex Reynolds

Reputation: 96937

To use masks for storing multiple selections, you might do something like the following:

NSInteger const kNoteOptionTypeOne = 0x1;   // 0000 0001
NSInteger const kNoteOptionTypeTwo = 0x2;   // 0000 0010
NSInteger const kNoteOptionTypeThree = 0x4; // 0000 0100
NSInteger const kNoteOptionTypeFour = 0x8;  // 0000 1000

For multiple selections, you would still store your combined mask as an NSNumber, e.g.

NSInteger mySelectionsMask = (kNoteOptionTypeOne | kNoteOptionTypeFour); // 0x0 | 0x4 = 1001 = 9
NSNumber *mySelections = [NSNumber numberWithInt:mySelectionsMask];

This mySelections value will be unique to some combination of the four options. You can go back from this combined mask to individual masks, in order to select different buttons of a segmented control, e.g.:

if ([mySelections intValue] == (kNoteOptionTypeOne | kNoteOptionTypeFour)) {
    // select buttons one and four of the segmented control
}
else if some other combination { etc. }

Or:

if (([mySelections intValue] & kNoteOptionTypeOne) == kNoteOptionTypeOne) 
    // select button one
if (([mySelections intValue] & kNoteOptionTypeTwo) == kNoteOptionTypeTwo)
    // select button two
... 

As this is stored as an NSNumber, you will be able to sort on it with an NSSortDescriptor instance as described above.

Upvotes: 1

gerry3
gerry3

Reputation: 21460

First, instead of trying to use one attribute to collect four possible options, I would use four separate boolean attributes. This will also allow you to filter your fetch requests very easily.

To configure each boolean, I would use a UIButton or UISwitch. The UISegmentedControl does not support multiple selection.

Upvotes: 0

Alex Reynolds
Alex Reynolds

Reputation: 96937

Use an enumeration to define four options, e.g.:

typedef enum _NoteOptionType {
    kNoteOptionTypeOne,
    kNoteOptionTypeTwo,
    kNoteOptionTypeThree,
    kNoteOptionTypeFour,
    kNoteOptionTypes,
} NoteOptionType;

These will be numbered 0 through 5.

Core Data stores integers as NSNumber instances. You could perhaps keep an attribute in your Note entity that is called optionType, which stores the NSNumber equivalent of a NoteOptionType value.

You can convert these to NSNumber options through something like, for example, [NSNumber numberWithInt:kNoteOptionTypeOne].

You could write a convenience method to convert a NoteOptionType to a string to put into a UISegmentedControl, e.g.:

+ (NSString *) keyForNoteOptionTypeTag:(NoteOptionType)optionTypeTag {
    if (optionTypeTag == kNoteOptionTypeOne)
        return [NSString stringWithFormat:@"First"];     
    else if (optionTypeTag == kNoteOptionTypeTwo)
        return [NSString stringWithFormat:@"Second"];
    ...
    return [NSString stringWithFormat:@"Undefined"];
}

Reference it like so:

NSLog(@"second option is: %@", [Note keyForNoteOptionTypeTag:kNoteOptionTypeTwo]);

In your fetch, you can use the NSNumber values you put in your Core Data store as criteria on which to sort, through the use of an NSSortDescriptor, e.g.:

NSSortDescriptor *optionTypeDescriptor = [[NSSortDescriptor alloc] initWithKey:@"optionType" ascending:YES selector:nil];
NSArray *sortDescriptors = [NSArray arrayWithObjects:optionTypeDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[optionTypeDescriptor release];

Upvotes: 0

Related Questions