I am stuck on the Gold Challenge


#1

Hi,

Could you give me some hints on the Gold challenge?

I tried to use the following solution. In the following method, it tried to compare the destinationIndexPath.row with the total row number. If it is less than the total row number, then it should be allow the move. Otherwise, it will not.

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    NSLog(@"%d, %d", destinationIndexPath.row, [[[BNRItemsStore sharedStore] allItems] count]);
    
    if (destinationIndexPath.row < [[[BNRItemsStore sharedStore] allItems] count]) {
        [[BNRItemsStore sharedStore] moveItemAtIndex:sourceIndexPath.row toIndex:destinationIndexPath.row];
    }
}

I use NSLog to print the destinationIndexPath.row and [[[BNRItemsStore sharedStore] allItems] count] value, even the previous one is equal to the second one but it still perform the move, which really confuses me.

Please let me know where I did wrong.

Thanks.


#2

This was a frustrating problem for me too, but I happened to solve it back in the silver challenge, and then the gold challenge was finished before I ever read what the challenge was!

The problem is that moveRowAtIndexPath is a UITableViewDataSource method, when what you really need to do is stop the unwanted move action before the data source is ever invoked. That means that you need a UITableViewDelegate method! If you look at the task list in the documentation for that Delegate, you will see that there is only one that fits the bill.

I felt like my understanding of all of this stuff took a serious turn when I finally realized all that. Hopefully you will feel the same way!


#3

As I see it its still possible to deal with this with with a dataSourceDelegate method. Although it still allows the move, if you call reloadData on the tableview you can immediately correct the attempted move beyond “No more items” to move the item to the last but one row…

-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{

    if ([destinationIndexPath row]>[[[BNRItemStore sharedStore]allItems]count]-1) {
        [[BNRItemStore sharedStore]moveItemAtIndex:[sourceIndexPath row] toIndex:[[[BNRItemStore sharedStore]allItems]count]-1];
    }else{
        
        [[BNRItemStore sharedStore]moveItemAtIndex:[sourceIndexPath row] toIndex:[destinationIndexPath row]];
    }
    [tableView reloadData];
}

#4

I had exactly the same problem but managed to figure it out now. Thanks for the help PneumaPilot.
The confusion comes from the fact that changing the datasource (the allItems array) has NO effect on the tableView once it’s loaded.
To do the challenge, you can use the delegate method that PneumaPilot pointed out, which can control whether or not the tableView entry get’s moved in the first place. This is my code:

- (NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
       toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
    if (sourceIndexPath.row == ([[BNRItemStore sharedStore].allItems count] - 1)) {
        return sourceIndexPath;
    } else if (proposedDestinationIndexPath.row == ([[BNRItemStore sharedStore].allItems count] - 1)){
        return sourceIndexPath;
    } else {
        return proposedDestinationIndexPath;
    }
}

Alternatively you can use the reload method.


#5

There is an easy way to do this.

Check my solution!

[code]-(NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
//Gold Challenge Solution

//Prevents from under No more Items!
//source indexPath is equivalent one of the rows from our array count, so like the No more Items!  really does not exist in our source
//Then it is not possible to move beyond the No more Items! cell/row equivalent to proposedDestinationIndexPath.

if (sourceIndexPath.row > proposedDestinationIndexPath.row) {
    return proposedDestinationIndexPath;
}else {
    return sourceIndexPath;
}

}
[/code]

I hope i could help you!


#6

Here’s my solution:

- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{

    NSArray *allItems = [[BNRItemStore sharedStore] allItems];
    //Allows you to reorder everything above "No more items!"
    //also prevents to put a row under "No more items!"
    if (proposedDestinationIndexPath.row >= [allItems count] ) {
        
        return sourceIndexPath;
        
    } else {
        
        return proposedDestinationIndexPath;
        
    }
}

#7

[quote=“SirGodart”]Here’s my solution:

[code]

  • (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
    {

    NSArray *allItems = [[BNRItemStore sharedStore] allItems];
    //Allows you to reorder everything above “No more items!”
    //also prevents to put a row under "No more items!"
    if (proposedDestinationIndexPath.row >= [allItems count] ) {

      return sourceIndexPath;
    

    } else {

      return proposedDestinationIndexPath;
    

    }
    }
    [/code][/quote]

This is the best solution from @SirGodart.

The other two solutions has problems with the las row because they doesn’t let you move the last row to the top either.


#8

All I did was validate that only the first section (the data section - and not the “No more items” section) was being involved in the re-order

If only section 0 (I know, it’s a magic number), then do the move, else reload the data (show the data on screen back to where it belongs)

-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
    if (sourceIndexPath.section == 0 && destinationIndexPath.section == 0)
    {
        [[BNRItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row toIndex:destinationIndexPath.row];
    }
    else
    {
        [tableView reloadData];
    }
}