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


当前回答

功能性更强。

Objective-C是面向对象的语言,但是Cocoa框架是函数式风格的,并且在很多情况下是函数式设计的。

There is separation of mutability. Use immutable classes as primary, and mutable object as secondary. For instance, use NSArray primarily, and use NSMutableArray only when you need. There is pure functions. Not so many, buy many of framework APIs are designed like pure function. Look at functions such as CGRectMake() or CGAffineTransformMake(). Obviously pointer form looks more efficient. However indirect argument with pointers can't offer side-effect-free. Design structures purely as much as possible. Separate even state objects. Use -copy instead of -retain when passing a value to other object. Because shared state can influence mutation to value in other object silently. So can't be side-effect-free. If you have a value from external from object, copy it. So it's also important designing shared state as minimal as possible.

但是也不要害怕使用不纯函数。

There is lazy evaluation. See something like -[UIViewController view] property. The view won't be created when the object is created. It'll be created when caller reading view property at first time. UIImage will not be loaded until it actually being drawn. There are many implementation like this design. This kind of designs are very helpful for resource management, but if you don't know the concept of lazy evaluation, it's not easy to understand behavior of them. There is closure. Use C-blocks as much as possible. This will simplify your life greatly. But read once more about block-memory-management before using it. There is semi-auto GC. NSAutoreleasePool. Use -autorelease primary. Use manual -retain/-release secondary when you really need. (ex: memory optimization, explicit resource deletion)

其他回答

想想nil值

正如这个问题所指出的,到nil的消息在Objective-C中是有效的。虽然这通常是一个优势——导致更干净和更自然的代码——但如果您在意想不到的情况下获得nil值,该功能偶尔会导致特殊且难以追踪的错误。

使用标准的Cocoa命名和格式化约定和术语,而不是使用其他环境中使用的任何术语。有很多Cocoa开发人员,当他们中的另一个人开始使用您的代码时,如果它看起来和感觉上与其他Cocoa代码相似,那么它将更容易接近。

做什么和不做什么的例子:

Don't declare id m_something; in an object's interface and call it a member variable or field; use something or _something for its name and call it an instance variable. Don't name a getter -getSomething; the proper Cocoa name is just -something. Don't name a setter -something:; it should be -setSomething: The method name is interspersed with the arguments and includes colons; it's -[NSObject performSelector:withObject:], not NSObject::performSelector. Use inter-caps (CamelCase) in method names, parameters, variables, class names, etc. rather than underbars (underscores). Class names start with an upper-case letter, variable and method names with lower-case.

无论你做什么,不要使用Win16/ win32风格的匈牙利符号。甚至微软也在转向。net平台时放弃了这一点。

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

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

这是一个微妙但很方便的方法。如果你将自己作为委托传递给另一个对象,在dealloc之前重置该对象的委托。

- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}

这样做可以确保不再发送更多的委托方法。当您即将dealloc并消失在以太中时,您希望确保没有任何东西可以意外地向您发送更多消息。还记得自己。someObject可以被另一个对象保留(它可以是一个单例对象或在自动释放池中或其他任何对象),直到您告诉它“停止向我发送消息!”,它才会认为您即将被释放的对象是公平的游戏。

养成这种习惯将使您避免大量令人痛苦的调试的奇怪崩溃。

同样的原理也适用于键值观察和NSNotifications。

编辑:

更有防御性的改变:

self.someObject.delegate = NULL;

成:

if (self.someObject.delegate == self)
    self.someObject.delegate = NULL;

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

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

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

@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;
}