Learning Cocoa with Objective-C by Apple Computer, Inc., James Davidson The unconfirmed error reports are from readers. They have not yet been approved or disproved by the author or editor and represent solely the opinion of the reader. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification This page was updated April 18, 2008. UNCONFIRMED errors and comments from readers: (xxi) 6th paragraph; "Prodigy" should be "The Prodigy." ;) (28) bottom code example; there is no hash with the import statement. the argv argument in the main function has no [] brackets. (32) ("trap" note) If you havespaces in the folder in --- If you have "white space" (spaces or tabs) in the name of the folder in (37) 1st paragraph; Using the project name 'Hello World' will not build on the December 2002 Project Builder. Instead, take out the space (to become 'HelloWorld') so that the project may properly build. (43) third line of first paragraph; "that goes with the territory" should be "that go with the territory" (45) (mid-page) On the back of every iPod is the phrase "Designed ... --- On the back of every iPod is the text "Designed ... It's not a phrase; it's two sentences! {49} (near end of box) ... enter man printf ... This will bring up the section 1 command; was this intentional? (52) ("trap" note) ... as in Figure 3-6. --- ... as in Figure 3-7. [53] Figure 3-8: Nested Objective-C messages; The figure shows two nested messages, to explain how nesting works (from the innermost to the outermost message). The inner message [NSObject alloc] is represented as a gray rectangle. But the size of the rectangle covers also the method name of the outer message [[NSObject alloc] init]; The gray rectangle should only cover the area oft square brakets of the inner message. (57) (2nd paragraph) ... between the brackets. --- ... between the braces. ... between the end bracket and ... --- ... between the closing brace and ... ?59? (mid-page) The ObjC memory management system is one of ObjC's uglier aspects (along with upsyDownsyCaps :-/). Anyway, I'd like to see a note here, explaining (and, if possible, justifying) why ObjC doesn't have garbage collection. [62] 8th paragraph starting with "Since this defeats the purpose....."; The last sentence of the paragraph should read, "If you experiment with this, be sure to set it back to return" [self name]. If you use the [self description] shown it will crash the program. (63) bottom of page; - init { if (self = [super init]) { /* class specific initialization goes here */ } return self; } should be: (id returned and == instead of =) - (id) init { if (self == [super init]) { /* class specific initialization goes here */ } return self; } (63) bottom 1/3; return self; } should be: (id returned) - (id) init { [super init]; /* class-specific initialization goes here */ return self; } ?67? (start of "Object Deallocation") ... in the form of a memory leak. This term (and concept) deserves an explanatory note. (69) (mid-page) ... leak, making it a good citizen. --- ... leak, making our app a good citizen. We're eliminating the leak, not making it a good citizen. (71) (first and last paragraphs) ... for the raison d'e^tre of ... -------------- I think this should be in italics. ... set, but can be ... --- ... set, but it can be ... (73) (near top) ... value "Underworld" --- ... value "Underworld". ...the NSLog function --- ...the NSLog function. ... and then Project Builder will compile and the run the code. --- ... and then Project Builder will compile and run the code. ?77? (near bottom) Note e explains why the code uses "range.location + range.length", but fails to explain why "range.location + 1" wouldn't work as well (and be a lot shorter :-). (77) Middle of page under item 2.; NSString * title = [song substringToIndex:range.location]; should be: NSString * title = [song substringToIndex: range.location]; notice the space between ": range.location" The same applies to: [song substringFromIndex:range.location + range.length]; which should be: [song substringFromIndex: range.location + range.length]; Note that the downloaded source also contains this error and will not compile! (79) entry "i"; Should be "for" instead of "forr". {80} stringWithContentsOfFile paragraph; stringWithContentsOfFile is a static method and should use "+" instead of "-". (80) (desc. of writeToFile:atomically:) ... file, then copied into ... --- ... file, then moved (actually, renamed) into ... (83) Someone needs to decide whether Bulleted items such as "Enumerate over their contents" need a closing period. Like C-based arrays, the first object in an array is located at index 0. Like C- and Java-based arrays, Cocoa indexes start at 0. In both of these sentences, the clauses mismatch. Rewrite time... To practice working with arrays do as follows: --- To practice working with arrays, do as follows: ... named "arrays", and save it ... --- ... named "arrays" and save it ... (85) Inserts the given objectto the end ... --- Inserts the given object at the end ... Inserts the given object to the receiving array ... --- Inserts the given object in the receiving array ... Removes the object from ... array located at ... --- Removes the object from ... array at the location specified by ... (85) second line; The following line of code: (gdb) print (int) [array containsObject:@"buckle"]; produces nothing. The semi-coloin should be omitted. (87) Already, the applications ... iChat, utilize ... --- Some applications ... iChat, already utilize ... The settings shown will be fine, and all you need to do ... --- The settings shown will be fine; all you need to do ... (89) (mid-page) Sets--...--are an unordered collection of ... Sets--...--are unordered collections of ... A set can be used instead ... This is a run-on sentence (rewrite time :-). (90) 2nd line; The last words of the sentence should be "...contents of an NSDictionary object", and not "contents of an array" (90) More quasi-sentence bullets without ending periods. a. Creates a new array based on a space-delimited string. --- a. Creates a new array based on a space-delimited string. (91) The strengths of the dictionary classes ... This is a run-on sentence (rewrite time :-). (92) More quasi-sentence bullets without ending periods. 2. Open the main.m file, and modify it to match Example 4-6. --- 2. Open the main.m file and modify it to match Example 4-6. Actually, the comma after "collectionfiles" (in the previous sentence) is also questionable. (92) 2/3 of the way down; "To practice working with collections and files do as follos:" (note typo on last word) (93) The code we added inExample ... --- The code we added in Example ... ... in the working directory of application. --- ... in the working directory of the application. Creates a new string based on the ... --- Creates a new string, based on the ... (94)(in box) ... several types directly represented ... --- ... several types that are directly represented ... (98) If you want to keep it beyond the ... --- If you want to keep an object beyond the ... {98} section "Exercises" item 1.; The correct methods are named lowercaseString and uppercaseString (102) Many user-interface objects other than ... This sentence is awkward (rewrite time :-). (104) In "Designing Applications Using MVC", it might be nice to give specific credit to the idea's creators (I think this was the SmallTalk group at Xerox PARC). {106} First Paragraph of "Create the Currency Converter Project"; You should not suggest creating projects that uses spaces in their name. In this case, the latest version of Project Builder was confused because it could not find a "Currency/" directory (first build error) then because it could not find a "Converter_Prefix.h" file (second build error). The directory automatically created when creating the project was "Currency Converter/" and the file automatically created was "Currency Converter_Prefix.h". I restarted the project by calling it "Converter" instead and all worked well. (106) First Paragraph; To further clarify the reported error regarding "Currency Converter_Prefix.h" - when you are using the December 2002 developer tools, you will run into a bug because this version includes support fo Precompiled Headers, but does not handle header files with spaces in them. If you do not want to restart the project all the way over, naming it without spaces, you can do this: 1. Go to Target View in the left side bar 2. Click "Currency Converter" under Targets 3. Go into Setting/Simple View (lower right pane) 4. Select GCC Compiler Settings 5. In the "Prefix Header" box, put quotes around "Currency Converter_Prefix.h" Now you should be able to build successfully. (109) Verify that the Visible at launch time option ... ---------------------- There really needs to be a special font to distinguish Apple text (menu item names, etc.). {114} -5; "With the option key still down..." duplicates the button, you have to nudge then check again by holding the option-key. (115) In the Instances pane of nib file window, ... --- In the Instances pane of the nib file window, ... (116) last paragraph (of inset); Regarding the Alignment Panel tool, it seems they've moved it from Tools -> Alignment to Layout -> Alignment -> Alignment Panel. It is also available as Shift-Command-A. I'm using the December 2002 version of the developer tools. (120) last sentence (step 2); Select the action that corresponds to the first field, rateField. ...should be... Select the outlet that corresponds to the first field, rateField. (121), it describes how to connect the Convert button to the Controller object. With the December 2002 Developer Tools, you must make sure to select the Outlets submenu of the Connections Info window to see the 'target' connection. (122) (end of page) This type is the same as void and ... ---- Why is this word in a special font? (126) ... the window server also detects users ... --- ... the window server also detects users' ... (or maybe) ... the window server also detects user ... (147) -2; should be (166) -3; "modified keys" should be "modifier keys" (167) 1st line; Another instance of "modified" that should be "modifier". Chapter 8: When creating the "Dot View" application in chapter 8, it should be noted that the slider needs to be told to continually send messages. This can be done as followings: 1. Select the slider widget 2. Open the Inspect (CMD + Shift + i) 3. Under "Attributes", select "Continuously Select Action While Sliding". {172} 172 after step 4; Need to generate the files after step 4 {183} Table 8-1; Technically, the parameters should probably match those given in the signature. The signature states the buttonlables to be xxxButtonLabel {default,alternate,other} whereas the table calls the parameters xxxButton and omits the "Label" part. (183) line -3: After this line, "c. Select Classes..." insert the following line: d. Click the "Choose" button. (185) 2nd to last line; Should be "finishes" or "is finished" instead of "finished" in "When the sheet finished, the callback method..." (194) line -7: "see the "Object-oriented Programming and the Objective-C Language" book...in the /Developer/Documentation/Cocoa/ObjectiveC folder." As of the December 2002 Developer distribution, the PDF document in that folder is called "The Objective-C Programming Language", dated May 2002. (198) line 15; I got an error when I tried to build as written: FoodItem * candyBar = [[FoodItem alloc] init]; which was fixed when I made the "I" lower case: Fooditem * candyBar = [[Fooditem alloc] init]; (203) Create the Data Source par. numbered 1; September 2002 second version. Instruction say to locate FoodItem.h and FoodItem.m in the "~/LearningCocoa/Key View Coding directory" that was created in the beginning of the chapter. The program was called "keyvaluecoding" following the lower case convention outlined in the beginning of the book for programs without GUI's. (Note "value" not "View"). Also, the picture in Fig. 9-8 of the Finder Window shows a path to the required files that is different from the LearningCocoa file. (206) tableView:objectValueForTableColumn:row: method; To save changes back to the data source, you should nowadays use setValue:forKey: instead of takeValue:forKey: so the last line of the given method should be changed accordingly. {206} Adding Entries to the Model; Following the instructions on page 206 through 209, you should be able to add new food items to the table. The button you create does do the job, but the problem is this: when you are editing an existing cell in the table of food items, the selected cell value will be saved not in the currently edited row, but in the newly created row. The newButtonPressed: method fires before the tableView:setObjectValue:forTableColumn:row does, making the latter save its value in the wrong row. {207} Step 6; I believe the instructions should say: 6. Select the _button_ view, and set its Autosizing attributes as show in Figure 9- 10. Currently, it says "table view." If you follow these steps to the letter, you end up with a pretty weird-looking app. (208) 10. the newButtonPressed: method; The last line (with comment d) should be changed to [table selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; because selectRow:byExtendingSelection: is deprecated since Mac OS X 10.3 [208] Source code for MyDataSource.m; - (IBAction)newButtonPressed:(NSEvent *) event{ should be: - (IBAction)newButtonPressed:(id) sender{ in line with the method definition given in MyDataSource.h on p.207 (Action messages should always send a reference to the sender as its parameter.) (224) 4th of the 4 method descriptions; The "ofType:" portion of the method name is missing in "- (BOOL)loadDataRepresentation:(NSData *)data:(NSString *)aType;" It should be "- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType;" [228] 2nd paragraph of "Examine the Document Interface"; It says: "the Attributes pane that File's Owner is set to correspond to an instance of MyDocument." I think it should be: "the Custom Class pane that File's Owner is an instance of MyDocument." (233) "Modify the Info Property List" step 4; The end of the second sentence should probably be changed from: [...]and with TXT in the OS types field. [...] to: [...]and with TEXT in the OS types field. [...] The "OS types" are always four characters since they map the document type to the pre-OS X "File Type" codes. As printed, the resulting application will not allow text documents to be opened unless they have a .txt extension. {240} item 4b: Ambiguous: Change "from the Views palette" to "from the Cocoa Data Views palette". {240} item 6: nothing visible happens when I do this. Do you really mean I should drag RTF Edit > Classes > MyDocument.h from the Project Builder window into the Interface Builder's MyDocument.nib Instances pane? {240} item 10: Once more, there is no Change button to click. What to do instead? [240] Step 10.; (rtf for Extension and RTF for OS types) should read: (rtf for Extension and RTFD for OS types). {241} line -4 (loadFileWrapperRepresentation:ofType:): line should end "length])" not "length])];". {242} line 11 (fileWrapperRepresentationOfType): line should end "length]);" not "length];". {242} line 22 (windowControllerDidLoadNib): line should end "length])" not "length]);". {242} item 17: There are a number of errors in Chapter 11, (to page 242) including one which I can't track down which prevents RTF Edit from running: Compiler error: Building target “RTF Edit” with build style “Development” (optimization:level ‘0’, debug-symbols:on) — (2 errors) Missing file or directory: RTF Missing file or directory: Edit_Prefix.h {244} item 4b: There is no Extras popup. Select Font > Show Colors. (249) bottom after 1.; Edit the removeFormatting: method should be edit the clearFormatting: method. (251) line -11: "want it place" should be "want it to place". (251) item 2 and page 252 Figure 11-11: there is no "Add" button to click (Project Builder version 2.1) (253) item 1: The listing given is out of date. The listing in Davidson's LearningCocoa/Chapter ll/ pg 255 RTF Edit/MyDocument.h is: #import @interface MyDocument : NSDocument { IBOutlet NSTextView * textView; NSAttributedString * rtfData; } - (IBAction)analyzeText:(id)sender; - (IBAction)clearFormatting:(id)sender; - (IBAction)speakText:(id)sender; @end {252} 1st line of code; The line: - (BOOL)loadFileWrapperRepresentation:(NSFileWrapper *) of Type:(NSString *)type Should probably read: - (BOOL)loadFileWrapperRepresentation:(NSFileWrapper *)wrapper of Type:(NSString *)type ...assigning a variable name to the NSFileWrapper argument. (255) First exercise; It says you have to remove two lines of code from 'awakeFromNib' but the method to edit is actually called 'windowControllerDidLoadNib:aController' {303} Figure 16-8 (top of page); This is probably a correction that needs to be made due to a change in the latest Interface Builder. I have the Dec. 2002 Dev Tools installed. Figure 16-8 shows the list of classes used to set the File's Owner as being under the "Attributes" pane of the "File's Owner Info" window but on my copy of Interface Builder it is under the "Custom Class" pane (Command-5). {327} Point 6 of Chapter 4 Solutions; It is not only the dictionary example that does not release its object. Neither does the array example on page 84 release the array object. {331} Last sentence; Chapter 9, Exercise 3 Answer - Besides the FoodItem class needing a dealloc method for name and price variables, the MyDataSource class also needs a dealloc method for its 'items' variable. [332] 2nd exercise; This example won't work as written. You need to set the "Role" to "viewer" - at least in PB 2.1. Looks like the layout has been changed based on Figure 10-7 [332] Ch 10, Answer to 3.; The "dataFromFile = [data retain];" should come before the if and the else clause should not be there. As it is right now, the Revert command reverts to the last time the file was loaded, not saved as it should. Here is the correct answer: - (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType { NSData * newData = [data retain]; [dataFromFile release]; dataFromFile = newData; if( textView ) { NSString * text = [[NSString alloc] initWithData:dataFromFile encoding:NSUTF8StringEncoding]; [textView setString:text]; [text release]; } return YES; } Also note that the old dataFromFile content was never released in the original code. It didn't really needed to because the only time it was assigned was the first time the window was loaded but it is required with the correct code above to avoid a memory leak since the data is loaded for each Revert command. {332} Solution for chapter 11, exercise 3; The solution supplied is incomplete (but it works nontheless): In addition to just creating a menu item and removing the 'speakText' method (from interface AND implementation), one should also remove the 'Speak' button from the GUI. (334) Excercise 1 for Chapter 13; Line 8 from code sample should match previous method for next image. Line should read: "[imageView setImage:[images objectAtIndex:currentImage]];" {335} Under solution for number 3, part c - change to init method; Solution has coding error definition of NSString file generates compile error because cannot be statically allocated should be NSString *file then completion of statement contains a minor typo in that the ofType:@"plist]; should be ofType:@"plist" closing quote added Comment: this is a WONDERFUL book and has opened up new worlds for me! Thanks! {335} Solution for chapter 15, exercise 2; As the exercise demands a reset button for the application, the resetted state of the text fields should be displayed immediately and not only after restarting the application (as it does with the supplied solution). Simply add the following four lines to the solution provided to achive this: - (IBAction)resetFields:(id)sender { // insert provided solution here [bookField setStringValue:[prefs stringForKey:@"FavBook"]]; [cityField setStringValue:[prefs stringForKey:@"FavCity"]]; [colorField setStringValue:[prefs stringForKey:@"FavColor"]]; [foodField setStringValue:[prefs stringForKey:@"FavFood"]]; } [336] Chapter 15, Exercise 4.; The updateRate method: - (IBAction)rateUpdated:(id)sender { [[NSUserDefaults standardUserDefaults] setFloatValue:[sender floatValue] forKey:@"rate"]; } gets the following warning from the compiler: warning: `NSUserDefaults' does not respond to `setFloatValue:forKey:' {336} In solutions to Chapter 16 number 1, part c; The solution code in bold type for part c of the solution is incorrect and generated compile time errors with Dev Tools current as of Dec. 2002 What worked for me was: [wordCountField setIntValue:[[[textView string] componentsSeparatedByString:@" "] count]]; [346] URL a little more than 1/2 way down the page; The URL points to the location of a great utility called Cocoa Browser. The link is still valid and the utility is still found at that location, but there is a slight problem. That version of Cocoa Browser does not work with the latest version of Cocoa (XCode 1.5 or newer). There is an upated version, Cocoa Browser SN, available here: http://numata.aquasky.jp/programming/cocoabrowser/index_en.shtml