Sunday, June 21, 2009

Differences between Cocoa and Cocoa Touch

I learned...

According to Dave Mark in "Beginning iPhone Development: Exploring the iPhone SDK":

"If you are coming to iPhone with previous Cocoa experience, a few tools that you're probably accustomed to using aren't available on the iPhone. The iPhone SDK doesn't support Core Data or Cocoa Bindings. We mentioned earlier that Cocoa Touch uses Objective C 2.0, but one of the key new features of that language is not available on iPhone: Cocoa Touch does not support garbage collection."

Its a good thing I spent a lot of time reviewing memory management. It looks like those retain and release statements will come in handy. I'm also glad I stopped at Chapter 8 in "Cocoa(R) Programming for Mac(R) OS X (3rd Edition)" and picked up this new book. Core Data was only a few chapters away and I would have wasted lots of precious time learning something I wouldn't be able to use.

Currently reading "Beginning iPhone Development: Exploring the iPhone SDK" by Dave Mark & Jeff LaMarche



This Purchase: $26.39 | Running Total: $3008.11

The Benefit of Key-Value Coding

I am learning about Key-Value coding in Chapter 7 of "Cocoa(R) Programming for Mac(R) OS X (3rd Edition)".

I would say the most important lesson from this chapter is knowing what accessor methods are and when they get called. The author's tutorial in this chapter clearly demonstrates this behavior. In the tutorial, I implemented an AppController with two accessor methods "set" and "get".

The implementation of these methods were fundamentally simply.

"set" sets an instance variable in the AppController class to a specified value
"get" returns that value

The "set" accessor method got called when I used "setValue ... forKey".
e.g. [self setValue:[NSNumber numberWithInt:5] forKey:@"fido"];

The "get" accessor method got called when I used "valueForKey".
e.g. NSNumber *n = [self valueForKey:@"fido"];

The tutorial helped illustrate this by having me issue NSLog calls from within each accessor method. I was also taught how to bind key-value code to a graphical object, in this case a slider. When the slider moved, the NSLog calls showed the set and get methods being called in the GDB debug console window.

Thursday, June 18, 2009

How to create a new instance of an AppController in the NIB

Following the steps in Aaron Hillegass' SpeakLine tutorial in Chapter 5 of "Cocoa(R) Programming for Mac(R) OS X (3rd Edition)", I got lost on how to add the AppController to the nib. I found out this is what you need to do:

Assuming you've already added the "AppController.m" and "AppController.h" Objective C files to your project.

1. From Interface Builder, go to Tools > Library
2. Find NSObject under "Library - Cocoa - Objects & Controllers"
3. Drag that into the NIB window (i.e. - MainMenu.xib)
4. Rename the new NSObject to "AppController"
5. With the "AppController" object highlighted, go to Tools > Identity Inspector, drill down on the "Class" field and select "AppController"
6. Your AppController class is now added to the nib

Accessor Methods: "Retain, then Release" methodology

From "Cocoa(R) Programming for Mac(R) OS X (3rd Edition)" by Aaron Hillegass

If you have a nonpointer type, the accessor methods are quite simple. For example, if your class has an instance variable called foo of type int, you would create the following accessor methods:

- (int)foo
{
return foo;
}

-(void)setFoo:(int)x
{
foo = x;
}

MATTERS BECOME MORE COMPLICATED IF FOO IS A POINTER TO AN OBJECT. In the "setter" method, you need to make sure that the new value is retained and the old value released, as shown below:

-(void)setFoo:(NSCalendarDate *)x
{
[x retain];
[foo release];
foo = x;
}

Wednesday, June 17, 2009

I installed XCode but cannot find the executable. Where does it get installed?

Once you download and install XCode, the executable can be found here:

Macintosh HD > Developer > Applications > XCode

Debugging "objc[17695]: FREED(id): message release sent to freed object=0x1073d0"

Here's a good article on how to troubleshoot these kinds of errors:
http://www.cocoadev.com/index.pl?DebuggingAutorelease

Taken from the article:

One of the most opaque bugs I've had to deal with in Cocoa is leaving a released object in the autorelease pool, causing an EXC_BAD_ACCESS in NSPopAutoreleasePool?(). When this happens, it's pretty much impossible to tell what the doubly-released object was and where it was instantiated.

Fear no more! Using Cocoa's NSZombie? debugging class and the command-line malloc_history tool, we can nail this bug in a pinch.

Suppose you have the following (obviously incorrect) code:

  NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSData* data = [NSData dataWithBytes:"asklaskdxjgr" length:12];

[data release];
[pool release];

The dataWithBytes: method sends an autorelease message to the created object, so we don't need to release it ourselves. When the autorelease pool is tossed the freed data object gets another release message, our app crashes, and we have no idea why.

The dataWithBytes: method sends an autorelease message to the created object, so we don't need to release it ourselves. When the autorelease pool is tossed the freed data object gets another release message, our app crashes, and we have no idea why.

Here's what we do:

Click on the "Targets" tab, open "Executables" and select the app (In XCode 2.0, double-click the executable in the file tree and select the arguments tab to enter environment variables). In the executable settings, add the following environment variables and set their values to "YES" (without the quotes):

  NSDebugEnabled
NSZombieEnabled
MallocStackLogging

You may also want the following environment variable set to YES:

  MallocStackLoggingNoCompact

With NSZombieEnabled, Cocoa sets an object's isa pointer to the NSZombie? class when its retain count drops to zero instead of deallocating it. Then when you send a message to an NSZombie? object (i.e., you're accessing freed data), it raises an exception and tells you where the object lives:

  2003-03-18 13:01:38.644 autoreleasebug[3939] *** *** Selector 'release'
sent to dealloced instance 0xa4e10 of class NSConcreteData.

Since you have MallocStackLogging turned on, you can now run "malloc_history

" to see the stack trace when the object was allocated:

  [dave@host193 Frameworks]$ malloc_history 3939 0xa4e10

Call [2] [arg=32]: thread_a0000dec |0x1000 | start | _start | main |
+[NSData dataWithBytes:length:] | NSAllocateObject | object_getIndexedIvars |
malloc_zone_calloc

if you run under gdb, you may enter:

 (gdb) shell malloc_history 3939 0xa4e10

And there it is: the double-released object was allocated with [NSData dataWithBytes:length:] in the function main()!

I love you, Cocoa!