Gold Challenge solution


#1

Here is my solution. Once again, I started with a fresh duplicate of Homepwner. Seems to work OK.
This is my BNRAssetTypeViewController.m which is the only file that was changed.

@interface BNRAssetTypeViewController ()

@property (nonatomic) NSMutableArray *itemsOfType;

@end

@implementation BNRAssetTypeViewController

- (instancetype)init
{
    return [super initWithStyle:UITableViewStylePlain];
    
}

- (instancetype)initWithStyle:(UITableViewStyle)style
{
    return [self init];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self.tableView registerClass:[UITableViewCell class]
           forCellReuseIdentifier:@"UITableViewCell"];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 2;
}


- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return @"Asset Types";
    }
    else return @"All items of selected Asset Type";
}


- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section
{
    if (section == 0) {
        return [[[BNRItemStore sharedStore] allAssetTypes] count];
    } else {
        NSArray *allItems = [[[BNRItemStore sharedStore] allItems] mutableCopy];
        self.itemsOfType = [[NSMutableArray alloc] init];
        
        if (!self.item.assetType) {
            return 0;
        }
        
        for (BNRItem *item in allItems) {
            
            if (item.assetType == self.item.assetType) {
                [self.itemsOfType addObject:item];
            }
        }
        return [self.itemsOfType count];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0) {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"
                                                                forIndexPath:indexPath];
        NSArray *allAssets = [[BNRItemStore sharedStore] allAssetTypes];
        NSManagedObject *assetType = allAssets[indexPath.row];
    
        // Use key-value coding to get the asset type's label
        NSString *assetLabel = [assetType valueForKey:@"label"];
        cell.textLabel.text = assetLabel;
    
        // Checkmark the one that is currently selected
        if (assetType == self.item.assetType) {
            cell.accessoryType = UITableViewCellAccessoryCheckmark;
            
        } else {
            cell.accessoryType = UITableViewCellAccessoryNone;
        }
    
        return cell;
    } else {
        
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"
                                                                forIndexPath:indexPath];
        //NSArray *allItems = [[BNRItemStore sharedStore] allItems];
        BNRItem *item = self.itemsOfType[indexPath.row];

        
        cell.textLabel.text = item.itemName;
        
        return cell;
     }
}

- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0) {
        UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        
        
    
        NSArray *allAssets = [[BNRItemStore sharedStore] allAssetTypes];
        NSManagedObject *assetType = allAssets[indexPath.row];
        self.item.assetType = assetType;
        
        
    
        [self.navigationController popViewControllerAnimated:YES];
    }
    
}

@end

I can’t say that any of these challenges have reinforced my knowledge of CoreData in any way. I guess this chapter is just an introduction to the subject so I won’t lose too much sleep over it.


#2

Core Data can get quite involved and complicated. There are books dedicated just to learn Core Data. Anything less than an entire book, consider it just an intro.

As for the solution you have given, you may have misinterpreted what’s being asked exactly. The Gold solution requires that you return only the items that belong to the currently selected/checked asset type, and not return all items (which may or may not belong to the currently selected asset type).

One solution would be what sunny4s has done, which is to sort through the entire list of items, and collect the items that have the same asset type as the currently selected asset type. If you have a long list of items, this may not be the best approach. Or, Access the currently selected NSManagedObject asset type through the current item, and access its set of items, and sort those items into an array, as show below.

[code]- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@“UITableViewCell” forIndexPath:indexPath];

NSUInteger section = [indexPath section];

NSArray *allAssets = [[BNRItemStore shareStore] allAssetTypes];
NSManagedObject *assetType = allAssets[indexPath.row];

if (section == 0) {
    // Use key-value coding to get the asset type's label
    NSString *assetLabel = [assetType valueForKey:@"label"];
    cell.textLabel.text = assetLabel;
    
    // Checkmark the one that is currently selected
    if (assetType == self.item.assetType) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    }
    else {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
}
else if (section == 1) {
    NSManagedObject *assetType = self.item.assetType;
    NSSet *items = [assetType valueForKey:@"items"];
    NSArray *sortedItems = [items sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"orderingValue" ascending:YES]]];
    BNRItem *anyItem = sortedItems[indexPath.row];
    
    cell.textLabel.text = anyItem.itemName;
}

return cell;

}
[/code]


#3

In my case, I utilized NSPredicate to get the items belonging to the selected type.


BNRAssetTypeViewController.m

-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
    if (section == 0) {
        return [[[BNRItemStore sharedStore] allAssetTypes] count];
    } else {
        NSArray *allItems = [[BNRItemStore sharedStore] allitems];
        NSPredicate *p = [NSPredicate predicateWithFormat:@"AssetType == %@", self.item.assetType];
        NSArray *typeItems = [allItems filteredArrayUsingPredicate:p];
        return [typeItems count];
    }
}

-(UITableViewCell *)tableView:(UITableView *)tableView
        cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"
                                                            forIndexPath:indexPath];
    
    if (indexPath.section == 0) {
    
        NSArray *allAssets = [[BNRItemStore sharedStore] allAssetTypes];
        ... ...
            cell.accessoryType = UITableViewCellAccessoryNone;
        }
    } else {
        NSArray *allItems = [[BNRItemStore sharedStore] allitems];
        NSPredicate *p = [NSPredicate predicateWithFormat:@"AssetType == %@", self.item.assetType];
        NSArray *typeItems = [allItems filteredArrayUsingPredicate:p];
        
        BNRItem *item = typeItems[indexPath.row];
        cell.textLabel.text = item.itemName;
    }
    
    return cell;
}

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    if (self.item.assetType) {
        return 2;
    } else {
        return 1;
    }
}

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return @"Asset Type";
    } else {
        return @"Assets in the selected type";
    }
}

-(NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0) {
        return indexPath;
    } else {
        return nil;
    }
}