A better introduction to Objective-C
cocoadevcentral.com
cocoadevcentral.com
- (void) dealloc
{
self.caption = nil;
self.photographer = nil;
[super dealloc];
}
Using the dot syntax will invoke a setter whose implementation might change if the class is subclassed, which can be the cause of subtle errors. Also, if you're using KVO (Key-Value Observing), invoking the setter might notify observers who then try to work with a (partially) deallocated object.This is standard:
- (void) dealloc
{
[caption release];
[photographer release];
[super dealloc];
}My problem with this argument is that the user could botch release just as well. Maybe they are slightly more likely to botch the setter, but either way they are botching it.
Since your object is likely to be dealloced at an odd time (for instance when an autorelease pool is drained), and in an inconsistent state (half its fields missing), it's much better to do a release.
- (void)dealloc {
self.someOtherVariable = nil;
self.myC = nil; // Sends KVO on myC. B sees half-deconstructed A.
self.myB = nil; // myB now is dealloc'd and stops observing A.
[super dealloc];
}
Admittedly this is a real edge case and probably bad design, but it's not overtly terrible. I have a couple cases where objects observe their owners.BTW thanks for the blog, Mike! I love it.
There may well be similar setups which aren't broken which still exhibit the problem, though.
Glad you enjoy the blog!
if ( [self hasPrefix:@"http://"] )
return YES;
else
return NO;
The other thing that puzzled me a little was the K&R interfaces and Allman everything else, but I guess it's a consistent style. I do use K&R exclusively for blocks, so I suppose I am just as guilty. return [self hasPrefix:@"http://"];
If so, I disagree. The way it was written in the tutorial is easier to read when going into a new language — and teaches you that Objective-C uses YES and NO, rather than true and false.I might even be convinced to go a step further and say that early on, it is far more important to actually get started and avoid hitting roadblocks, then it is to write nice and pretty code. You can figure that out later on, once you're comfortable with everything.
This particular construct is debatable - I personally think it can read better to explicitly break out a boolean statement like that in some cases, especially in a simple method like in this example. I certainly wouldn't take a hostage over that opinion, though.
Arguably, an ObjC programmer should know that booleans are YES and NO and not true or false, but so what? Code that can't be maintained isn't good code. Code that is developed within a team should be readable before it should be clever. if it is clever, or if it needs to be clever, then it should be commented to the degree that it is more easily understood.
I personally would rather write readable code than more comments.
It's just C. 0 is false, anything else is true.
Don't miss all of the other more advanced tutorials similar to this one at the full site, http://CocoaDevCentral.com
In this case, I had a desire to dig into an Obj-C project yesterday to try yet again to really learn it. The Apple tutorial is extensive, if verbose. This introduction is exactly what I need at this moment to get me through the knowledge gap.
[NSString stringWithFormat:[prefs format]];
"Avoid nested nesting more than two message calls on a single line, as it easily gets unreadable."Oh, the joy of function call chaining in languages like JavaScript:
rs = db.find({"name": "Joe"}).limit(10).lower().sort();
I don't dare to imagine how that'd look in ObjectiveC ;-) NSArray *records = [db find:[NSDictionary dictionaryWithObject@"Joe" forKey:@"name"] limit:10];
[records sortedArrayUsingComparator:^(id a, id b) {
// logic for sorting
}];
...and then you'd do the lower method on usage... NSArray *records = [[db find:[NSDictionary dictionaryWithObject:@"Joe" forKey:@"name"] limit:10]
sortedArrayUsingComparitor:^(id a, id b) {
// sort logic
}];
I typically add a category to NSArray for mapping a selector or block. The signatures are
- (NSArray )mapBlock:(id (^)(id object))block;
- (NSArray )mapSel:(SEL)selector;Which would enable you to do it all in one statament:
NSArray *records = [[[db find:[NSDictionary dictionaryWithObject:@"Joe" forKey:@"name"]
limit:10]
sortedArrayUsingComparitor:^(id a, id b) {
// sort logic
}]
mapSel:@selector(lowercaseString)];
Also for mapping over an array you can usually use NSArrays valueForKey: which returns a new array
which contains the result of calling valueForKey: on each member of the target array.
As your sorting logic would typically exist in the db layer whether you were using CoreData or something else, it would be easy to write a wrapper such that you could write something like: [[[[MyFetchRequest forEntityNamed:@"foo"
orderedBy:@"SomeKey"
limit:10] fetch]
valueForKey@"nameField.lowerCaseString"]
enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// do stuff here
}];
Again this is all 'fake' code as this is just a readability discussion.I don't really agree with the article that nesting message-sends leads to unreadable code. I think reading obj-c is a lot like reading lisp s-expressions and your eye / brain quickly learns to read nested constructs. I generally try not to save anything to an explicit var that I don't intend to use somehow. (of course there are limits to this) I don't find nested code above difficult to read, YMMV.
Apple has a bunch of good tutorials, for example this one: http://developer.apple.com/library/mac/#documentation/cocoa/....
They appear to be methods for doing multiple inheritance type stuff without the multiple inheritance problems. From what I understand protocols set a list of methods that a class implementing that protocol must provide, whereas categories let you 'tack-on' methods to existing classes.
They seem like powerful features & I'm sure there is more to them than I've described, but I sometimes have problems re-wiring my brain to 'think in objective-c'.
Seeing more tutorials that show how to use these interesting language concepts in real projects would be very educational.
Categories are useful not for sharing code, but for expanding a class's functionality. This is especially useful when you write a class X that works with an existing class Y, but some of X's code should be an instance method of Y, or X introduces additional capability for Y to support X. UITableView adding functionality to NSIndexPath to support referencing table sections and rows is a good example. All those Java classes that add static methods to support existing Java classes, or if you used Smalltalk and added methods to existing classes, this is the equivalent.
>Equivalent to Java's interfaces, but Cocoa use protocols heavily for delegates only.
Uh, NSCoding, NSCopying and the million other non-delegate protocols? Cocoa uses protocols heavily for a lot of things, not just delegates. The average Cocoa/Cocoa Touch developer, however, uses protocols mostly for delegates.
A protocol says that an object can (and in some (but not all) cases, is required to) implement a given list of methods, leaving the implementation/the "how" up to the programmer. Think of protocols as being similar to interfaces in Java.
OTOH, A category says "in addition to the existing methods, this class will also, for sure, implement these additional methods — and here's how."
Perhaps most importantly, the tutorial should have mentioned that objective-c is a superset of c. That alone would have answered most of the questions around flow control statements since those, presumably, use the same syntax as c. As it stands, there's barely enough in this tutorial to do basic scripting with objective-c.
Just have to get used to it, I suppose.
In any case, if you're reading an introduction to Objective-C today, you're probably not going to be submitting anything to the App Store in the next fortnight.
The rest of ARC still needs a bit of runtime support, but the functions it needs are basically just wrappers around the standard Objective-C memory management messages. They exist because they enable various optimizations. Apple provides a shim library for these which allow ARC apps to run on iOS 4.3. I'd guess they could run on even earlier OSes, but I believe that's not officially supported.
[1] Full disclosure: I haven't released my first app yet so I'm wondering if I should only develop with the new IOS 5 tools or if I'm going to have to write my app with Xcode 4.1 anyway.
There is no reason to support anything earlier than iOS 4.3 for an app being released today. 4.3 works on all devices except the original iPhone, the 3G, and the equivalent iPod Touch models. It's also a free upgrade for (nearly?) everybody. The fraction of your audience still using something prior to 4.3 will be very small.
If you're not releasing very soon, it will probably be worthwhile to simply require iOS 5. New OS version uptake tends to be fast, and it seems likely that those who don't update their OS are also less likely to buy apps. iOS 5 is a pretty big deal with a lot of new features, so I think it will probably see pretty swift uptake. iOS 5 also provides a lot of nice features for a developer (like those zeroing weak references, which I believe are pretty important for ARC programming), so there's a good incentive on your end to require 5+.
There's only one reason that I can think of: Verizon/CDMA iPhones only run iOS 4.2.x, and won't be on parity with GSM iPhones until iOS 5 comes out.
For whatever reasons, some users still stick with older firmware versions. 100% of our userbase is iOS 4+, but about 10% of it is below 4.3.