作者经历:[self.paradigm shiftFrom:@"ruby" to:@"objective-c"]
所以的语言都会教给我们一些编程艺术。作为一名专注Ruby的开发者,我一向比较害怕诸如Java和C++等强类型的语言,还有就是它们的鼻祖C。所以当我决定学习Cocoa进行iPhone应用开发时我有点疑惑应该如何改变了,同时也期待我可以变成一个更好、更多面手的开发人员。几周以后我可以说我实现了我的目标,当然期间也付出了很多汗水。
我想很多人的处境跟我一样:想学习Objective-C进行iPhone编程,手头上就只有一两本书做向导。市面上很多Cocoa和iPhone SDK的学习教程都很好,但还是会有很多陷阱和风格上的技巧可能意味着理解一个语句和茫然看着它直至通过Google搞定之间的差别。该博文的目标是想让你不通过Google就可以获取到这些。这是8条最大的转变,我真觉得要是我在开始学习Objective-C之前知道就好了。期待你可以学到一些可以避免我已经犯过的低级错误的东西。
1. 打开NSZOMBIEENABLED
这不是开玩笑。这是应用开发中用调试来发现错误的正确方式。
你可能会知道iPhone应用中没有一个自动的垃圾回收器,所以你必须手动释放(release)和保持(retain)对象。你有时可能不小心释放了原本应该保持的对象。你的代码在向一个nil对象发送消息的时候,应用就崩溃了,这是你一脸很茫然。当然你会得到一个EXC_BAD_ACCESS 错误以提示你在试图访问一个已经释放的内存,但这起不了什么作用。
如果你打开了NSZombieEnabled,释放的实例就会保持在内存中并转化成一个僵尸(Zoombie)。如果它们接收一个消息就会触发错误。这样你就可以真正调试内存问题了。
为了打开该功能,你需要:
Ø 在Xcode中打开你的项目
Ø 项目列表中找到'Executables'部分,打开小三角形
Ø 右击可执行文件名并选择'Get Info'
Ø 单击最上方的’Arguments'
Ø 单击'Variables to be set in the environment'下方的plus图标
Ø 键入NSZombieEnabled的变量名,值为YES
马上就行动吧,你会感谢我的。不过记得在发布应用时候取消它,因为在发布的应用中你想要实例被释放掉,而不是变成僵尸。
2. 把Nil当成朋友而不是敌人
这对我是一个很难转换的一点。
在诸如Ruby等大多数的面向对象语言中,如果你调用一个nil对象的方法,你的程序会挂得很惨。这正是神奇的Ruby中Andand框架要防止的由于疏忽导致nil接收一个消息并触发错误。
在Objective-C中如果对nil传递一个消息是合法的。实际上我应该进一步说这是Objective-C的一个神奇的特色。在iPhone的类中就广泛使用到这点,因此你也应该使用。它会使得你的代码类似如下的样子:
if ([anObjectThatMayBeNil startProcessing]) {
// ...code...
}
你不需要检查对象是否是nil。如果该声明不为true,或者startProcessing失败,或者对象不存在,你都不打算执行code部分的代码段。这点是否有点疯狂完全取决于个人解读。我是从Ruby转过来我有点喜欢这点,不过我也可以感受到这会使得代码很难调试。
我的建议就是拥抱这样的疯狂。Objective-C通过允许使用不存在对象的方法提供了很多强大的功能:应该关注如何使用这样功能并让程序更健壮。
3. 记得使用该死的@和;
.这真是一个简单而弱智的建议。
NSString是大多数Objective-C类在需要字符串类似的对象时候使用的。它不仅有引号,还需要在之前加个@符号。
@"这是一个合法的NSString."
"这个不是,如果使用了就会导致让人厌烦的奇怪错误。"
同样,不要忘记分号。我知道说这句话很愚蠢,但出于Ruby的背景我就经常在语句后直接回而在编译器出错后茫然。庆幸的是你至少可以得到一个合理的消息从而让你发现错误并补上分号。
4. 在代码中使用委托(Delegate)
不过委托还是相当强大的,也是Objective-C中一个非常酷的一个风格元素。这使得你可以发送一个耗时或复杂的操作到另外一个对象并且确信你终究会听到回音,同时可以充分发挥多态从任何对象调用任务并根据情况响应任务。
这方面一个很好的例子就是CoreLocation ,它iPhone用来位置更新的框架。在应用中我使用单例的Locator来控制对CoreLocation框架的访问。CLLocationManager 的委托如下:
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
当CLLocationManager接收到一个位置更新后它就会调用delegate上的locationManager:didUpdateToLocation:fromLocation:方法。我所做的就是在代码里实现该方法,我知道它只有在位置正确更新的时候才会被调用。还有一个方法是用来处理更新位置时的错误。
这个功能的的优势就是一个对象可以改变它的委托从而使得受委者可以对相同的消息做不同的响应。应用可以在位置更新时让其中的一个控制器(Controller)显示弹出窗口,而让另一个显示动画。两个控制器的方法是一样的(locationManager:didUpdateToLocation:fromLocation:):。所做的只是更改下CLLocationManager的委托。
一旦你习惯了这样的编程风格你就会很喜欢它。
5. NSLog所有的东西
NSLog(@"Hi there, the object you want is: %@", anObject);
Ruby在崩溃的时候会给一个很好的回溯记录。我个人认为Objective-C(即使带有gdb)还需要做很多改善。经常log,在任何地方log任何东西,这样在你的应用异常崩溃的时候你就可以检查,也就更有可能发现元凶。
顺便要提下NSString中的’%@’。这是一个对象替换的语法。这仅仅对NSObjects对象有效,它会调用对象的description方法。如果你试图在普通C类型上使用它,就会崩溃。所以如下代码是就犯了大错误的:
int i = 1;
NSLog(@"The number is: %@", i); // BOOM CRASH!
通过使用正确的字符串替换进行修改后:
int i = 1;
NSLog(@"The number is: %i", i); // sweet, sweet success
这是一个容易忽略的陷阱。其他类型的字符串替换可以查看《Cocoa 字符串替换》一文档。
6. 为自定义类提供description方法
和NSLog建议紧密相连的另一个建议是:为你所有自定义的类提供一个description方法。
- (NSString *)description {
return self.name;
}
这样log它们的时候就会返回一个合适的字符串,而不是nil。
7. Objective-C没有真正使用强类型,你也不要
在合适的地方使用强类型,但你不需要受限于它,因为Objective-C也不是强类型的。任何Objective-C的对象都可以使用“id”类型声明,而不用各自的类型。这使得你可以使用一些具有潜在危险的多态实例。
Duck *aDuck = [[Duck alloc] init];
Goose *aGoose = [[Goose alloc] init];
Pond *bigLake = [[Pond alloc] init];
bigLake.inhabitant = aDuck;
[bigLake.inhabitant quack]; // The duck says: "quack!"
bigLake.inhabitant = aGoose;
[bigLake.inhabitant quack]; // The goose says: "do I look like a duck to you?"
这些仅需Pond类中的一个简单声明就可以实现了。
@interface Pond : NSObject {
id *inhabitant;
}
@property (nonatomic, retain) id *inhabitant;
Objective-C不会在意inhabitant是什么,只要它是继承自NSObject(该类定义了id)就好了。这些代码会在编译是警告inhabitant可能无法响应quack,所以还是要小心使用这个功能。如果你像给nil发送一个消息类似地将一个不合理的方法传递给一个对象,在你对象没有定义该方法的时候你的程序就会崩溃。
但是你还是可以到处传递各种不同的对象。只要记着在使用它们时候确认下它们可以响应指定的方法就好了。
8. 阅读API参考文档,之后在通过Google核对
有次我试图在UIWebView对象上做一些巧妙地操作,但从默认API查看器给出的文档来看这不大可能。Google帮了我并给了我提示(就是webView:shouldStartLoadWithRequest:navigationType:)。尽管文档看起来很完整(即使这也无法达到,除非你注册并下载下完整的文档),不过还是很多人在Cocoa和iPhone SDK上比我尝试了更久。一个简单的Google搜索有时可能带来意想不到的结果。遇到的问题你应该相信有些人已经经历过了。
小结
我确信还遗漏了很多。我在单独使用Ruby几年后对C有些健忘了,学习Objective-C就有点困难。但是我觉得还是很值得的。Objective-C很简单优雅,能给你更多的帮助并制作一些很神奇的东西。记住上述的8条建议,你的Objective-C程序也会很健壮。如果你有声明可以分享的,记着发表评论,也让其他人看看你有用的建议。
原文链接: