PDA

View Full Version : Learning ObjC, Cocoa, and iPhone SDK


Kraetos
2008-06-17, 10:53
I need to jump into Cocoa and iPhone development quickly for a job. I picked up Hillegass's (http://www.bignerdranch.com/index.shtml) Cocoa Programming for Mac OS X (http://www.amazon.com/exec/obidos/ASIN/0321503619/bignerdranch-20) after hearing on good authority that it's more or less the definitive learning Cocoa book.

I just got through the first three chapters and I am afraid my head is spinning. I don't think I've learned much.

My programming background consists of:

- About a year of formal training in Java, which I picked up pretty quickly
- Self-taught HTML, CSS and PHP - but I'm actually pretty good with PHP
- Familiarity with Perl and JavaScript. I can read them, debug them, adapt code for my own purposes, or write small functions for other peoples code, but I've never written anything substantial in Perl or JavaScript.

I don't know C, or C++, and I think that's what is more or less getting in my way. Things like memory management are totally foreign to me. Should I just keep truckin' through this Cocoa book or should I be learning something else first - something a little more basic in C, perhaps?

To make things more challenging, I don't have much time. I need to be part of a Cocoa dev team... soon. :eek: I'm pretty good at teaching things to myself, so this is frustrating. I just feel like I've maybe skipped a step.

chucker
2008-06-17, 11:08
Thus quoth myself: (http://www.reddit.com/info/6n0gk/comments/c04brwa)
I bought Hillegass's Cocoa programming book, and it's good, but for years and years I kept retrying to figure the language out, and kept failing.
Then I had an actual idea for a very simple problem I wanted to solve, and suddenly, it just clicked with me. Within days, I had a working implementation; a few weeks later, I had several times as many features as I had planned.
Maybe it's just me, but tutorials and the like — whether online, in book form, as a podcast or otherwise — just don't seem to really help me much. Learning by doing and having a reference to my avail, on the other hand, works great.
So my advice would be: just think of something simple that you're missing in OS X; a problem that you actually have that you might be able to solve. Solves the dogfood problem and motivates you just enough to actually get it done. Learning the basics language, then, really isn't too hard.
As for nifty trickery like method swizzling… you'll get there eventually along the way.
Oh, and aside from Apple's own resources, keep checking the cocoadev wiki as well.

In short, I for one strive in learning by doing. Given that you say "I'm pretty good at teaching things to myself", maybe the same applies to you. Solve a problem that's simple yet useful. Worked in my case.

In particular, it was mere days after I had bought my MacBook Pro, and I got curious about CPU temperature. At the time, there was only one solution to finding that information out, and it required installing a kernel extension and running a sysctl command in the shell. So I wrote a wrapper around it to display the results in the menu bar, thereby learning not just how to mix C and ObjC code well (i.e. knowing which to use when), but also learnt how to figure things out in the various APIs, or how to look them up fast.

In any case, if you have concrete questions, just ask. But I suggest you just find a place to begin writing an app.

I do not believe your lack of knowledge of C is much in the way. Given that you know Perl, Java, JavaScript and PHP, the C-style syntax is hardly foreign to you (all of those are inspired by it). The only major piece you're missing is pointers, and those aren't terribly essential for basic Cocoa work.

Kraetos
2008-06-19, 11:24
Yeah, you're totally right. The problem is I don't even know where to start. :(

Alright, concrete examples. I haven't started out on an actual program I need, but there's a challenge problem in the book that I think would be very helpful for me to figure out. I've been working at it but I've gotten stuck.

So, idea is: an application with a single window that lets you input a string, which will then return the number of characters in the string.

Here's my header file, thus far:


#import <Cocoa/Cocoa.h>

@interface AppController : NSObject
{
IBOutlet NSTextFieldCell *textFieldCell;
}

- (IBAction)countIt:(id)sender;

@end


And my main file:


#import "AppController.h"

@implementation AppController

-(id)init
{
[super init];

// Logging everything because I dont quite know whats going on yet.
// And for debugging.
NSLog(@"init");
return self;
}

- (IBAction)countIt:(id)sender
{
NSString *string = [textFieldCell stringValue];

// is the string zero length?

if ([string length] == 0)
{
NSLog(@"string from %@ is of zero-length", textFieldCell);
return;
}

// code to get the length of the string goes here
// code to send it back to NSTextFieldCell
}

@end


I can't get the syntax right for the NSString's length method. I want to send it to the log as well as the text field I have. I expected "NSLog([string length]) to work but it didn't.

Ergh, I could write this in 2 minutes in Java. This is frustrating. Thanks for the encouragement chucker :)

ShadowOfGed
2008-06-19, 12:16
I can't get the syntax right for the NSString's length method. I want to send it to the log as well as the text field I have. I expected "NSLog([string length]) to work but it didn't.

Ergh, I could write this in 2 minutes in Java. This is frustrating. Thanks for the encouragement chucker :)

Well, "NSLog([string length])" will fail because [string length] is going to return an NSUInteger. NSLog() works like printf(); it requires a formatting string. I don't know about Java, but there's no implicit typecasting to strings in C, C++, and Objective-C. So what you really needed was this:

NSLog(@"%d", [string length]);

Now, I'll be honest. I still haven't entirely figured out the Cocoa/UI paradigms yet. To learn the language itself, I'd suggest writing some sort of command-line tool that links only against Foundation.framework. That gives you access to the fundamental collections and types available to most Objective-C code, without also requiring you to learn the Cocoa/UI paradigms, Interface Builder, KVC/KVO, bindings, etc.

Kraetos
2008-06-19, 12:43
Yeah, that worked.... sorta.

It always returns 14, regardless of the input string. Is it maybe counting something other than characters?

My intent is actually to learn Cocoa, not ObjC, because I need to get onto the iPhone quickly.

chucker
2008-06-19, 12:46
First, you want to hook up the outlet to the NSTextField, not its cell. The cell is the 'backstage object' doing the drawing on screen and other internals; the object you generally want to interact with doesn't end with 'cell'.

And second, as ShadowOfGed said, you cannot pass the results of [string length] on to NSLog(), because it expects an object. (It will either return the object itself, or try to send -description or -debugDescription* on to it. All Cocoa classes have a -description method. In case of a string, it returns the string itself; for NSDictionary, it returns the hierarchy of obejcts in it; for many other objects, it merely returns some basic debug info. You can overwrite it to make your custom classes' objects, well, descriptive.)

Here's what will work:

@interface AppController : NSObject {
IBOutlet NSTextField *textField;
}

-(IBAction) countIt:(id)sender;
@end

And:

-(IBAction) countIt:(id)sender {
NSLog(@"%i", [[textField stringValue] length]);
}

The -length method returns an NSUInteger; the %i formatter allows that to be used within a string; @"" creates a string on the fly which then gets used by NSLog.

%d will work, too. I think your problem with 14 is that you're sending messages to the cell (NSTextFieldCell), not the control (NSTextField).

*) IIRC.

Kraetos
2008-06-19, 13:00
Alright, awesome. It compiles now just fine. Also, thanks for that description of NSLog. That makes sense to me now.

But, it still only returns 14 :(

chucker
2008-06-19, 13:06
Here's (http://chucker.mystfans.com/temp/Test.zip) my project that does the above.

ShadowOfGed
2008-06-19, 13:24
Alright, awesome. It compiles now just fine. Also, thanks for that description of NSLog. That makes sense to me now.

But, it still only returns 14 :(

Well, change your NSLog to something more verbose:

NSString *fieldValue = [myTextField stringValue];

NSLog(@"%i characters in '%@'", [fieldValue length], fieldValue);

Maybe there are a bunch of space characters hiding somewhere? I doubt [NSString -length] is lying to you; I'm just guessing there are characters in that string you're not expecting.

Kraetos
2008-06-19, 13:25
My code looks identical to yours, but mine still doesn't work.

I think I found something though, in the XIB file. When I control-drag from my text field to my AppController object, it links it under "sent actions." Yours does the same link, but under "referencing outlets." What's the difference between the two?

Thanks so much for your help, by the way :)

ShadowOfGed
2008-06-19, 13:29
An outlet (IBOutlet) is used to gain access to an object in the view hierarchy. This is used when your object needs to reference, say, a text field directly. You declare an ivar with IBOutlet, and then wire it up in Interface Builder.

An action (IBAction) is a method that is invoked in response to a UI event. Say, when the user clicks a button. For a text field, it could be things like when it receives focus, when it loses focus, when the value changes, etc.

This is why you always see IBOutlet on ivars and IBAction on methods.

chucker
2008-06-19, 13:29
When I control-drag from my text field to my AppController object, it links it under "sent actions."

You want to drag from AppController to the text field to create the outlet. Dragging the other direction shouldn't have let you connect to that outlet at all, though.

Kraetos
2008-06-19, 13:55
Hah! I did it! I had everything in interface builder wired backwards!

Thanks guys! :)

chucker
2008-06-19, 13:57
Sweet. :)

ShadowOfGed
2008-06-19, 14:01
You want to drag from AppController to the text field to create the outlet. Dragging the other direction shouldn't have let you connect to that outlet at all, though.

This is one of the things I've never quite understood about Interface Builder. WHY ON EARTH should the direction I connect an outlet matter? From all appearances, it's a non-directed graph. The line has no arrow. If I want to wire control/view to an outlet, I feel like I should be able to connect it in either direction.

Does someone care to explain? :)

Kraetos
2008-06-19, 15:11
Erk, I lied. I can't get it to output to a text field.

I added this line of code in countIt:


[textField setStringValue:(@"%i characters in '%@'", [fieldValue length], fieldValue)];


And then linked AppController to an NSTextField (a label). If I drag from the text field to the AppController, it uses the text in the text field as input. If I go the other way, nothing happens.

What am I missing?

chucker
2008-06-19, 16:35
[textField setStringValue:(@"%i characters in '%@'", [fieldValue length], fieldValue)];

Try:

[textField setStringValue:[NSString stringWithFormat:@"%i characters in '%@'", [fieldValue length], fieldValue]];

What you're missing is that NSLog(), being a macro for debug purposes, does various things like stringWithFormat automagically.

Kraetos
2008-06-20, 10:07
Awesome... that worked real well.

And my last question is, how do I send that to a different text field? I can only get the code to interact with one of my two text fields; never both.

chucker
2008-06-20, 11:16
To interact with two text fields, you need two outlets.

First, I extend the nib in Interface Builder, adding a label (its class is NSTextField as well).

I then add an outlet for that:

@interface AppController : NSObject {
IBOutlet NSTextField *textField;
IBOutlet NSTextField *label;
}

-(IBAction) countIt: (id)sender;
@end

Back in IB, I control-drag from the App Controller to the label, selecting label instead of textField as the outlet this time.

And finally, I modify the countIt: method as follows:

-(IBAction) countIt: (id) sender {
[label setStringValue:[NSString stringWithFormat:@"%i characters in %@", [[textField stringValue] length], textField]];
}

I can now type text in the text field and click the button, which will take the text field's stringValue using the outlet "textField", and set the label's stringValue to the result using the outlet "label".

Kraetos
2008-06-20, 12:14
Makes sense!

Alright this is starting to click. Thanks a lot chucker :)