Learning Core Data for iOS (2014)

B. Preparing Grocery Cloud for Chapter 16

The StackMob integration to be discussed in Chapter 16, “Web Service Integration,” will be implemented into a new project called Grocery Cloud. This appendix shows how to prepare the Grocery Cloud starting project using Grocery Dude from the end of Chapter 12, “Search.” Nothing in this appendix is related to Core Data, which is why it has been placed in an appendix. It is not essential that you follow this appendix, seeing as the Grocery Cloud starting project is downloadable from the link given in Chapter 16. The following instructions assume you’re using Xcode 5 or above.

Renaming Grocery Dude

The first step is to rename Grocery Dude to Grocery Cloud, so there’s no confusion between the two projects.

Rename Grocery Dude to Grocery Cloud as follows:

1. Download and unzip Grocery Dude from the end of Chapter 12 using the following URL: http://www.timroadley.com/LearningCoreData/GroceryDude-AfterChapter12.zip.

2. Rename the directory containing the project from Grocery Dude to Grocery Cloud. Don’t rename the Grocery Dude directory within the newly renamed Grocery Cloud directory just yet.

3. Double-click the Grocery Dude.xcodeproj file in the Grocery Cloud directory, which should open the project in Xcode 5 or above.

4. Click Product > Clean to ensure there’s no residual cache from other projects.

5. Ensure the Project Navigator is visible (image+1) and then slowly click the project name twice and rename it to Grocery Cloud, as shown in the top left of Figure B.1. As soon as you’ve renamed the project, a window will appear as shown on the right of Figure B.1.

Image

Figure B.1 Renaming Grocery Dude to Grocery Cloud

6. Click Rename. If you are prompted with an alert informing you that Main.storyboard has changed, click Revert.

7. Rename the Grocery Cloud > Targets > Grocery Cloud > Info > Bundle display name from ${PRODUCT_NAME} to GroceryCloud.

Repointing File Paths

The next step is to change the path where the Info.plist and Precompiled Prefix Header files are expected to reside once the renaming exercise is complete.

Update Grocery Cloud as follows to repoint file paths:

1. Select the Build Settings tab of the Grocery Cloud target and ensure Basic is selected, as shown in Figure B.2.

Image

Figure B.2 Changing expected file paths

2. Change the directory that Grocery Cloud-Info.plist and Grocery Cloud-Prefix.pch are located in from Grocery Dude to Grocery Cloud, as shown in Figure B.2.

Renaming Groups and Tests

Xcode groups are used to organize the project class files. The next step is to rename these groups so they match the new project name.

Update Grocery Cloud as follows to rename the Xcode groups:

1. Rename each of the groups in the project so they all begin with Grocery Cloud. Then rename Grocery_DudeTests.m to Grocery_CloudTests.m, as shown in Figure B.3.

Image

Figure B.3 Renaming Grocery Dude groups and tests to Grocery Cloud

2. Right-click the top Grocery Cloud group shown in Figure B.3 and select Show in Finder.

3. Rename the Grocery Dude directory shown in Finder to Grocery Cloud. Some files in Xcode will now display red because their parent path is invalid.

4. Rename the Grocery DudeTests directory shown in Finder to Grocery CloudTests. Some more files in Xcode will now display red because their parent path is invalid.

5. Return to Xcode and select the Grocery Cloud group shown near the top of Figure B.3. Open the Identity and Type section of File Inspector (Option+image+1) and then click the icon shown in Figure B.4.

Image

Figure B.4 Repointing the Grocery Cloud group

6. Choose the Grocery Cloud directory that sits alongside Grocery Cloud.xcodeproj to represent the Grocery Cloud Xcode group. The files that were previously red beneath the Grocery Cloud group should return to black.

7. Repeat steps 5 and 6; however, this time repoint the Grocery CloudTests group to the renamed Grocery CloudTests directory.

Renaming the Scheme

The project scheme is currently called Grocery Dude. This should be renamed to Grocery Cloud to maintain consistency throughout the project.

Update Grocery Cloud as follows:

1. Click Product > Scheme > Manage Schemes....

2. Slowly double-click the scheme name and rename it to Grocery Cloud, as shown in Figure B.5, and then click OK.

Image

Figure B.5 Renaming the scheme to Grocery Cloud

Updating the Artwork

Grocery Cloud will have a different icon and default splash screen than Grocery Dude to help distinguish between the two projects.

Update Grocery Cloud as follows to replace the existing artwork:

1. Download the updated artwork from the following URL: http://www.timroadley.com/LearningCoreData/Icons_GroceryCloud.zip.

2. Select the Images.xcassets asset catalog.

3. Select AppIcon.

4. Drag AppIcon_29pt.png into the 29pt placeholder to replace the existing icon.

5. Drag AppIcon_40pt.png into the 40pt placeholder to replace the existing icon.

6. Drag AppIcon_60pt.png into the 60pt placeholder to replace the existing icon.

7. Select LaunchImage.

8. Drag LaunchImage_2x.png into the 2x placeholder to replace the existing image.

9. Drag LaunchImage_R4.png into the R4 placeholder to replace the existing image.

Disabling Camera and Image Support

To keep Chapter 16 concise and Grocery Cloud free on the App Store, image support will be removed from Grocery Cloud. To this end, the thumbnail generation triggered in the viewDidAppear methods of PrepareTVC.m and ShopTVC.m needs to be commented out. The code won’t be removed, so you may experiment with adding image support yourself later.

Update Grocery Cloud as follows to disable image support:

1. Comment out the viewDidAppear method in PrepareTVC.m and ShopTVC.m.

2. Add the following code to the bottom of the viewDidLoad method of ItemVC.m:

self.cameraButton.hidden = YES;
self.photoImageView.hidden = YES;

Workaround: Section Name Key Path Issue

StackMob provides a framework that will be used in Chapter 16 to integrate Core Data with their backend web service. A known limitation of the StackMob framework is that you cannot set a relationship as the key path used to divide a UITableView into sections. Unfortunately, this functionality is fundamental to Grocery Cloud. To work around this issue, two new string attributes will be added to the Item entity. These attributes will be populated with item locations from their equivalent relationship, and will be used instead to section the table view. Note that until the workaround code has a chance to run, you may see the error “Object will be placed in unnamed section” in the console log.

Update Grocery Cloud as follows to work around the section name key path issue:

1. Select Model.xcdatamodeld.

2. Click Editor > Add Model Version....

3. Click Finish to accept Model 9 as the new model name.

4. Ensure Model 9.xcdatamodel is selected.

5. Create a new String attribute in the Item entity called storedIn.

6. Create a new String attribute in the Item entity called aisle.

7. Regenerate and overwrite the existing NSManagedObject subclass files for all entities by selecting all Model 9 entities and then clicking Editor > Create NSManagedObject Subclass... and then follow the prompts. Ensure the Grocery Cloud target is selected before clicking Create.

8. Ensure Model.xcdatamodeld is selected.

9. Set the Current Model Version to Model 9 using File Inspector (Option+image+1).

The code to copy an item’s related location names to the equivalent attribute from the Item entity is shown in Listing B.1.

Listing B.1 PrepareTVC.m: cellForRowAtIndexPath


// StackMob Relationship sectionNameKeyPath Workaround
[self.frc.managedObjectContext performBlock:^{
    if (!item.storedIn ||
        ![item.storedIn isEqualToString:item.locationAtHome.storedIn]) {
        item.storedIn = item.locationAtHome.storedIn;
        NSLog(@"sectionNameKeyPath WORKAROUND (See Appendix B):");
        NSLog(@"item.storedIn is now = '%@'", item.storedIn);
    }
    if (!item.aisle ||
        ![item.aisle isEqualToString:item.locationAtShop.aisle]) {
        item.aisle = item.locationAtShop.aisle;
        NSLog(@"sectionNameKeyPath WORKAROUND (See Appendix B):");
        NSLog(@"item.aisle is now = '%@'", item.aisle);
    }
}];


Update Grocery Cloud as follows to work around the section name key path issue:

1. Add #import "LocationAtHome.h" to the top of PrepareTVC.m.

2. Add #import "LocationAtShop.h" to the top of PrepareTVC.m.

3. Copy the code from Listing B.1 to the bottom of the cellForRowAtIndexPath method of PrepareTVC.m before return cell;.

4. Repeat steps 1, 2, and 3 for ShopTVC.m instead of PrepareTVC.m.

Now that the reliance on locationAtHome.storedIn and locationAtShop.aisle has been removed, the sectionNameKeyPath reference in the configureFetch methods needs to be updated.

Update Grocery Cloud as follows to ensure sectionNameKeyPath does not rely on a relationship:

1. In the configureFetch method of PrepareTVC.m, replace the two occurrences of locationAtHome.storedIn with storedIn.

2. In the configureFetch method of ShopTVC.m, replace the two occurrences of locationAtShop.aisle with aisle.

Summary

The starting project for Chapter 16 has now been created. Note that the persistent store local to the device won’t be used anymore. If you already have a copy of Grocery Cloud on your device, perhaps from the App Store, it is recommended that it be removed before beginning Chapter 16. If you did run the application now, you would see a lot of console log entries as the sectionNameKeyPath workaround is applied.

As one final touch before beginning Chapter 16, search the Xcode project for the word “Dude” and replace it with the word “Cloud.”