My Cocoa coding is for hobby only, and only for about 4 years, so I do not have experience with working in teams or on multi-developer projects.

But I see this issue in other development environments of recent issue as well. Apple has provided a rich set of finely-granulated APIs, which allow a huge amount of flexibility and customization. The downside of this (true with the Carbon C APIs as well) is that to do a simple thing involves calling 3 or 4 APIs just to set the "default" values for pieces of the final method call that you want.

Here's an example I just finished. All I want is to retrieve 14 bytes of data from accessing a single URL. In a shell script I could do it with one "curl" call. In Cocoa, I have to

1) Make a string into an NSURL
2) Make an NSURLRequest from the NSURL
3) Call the convenience method "[NSURLConnection sendSynchronousRequest:..." to avoid having to even further specify details about what I want to do.

So this comes down to

[NSURLConnection sendSynchronousRequest: [NSURLRequest requestWithURL: [NSURL URLWithString: @"http://random.org/integers/?num=1&min=1&max=4&col=5&base=10&format=plain&rnd=new "]] returningResponse: NULL error:NULL];

Now that is going to be a bitch to debug if I write it that way to begin with, because there is no way to get the intermediate values without putting expressions in the gdb console. So I have developed the habit of doing it in the following way:

1) Write each portion of the code by assigning to intermediate ivars. This of course is easiest if you just type them in-line as you write them, but then of course they will not show up in the debugger so it is better to go ahead and type them in the @interface section.

(As an aside, wouldn't it be great if Xcode had a feature to add ivar declarations to @interface based on what you selected - e.g. select the "NSString *foo" part of a statement "NSString *foo = [NSString string]" statement and Xcode would automatically add "NSString *foo;" to the @interface and remove the characters up to the "f" in "foo" from the selected statement. I find myself doing this about 50 times a day.)

2) Debug the code block. If it runs correctly, then I am left with these single-use ivars which clog up my header file and make it difficult for another person to tell which is the real result variable. They also have to keep referring back to the intermediate vars to see what their values are in order to interpret the main API call. It becomes harder and harder to construct names for these ivars as they all have very similar contents and purposes. So you wind up with ivars named "voterCountForVoterAfterRandomChoiceIsMadeButBeforeFinalSorting" and so forth.

3) For each ivar that I used, I copy the right side of the assignment statement and paste it in place of the name of the ivar in the subsequent code lines.

4) Then after testing the new code, I delete all the ivar assignments and delete their definitions from @interface.

N.B.: I don't do this if the intermediate variables are used more than once in the final code call - in those cases I leave the variable name in there to avoid calculating it more than once.

What would be great is if Apple would give us many more convenience methods that pared it down to the most common things - like a "- (NSStriing *) NSSynchronousURLFetch:(NSString *)theURL" method that just takes a string which represents the URL and returns a string which is the content at that URL.

I'd also be very interested in others' views on this.


Date: Mon, 14 Apr 2008 22:53:16 -0400
From: "Adam Gerson" <[EMAIL PROTECTED]>
Subject: is this badly written code?
To: "cocoa-dev@lists.apple.com" <cocoa-dev@lists.apple.com>
Message-ID:
        <[EMAIL PROTECTED]>
Content-Type: text/plain; charset=ISO-8859-1

In cocoa its very tempting to write a single line of code like:
NSManagedObject *selectedTreeObject = [[[[[self delegate]
mainWindowController] treeController] selectedObjects]
objectAtIndex:0];

or to flush it out in to individual lines:

NSWindowController *mainWindow = [[self delegate] mainWindowController];
NSTreeController *treeController = [mainWindow treeController];
NSArray *selectedTreeObjects = [treeController selectedObjects];
NSManagedObject *selectedTreeObject = [selectedTreeObjects objectAtIndex:0];

I am looking for some guidance on best practices in a situation with a
lot of nested calls like this. If ultimately the only value I care
about is the final one, selectedTreeObject, whats the best way to go
about getting it? I know "best" is a subjective word. Interested to
hear all of your opinions.

Adam
_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]

Reply via email to