The logic behind moveItemAtIndex


#1

Hi guys,

I really don’t understand the concept behind this new logic. The result of the calculation for the newOrderValue will always the same as the to (toIndex).
Another doubt is how the order of the object that is been replaced will have its orderValue updated?

Cheers


#2

I don’t understand how to calculate newOrderValue in that way too, appreciate any
explanation.


#3

Well it’s actually not very complicate.
I also did not get it at first because I did not pay attention to the fact that we had updated the allItems array before doing anything else.

Let’s say that we have four objects in our allItems array:
item 0 (ordering value: 1)
item 1 (ordering value: 2)
item 2 (ordering value: 3)
item 3 (ordering value: 4)

I want to put item 2 between item 0 and item 1 (from: 3 to: 2).

first the method will execute this:

[code] // Get pointer to object being moved so we can re-insert it
BNRItem *p = [allItems objectAtIndex:from];

// Remove p from array
[allItems removeObjectAtIndex:from];

// Insert p in array at new location
[allItems insertObject:p atIndex:to];[/code]

So the the allItems array has been reordered like this:
item 0 (ordering value: 1)
item 2 (ordering value: 3)
item 1 (ordering value: 2)
item 3 (ordering value: 4)

Now what we need to do is to update the ordering value of item 2 so that it stays between item 0 and item 1:
lowerBound first:

double lowerBound = 0.0; // Is there an object before it in the array? if (to > 0) { lowerBound = [[allItems objectAtIndex:to - 1] orderingValue]; } else { lowerBound = [[allItems objectAtIndex:1] orderingValue] - 2.0; }

Our lowerBound is equal to:

 lowerBound = [[allItems objectAtIndex:to - 1] orderingValue]
 lowerBound = [[allItems objectAtIndex:1] orderingValue]
 lowerBound = [item 0 orderingValue]
 lowerBound = 1

Same thing with the upperBound:

double upperBound = 0.0; // Is there any object after it in the array? if (to < [allItems count] - 1) { upperBound = [[allItems objectAtIndex:to + 1] orderingValue]; } else { upperBound = [[allItems objectAtIndex:to - 1] orderingValue] + 2.0; }

Our upperBound is equal to:

upperBound = [[allItems objectAtIndex:to + 1] orderingValue]
upperBound = [[allItems objectAtIndex:3] orderingValue]
upperBound = [item 1 orderingValue]
upperBound = 2

Finally,

[code] double newOrderValue = (lowerBound + upperBound) / 2.0;

NSLog(@"moving to order %f", newOrderValue);

[p setOrderingValue:newOrderValue];[/code]

So at the end our allItems array look like this:
item 0 (ordering value: 1)
item 2 (ordering value: 1.5)
item 1 (ordering value: 2)
item 3 (ordering value: 4)


#4

I get how it works, but for this specific case where we load all items wouldn’t it be simpler to go something like

double order = 1.0;
    for(BNRItem *i in allItems)
    {
        [i setOrderingValue:order];
        order += 1.0;
    }

basically give each item their position in the array + 1 as ordering value.

(maybe i am missing something that comes later in the book, so excuses if that’s it)


#5

I agree with donPiter and was thinking of trying the same thing at some point. I can see a point where after many changes the orderingValue could become After 20 shifts into position 2 the orderingValue becomes .00001144. Additionally, I think it would be difficult to use this value in other ways if you wanted.


#6

I thought that it would be much cleaner to just re-number the orderingValues for all the items. The code below does that. Does anyone see a problem with this approach?

[code]- (void)moveItemAtIndex:(int)from
toIndex:(int)to
{
if (from == to) {
return;
}
// Get pointer to object being moved so we can re-insert it
BNRItem *p = [allItems objectAtIndex:from];

// Remove p from array
[allItems removeObjectAtIndex:from];

// Insert p in array at new location
[allItems insertObject:p atIndex:to];

double newOrderValue = 0.0;

//NSLog(@"moving to order %f", newOrderValue);
[p setOrderingValue:newOrderValue];

for (BNRItem *i in allItems) {
    NSLog(@"itemName = %@  OrderValue = %f", [i itemName],[i orderingValue]);
    newOrderValue += 1.0;
    [i setOrderingValue:newOrderValue];
}

}
[/code]

Thanks, Dwayne


#7

You have to iterate through all items. That is the problem. Just imagine you have thousands of them…