我知道HIG(这非常方便!),但是在编写Objective-C时,更具体地说,在使用Cocoa(或CocoaTouch)时,您使用了什么编程实践?


当前回答

抵制世界的子类化。在Cocoa中,很多工作都是通过委托和使用底层运行时完成的,而在其他框架中则是通过子类化完成的。

例如,在Java中你经常使用匿名*Listener子类的实例,在. net中你经常使用EventArgs子类。在Cocoa中,你什么都不用做——而是使用目标-动作。

其他回答

黄金法则:如果你分配了,那么你就释放了!

更新:除非你正在使用ARC

不要使用未知字符串作为格式字符串

当方法或函数接受格式字符串参数时,应确保能够控制格式字符串的内容。

例如,当记录字符串时,很容易将字符串变量作为唯一参数传递给NSLog:

    NSString *aString = // get a string from somewhere;
    NSLog(aString);

这样做的问题是,字符串可能包含被解释为格式字符串的字符。这可能导致错误的输出、崩溃和安全问题。相反,你应该将字符串变量替换为一个格式字符串:

    NSLog(@"%@", aString);

简单但经常被遗忘。根据规格:

一般来说,方法各不相同 具有相同选择器的类 (相同的名字)也必须共享 相同的返回值和参数类型。这 约束是由编译器施加的 允许动态绑定。

在这种情况下,所有相同的命名选择器,即使在不同的类中,也会被认为具有相同的返回/参数类型。这里有一个简单的例子。

@interface FooInt:NSObject{}
-(int) print;
@end

@implementation FooInt
-(int) print{
    return 5;
}
@end

@interface FooFloat:NSObject{}
-(float) print;
@end

@implementation FooFloat
-(float) print{
    return 3.3;
}
@end

int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    
    id f1=[[FooFloat alloc]init];
    //prints 0, runtime considers [f1 print] to return int, as f1's type is "id" and FooInt precedes FooBar
    NSLog(@"%f",[f1 print]);

    FooFloat* f2=[[FooFloat alloc]init];
    //prints 3.3 expectedly as the static type is FooFloat
    NSLog(@"%f",[f2 print]);

    [f1 release];
    [f2 release]
    [pool drain];

    return 0;
}   

IBOutlets

从历史上看,outlet的内存管理一直很差。 当前的最佳实践是将outlet声明为属性:

@interface MyClass :NSObject {
    NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end

使用属性使内存管理语义清晰;如果使用实例变量综合,它还提供了一致的模式。

如果您使用的是Leopard (Mac OS X 10.5)或更高版本,则可以使用Instruments应用程序来查找和跟踪内存泄漏。在Xcode中构建程序后,选择使用性能工具> Leaks运行>。

即使你的应用程序没有显示任何泄漏,你可能把对象保存得太久了。在Instruments中,您可以为此使用ObjectAlloc工具。在Instruments文档中选择ObjectAlloc乐器,并通过选择View > detail(它旁边应该有一个复选标记)来显示乐器的详细信息(如果还没有显示的话)。在ObjectAlloc详细信息中的“分配生命周期”下,确保选择“已创建和仍然存在”旁边的单选按钮。

现在,每当您停止记录应用程序时,选择ObjectAlloc工具将在“# Net”列中显示对应用程序中每个仍然活动的对象的引用数。确保不仅要查看自己的类,还要查看NIB文件的顶级对象的类。例如,如果你在屏幕上没有窗口,而你看到一个仍然存在的NSWindow的引用,你可能没有在你的代码中释放它。