Gold Challenge - Do What Joe Says!


#1

SO I had been working on the Gold Challenge for Chapter 16 and after been stalemated for a couple of days decided to look on the forum for a hint. While perusing on of the threads I came across a post by Joe Conway that in essence said do it with Core Data and that you just ask BNRAssets for its items. Well, great, I said to myself. Then I thought, what message? I poked around Apple documentation and got close, but no cigar. I then read the final part of Chapter 16 that discussed NSSet and faults. I then noticed that the message I was sending BNRAssets was returning a fault - in my line of work (radiation therapy faults are bad things you don’t wan to happen most of the time, although they can also be helpful). Anyway, I looked up NSSet and faults and found what I believe to be the answer in indeed one or two lines of code.

NSManagedObject *singleAssetType = [allAssetTypes objectAtIndex:0];
NSSet *itemSet = [singleAssetType valueForKey:@"items"];
NSArray *itemArray = [itemSet allObjects];

NSLog(@"Item at o is %@", [itemArray objectAtIndex:0]);

I haven’t finished the challenge yet, so the code above is just used to tell me if I’m getting the right results. Indeed, I received the following NSLog output:

assetType = “0x81a7aa0 x-coredata://38B48AE6-9E81-4D24-B030-6F427246C76E/AssetType/p1”;
dateCreated = “2013-06-25 13:05:42 +0000”;
imageKey = nil;
itemName = bag;
orderingValue = 1;
serialNumber = ggg;
thumbnail = nil;
thumbnailData = nil;
valueInDollars = 100;

So Joe the lesson is listen to Joe and read the whole chapter 2, 3 or more times. It may just lead you to the correct answer. Thanks, Joe.


#2

Thanks! This got me the final bit of the way there.

As Joe hinted at in another thread, we want to query BNRAssetType for the current item’s assetType. Since there should only be one assetType returned (ie, “Electronics”, which we’ll assume for now there’s only one of), we then grab index 0 from the returned query. Calling valueForKey: on that will give us a NSSet of the rows that fall within the search criteria we want. Calling allObjects on the NSSet will give us a NSArray from which we can do all our normal logic.

AssetTypePicker.m

- (NSArray *)getAllItemsInAssetType
{
	// For the active item, determine the assetType then query the database
	NSString *assetType = [[item assetType] valueForKey:@"label"];
	NSArray *items = [[BNRItemStore sharedStore] allItemsInSection:assetType];

	// For the queried assetType, get an NSSet of BNRItems
	// index 0: since each assetType should be unique, there should only be one result returned.
	NSSet *itemSet = [[items objectAtIndex:0] valueForKey:@"items"];
	return [itemSet allObjects];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
	if (section == 1) {
		return [[self getAllItemsInAssetType] count];
	}
	// ...
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)ip
{
	if ([ip section] == 1) {
		// ...
		NSArray *items = [self getAllItemsInAssetType];
		NSString *assetLabel = [[items objectAtIndex:[ip row]] itemName];
		[[cell textLabel] setText:assetLabel];
		// ...
	}
}

BNRItemStore.m

- (NSArray *)allItemsInSection:(NSString *)section
{
	NSFetchRequest *request = [[NSFetchRequest alloc] init];
	NSEntityDescription *e = [[model entitiesByName] objectForKey:@"BNRAssetType"];
	[request setEntity:e];
	
	NSPredicate *p = [NSPredicate predicateWithFormat:@"(label LIKE %@)", section];
	[request setPredicate:p];
	
	NSError *error;
	NSArray *result = [context executeFetchRequest:request error:&error];
	if (!result) {
		[NSException raise:@"Fetch failed" format:@"Reason: %@", [error localizedDescription]];
	}
	
	return [[NSMutableArray alloc] initWithArray:result];
}