Friday, June 21, 2013

NSMutableIndexSet removeIndex example in Objective C (iOS).


NSMutableIndexSet removeIndex

Removes an index from the receiver.

- (void)removeIndex:(NSUInteger)index

Parameters of [NSMutableIndexSet removeIndex]
index
Index to remove.

NSMutableIndexSet removeIndex example.
You may want to look at NSMutableIndexSet. It is designed to efficiently store ranges of numbers.

You can initialize it like this:

NSMutableIndexSet *set = [[NSMutableIndexSet alloc]
    initWithIndexesInRange:NSMakeRange(1, 100000)];
Then you can remove, for example, 123 from it like this:

[set removeIndex:123];
Or you can remove 400 through 409 like this:

[set removeIndexesInRange:NSMakeRange(400, 10)];
You can iterate through all of the remaining indexes in the set like this:

[set enumerateIndexesUsingBlock:^(NSUInteger i, BOOL *stop) {
    NSLog(@"set still includes %lu", (unsigned long)i);
}];
or, more efficiently, like this:

[set enumerateRangesUsingBlock:^(NSRange range, BOOL *stop) {
    NSLog(@"set still includes %lu indexes starting at %lu",
        (unsigned long)range.length, (unsigned long)range.location);
}];

Example of [NSMutableIndexSet removeIndex].
- (NSUInteger)indexForImageGivenIndexSet:(NSIndexSet*)indexSet             // Set of indexes you want to select from
                         prizeImageIndex:(NSUInteger)prizeIndex      // The prize index
                        probabilityScale:(CGFloat)probabilityScale   // The scale for the prize (8.0 for 8x less than the others)
{
    // If invalid, return what was given
    if (![indexSet containsIndex:prizeIndex]) {
        return prizeIndex;
    }

    // Calculate our probabilities
    // For a set of 4, with a scale of 8 on the prize, our probabilities would be
    // 0.04 (prize), 0.32, 0.32, 0.32
    double prizeProbability = (1.0 / indexSet.count) * (1.0 / probabilityScale);

    double val = (double)arc4random() / RAND_MAX;

    if (val < prizeProbability) {
        return prizeIndex;
    }
    else {
        // Select from the others in range equally
        NSMutableIndexSet* newSet = [[NSMutableIndexSet alloc] initWithIndexSet:indexSet];
        [newSet removeIndex:prizeIndex];

        NSInteger selectedPosition = arc4random() % newSet.count;
        __block NSInteger count = 0;
        return [newSet indexPassingTest:^BOOL(NSUInteger idx, BOOL *stop) {
            if (count == selectedPosition) {
                *stop = YES;
                return YES;
            }
            else {
                count++;
                return NO;
            }
        }];
    }
}

NSMutableIndexSet removeIndex example.
You will have to make subclass of the NSTableView class. This is basic example how you could do it. It handles selection with the spacebar and with the right mouse button, hoever it does not handle right mouse button drag selection.

The idea is to use NSTableView in single select mode and implement alternative selection. We add property markedRows and then use it instead of original selectedRows property.

FOTableView.h

#import <Cocoa/Cocoa.h>

@interface FOTableView : NSTableView

@property (strong,nonatomic) NSMutableIndexSet *markedRows;

@end
FOTableView.m

#import "FOTableView.h"

@implementation FOTableView

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
    }

    return self;
}

-(NSMutableIndexSet *) markedRows
{
    if (!_markedRows) {
        _markedRows = [NSMutableIndexSet new];
    }
    return _markedRows;
}

- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect
{
    if ([self.markedRows containsIndex:row]) {
        NSRect clipRect = [self rectOfRow:row];
        NSColor *color =  [NSColor colorWithCalibratedRed:0.932 green:0.046 blue:0.960 alpha:1.000];
        [color setFill];
        NSRectFill(clipRect);
    }

    [super drawRow:row clipRect:clipRect];
}

- (void)keyDown:(NSEvent *)theEvent
{
    NSString *keyString;
    unichar  keyChar;

    keyString = [theEvent charactersIgnoringModifiers];
    keyChar = [keyString characterAtIndex:0];
    NSInteger row = [self selectedRow];
    switch(keyChar){           
        case 32:
        {
             if (row != -1)
             {
                 if ([self.markedRows containsIndex:row]) {
                     [self.markedRows removeIndex:row];
                 }
                 else {
                     [self.markedRows addIndex:row];
                 }
             }
            [self selectRowIndexes:[NSIndexSet indexSetWithIndex:++row] byExtendingSelection:NO];
            [self setNeedsDisplay:YES];
            break;
        }

        default:
            [super keyDown:theEvent];
    }

    NSLog(@"key pressed: (%hu)%@", keyChar,keyString);
}

- (void)rightMouseDown:(NSEvent *)theEvent
{
    NSInteger row = [self rowAtPoint:[self convertPoint:[theEvent locationInWindow] fromView:nil]];
    if ([self.markedRows containsIndex:row]) {
        [self.markedRows removeIndex:row];
    }
    else {
        [self.markedRows addIndex:row];
    }

    [self setNeedsDisplay:YES];
}

@end

End of NSMutableIndexSet removeIndex example article.