New shopping list


Published on

New Shopping List (an example in code)

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

New shopping list

  1. 1. New Shopping List Tennessee Valley Apple Developers Saturday CodeJam December 4, 2010
  2. 2. 1. Create a new project: A. Mac OS X Application > Cocoa Application: Document based B. Name: Shopping List II. Expand the “Classes” and “Interface Builder Files” folders A. Note the new .xib file called “MyDocument”, and the corresponding reference in [MyDocument windowNibName] to “MyDocument”
  3. 3. Also, make note of the control structure in [MyDocument init]. The NSDocument is a “controller” class, which means it serves as the intermediary between the user interface (the view) and the underlying data (the model) Now, let’s build our user interface in Interface Builder.
  4. 4. Pull up the Library, and add a Table View to the Document Window. Expand it to fill the window from side to side (using the Apple layout indicators as guides), and from top to bottom, leaving enough space to add a Label object, a Text Field object and a Push Button object at the bottom of the window view. Remove one column from the table view, leaving a single column. Change the remaining column header to say “Shopping List Items” Change the Label to “Add item to list:” Change button to “Add” Save the user interface file in Interface Builder
  5. 5. Switch back to Xcode, and add two outlets to the MyDocument class (header file): • shoppingListTbleView (NSTableView) • newItemNameTextField (NSTextField) Add one action: • addNewItemToShoppingList:(id)sender; Save MyDocument.h and switch back to Interface Builder
  6. 6. Wire up the following: Text Field -> newItemNameTextField Table View -> shoppingListTableView Push Button -> addNewItemToShoppingList Save file in Interface Builder and switch back to Xcode.
  7. 7. Add the new action to the MyDocument.m file (we’ll fill in the code instructions later). Save, and go ahead and build to make sure you have no syntax errors. Now, we’re going to add our data store to keep track of our shopping list items. For now, we’re only storing the name of each item we need, so what would be a good data type to use?
  8. 8. Open MyDocument.h and add a pointer to a mutable array called shoppingListArray. Switch to the implementation file and add code to initialize the array to the init method (inside the if code block): shoppingListArray = [[NSMutableArray alloc] initWithObjects:@”Milk”, @”Eggs”, @”Butter”, nil]; Don’t forget, since we used “alloc” to initialize this object, to release it in the dealloc method. Build and run to check for syntax errors.
  9. 9. Now, to get our shopping list to show up in our table view, we need to let the table view know where our data is stored. Switch to IB, find the Table View and right click on it to pull up the object list; link the dataSource to the File’s Owner object. Now, since we’re using a Table View to display our data source, we need to know what messages we can respond to. To find this out, we need to look at the documentation for the…. NSTableViewDataSource Protocol to find the methods that an NSTableView object uses to provide access to its data source.
  10. 10. tableView:objectValueForTableColumn:row: This method sets the data object for an item in a given row in a given column. We only have one column in our table, but we will need to programmatically determine which row to put our data items into. Once our view is initialized, we’ll also need to be able to determine how many rows are in our table so we can select the next one to add our next shopping list item. numberOfRowsInTableView: returns the number of rows in the table view data source object. What do you think needs to be returned here? We need to implement both of these methods in our controller.
  11. 11. - (NSInteger)numberOfRowsInTableView: (NSTableView *)aTableView { return [shoppingListArray count]; }
  12. 12. (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { //We can ignore the first parameter since we only have one table, and we can ignore the second since we only have one column. rowIndex specifies the index of the row for which we need to return an object. This corresponds with each position in our shoppingListArray. We can return an object at a particular position in our array with the objectAtIndex: method. return [shoppingListArray objectAtIndex:rowIndex]; } Save, build and run. You should see your shopping list table populated with our shoppingListArray objects.
  13. 13. Now we need to add functionality to add items to our shopping list. When we click on the “add” button we’ll: • get the string value from the text field supplied by the user • clear the text field so it’s ready for another entry from the user • reload the table view so the new item shows up
  14. 14. Now we’re going to add code to our action method, addNewItemToShoppingList:. 1. Create a string variable to store the text field contents: NSString *newItem = [newItemNameTextField stringValue]; 2. Store the item in the shoppingListArray: [shoppingListArray addObject:newItem]; 3. Clear the text field: [newItemNameTextField setStringValue:@””]; 4. Reload the table view: [shoppingListTableView reloadData]; Save, build and run.
  15. 15. Now that we have our basic shopping list working, let’s add some functionality -- the ability to edit the shopping list. Editing capability is already inherent in the table view design (as you can see by clicking on any of the items), but changes are not saved to the table. Let’s look at the NSTableViewDataSource protocol documentation again, specifically at the methods for the data source.
  16. 16. tableView:setObjectValue:forTableColumn:row: lets us set the value of the data in a particular column and row. Again, since we are working with only one table and column, we can ignore the first two parameters, and focus on the parameter “rowIndex”. Go ahead and copy the signature of this method and put it in the MyDocument.m file in Xcode. Now, let’s look at the NSMutableArray Class documentation for a method that lets us replace an object in our array.
  17. 17. replaceObjectAtIndex:withObject: will do the trick -- it will replace an object at a certain index position in the array with the supplied object. When we edit our table using the built-in capabilities, we want to take the newly edited object from the table and place it in our array. Add code to MyDocument.m to do this: [shoppingListArray replaceObjectAtIndex:rowIndex withObject:anObject]; Save, build and run. Test and see what happens!
  18. 18. Next CodeJam • We’ll modify our shopping list to add a persistent data store (save our shopping list so it can be retrieved later) • Add the ability to remove items from our shopping list, complete with an alert box to give users the opportunity to change their mind. • Add items to the shopping list by hitting the “return” key as well as clicking the “add” button. • Disallow adding duplicate items to our shopping list • Change our shopping list to add a “quantities” column to our table • Change our data store from NSMutableArray to NSMutableDictionary • Add a ShoppingListItem class to encapsulate our shopping list item-specific code (model object), complete with properties and synthesized accessor methods. • Add a checkbox so we can check purchased items off our list
  19. 19. Saving our shopping list Right now, we can build a shopping list, edit the items, but when we end our application, our shopping list vanishes. Let’s add the ability to save our shopping list. Our shopping list is stored in an instance variable called shoppingListArray, which is a Mutable Array. Look at the documentation for NSMutableArray (and its parent NSArray) to see if there is an existing method that lets you save the array contents in some sort of permanent storage mechanism. Also take a look at the documentation for NSDocument, which is the class type your user interface, MyDocument.
  20. 20. • NSArray has two methods that can be used to write array data to persistent storage: • writeToFile:atomically: • writeToURL:atomically: • NSDocument also has a method that can be used: • writeToURL:ofType:error:
  21. 21. • Remember, in one of our earlier sessions we covered the fact that Apple was adopting URL protocols for file interaction, so we’ll use the URL methods to save and retrieve our data. • Copy the method signature for writeToURL:ofType:error and implement it in MyDocument as follows: - (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError { return [shoppingListArray writeToURL:absoluteURL atomically:YES]; } • Save and build. Use “File > Save” to use the built-in save methodology of OS X.
  22. 22. Retrieving a saved shopping List • Now that we can save it, we need to be able to retrieve it. • NSDocument has a corresponding method called readFromURL:ofType:error that can be used to open a previously saved document window. • We need to read the shopping list array that was previously saved into our shoppingListArray object; however, if a shoppingListArray already exists, we need to release it first so that we don’t have a memory leak before we create a new one with our data file. • If we look at the documentation for NSArray, we see that we can initialize an array object from a URL (in this case a file) using the method initWithContentsOfURL:absoluteURL.
  23. 23. Copy the signature of NSDocument::readFromURL:ofType:error and implement it in MyDocument as follows: - (BOOL) readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError { [shoppingListArray release]; shoppingListArray = [[NSMutableArray alloc] initWithContentsOfURL: absoluteURL]; [shoppingListTableView reloadData]; return YES; } Build and run. Note that we can retrieve the previously saved shopping list back into a document window where we can continue to work with it. A note of caution: we have not implemented any code to check the data in the file for validity, nor did we implement any code to check and make sure that our shopping list was saved successfully (we assumed that both of these things happened). In real life, we would implement error checking and file checking methodologies to ensure just that.
  24. 24. Adding a remove button • We’ve implemented the ability to create a shopping list, add items to it, edit those items, save the list to persistent storage and retrieve it. What about deleting items? • We’re going to add a remove button in Interface Builder along with the necessary code to implement the remove functionality
  25. 25. Open MyDocument.xib in Interface Builder. In the Library, find the NSButton object called “Square Button” and drag it onto the bottom left-hand side of your Window; reduce it in size by about half. Open the Attribute Inspector and find the Image Attribute; change this from blank to NSRemoveTemplate. This will change the appearance of the button, and add some functionality. Save MyDocument.xib in IB and switch back to XCode. Add a new IBAction method signature to MyDocument.h called “removeItemFromShoppingList:” - (IBAction) removeItemFromShoppingList:(id)sender; Copy and paste this signature into the implementation file and create an empty method.
  26. 26. Displaying an Alert • Cocoa has several ways to display alerts and dialog boxes to the user – one is an object called NSAlert. • To use it, we create an alert instance, add some informative text to communicate with the user, and add some buttons to the object to let the user communicate with the application. We then set the alert style and run the alert.
  27. 27. Add the following to removeItemFromShoppingList: NSAlert *alert = [[NSAlert alloc] init]; [alert addButtonWithTitle:@"Delete"]; [alert addButtonWithTitle:@"Cancel"]; [alert setMessageText:@"Delete the shopping list item?"]; [alert setInformativeText:@"Deleted items cannot be restored!"]; [alert setAlertStyle:NSWarningAlertStyle]; [alert runModal]; [alert release]; Save MyDocument.h and MyDocument.m and toggle back to IB to wire up your RemoveButton to the method removeItemFromShoppingList: Save in IB, toggle to XCode and Build and Run.
  28. 28. We have a working alert box, but our button doesn’t remove our shopping list item yet. First let’s add code to check and see if our user has selected a shopping list item. If our selected item has an index number of --1, no row is selected. In this case we want to just return from our remove method without doing anything. Add the following to the beginning of the “remove” method: int selectedItemIndex = [shoppingListTableView selectedRow]; if(selectedItemIndex == -1) return;
  29. 29. To find which alert button was pressed by the user, we need to check the value returned by the runModal method. Apple has defined some integer constants (NSAlertFirstButtonReturn and NSAlertSecondButtonReturn) to help with this. Add the following code to the “remove” method, right before the “alert release” statement: int returnValue = [alert runModal]; // remove [alert runModal] if(returnValue == NSAlertFirstButtonReturn) { [shoppingListArray removeObjectAtIndex:selectedItemIndex]; [shoppingListTableView reloadData]; } Build and run.
  30. 30. Adding one more bit of functionality to the user interface • Our application would be alot more user friendly if an item was added to the shopping list when the return or enter key was pressed in addition to clicking on the “add” button. • Open MyDocument.xib in IB, and set the action for the New Item text field to be the addNewItemToShoppingList: method. • Then, use the Identity inspector for the test field to set its action to “Sent on Enter Only” • Save in IB, toggle to XCode and build and run.
  31. 31. Dealing with Duplicate Items • Now let’s change our shopping list to make sure we can’t add duplicate items. We’ll be using an iterative loop to check for an item’s existence before it gets added to the shopping list. • Open MyDocument.m and find the method addNewItemToShoppingList:
  32. 32. Add the following to the beginning of the method: NSString *itemToAdd = [newItemNameTextField stringValue]; for (NSString *eachItem in shoppinglistArray) { if([eachItem isEqualToString:itemToAdd]) return; } //Remove the following lines //NSString *newItem = [newItemNameTextField stringValue]; //[shoppingListArray addObject:newItem]; [shoppingListArray addObject:itemToAdd]; Build and run.
  33. 33. Next CodeJam • Change our shopping list to add a “quantities” column to our table • Change our data store from NSMutableArray to NSMutableDictionary • Add a ShoppingListItem class to encapsulate our shopping list item-specific code (model object), complete with properties and synthesized accessor methods. • Add a checkbox so we can check purchased items off our list • Say Goodbye to OS X and Start iOS Programming!!!!!!!