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


当前回答

不要忘记NSWindowController和NSViewController会释放它们所控制的NIB文件的顶级对象。

如果手动加载NIB文件,则在使用完该NIB的顶级对象后,需要负责释放它们。

其他回答

变量和属性

1/保持头文件整洁,隐藏实现 不要在头文件中包含实例变量。作为属性放入类延续中的私有变量。公共变量在头文件中声明为公共属性。 如果它应该是只读的,将其声明为readonly,并在类延续中将其重写为readwrite。 基本上我根本不用变量,只用属性。

2/给你的属性一个非默认变量名,例如:


@synthesize property = property_;

原因1:在分配属性时,您将捕获由于忘记“self.”而引起的错误。 原因2:从我的实验中,仪器中的泄漏分析仪在检测默认名称的泄漏属性时存在问题。

3/不要在属性上直接使用retain或release(或仅在非常特殊的情况下)。在dealloc中,给它们分配一个nil。保留属性意味着自己处理保留/释放。例如,您永远不知道setter是否没有添加或删除观察器。您应该只在它的setter和getter中直接使用变量。

的观点

1/如果可以的话,将每个视图定义放入xib中(例外通常是动态内容和层设置)。它节省时间(比写代码简单),易于更改,并保持代码整洁。

2/不要试图通过减少视图数量来优化视图。不要在代码中创建UIImageView而不是xib,因为你想在其中添加子视图。使用UIImageView作为背景。视图框架可以毫无问题地处理数百个视图。

3/ iboutlet不需要总是被保留(或强大)。注意,大多数iboutlet都是视图层次结构的一部分,因此隐式保留。

4/释放viewDidUnload中的所有iboutlet

5/从dealloc方法调用viewDidUnload。它不是隐式调用的。

内存

1/创建对象时自动释放对象。许多错误是由于将释放调用移动到一个if-else分支或在返回语句之后引起的。释放而不是自动释放应该只在特殊情况下使用——例如,当你在等待一个运行循环时,你不想让你的对象过早被自动释放。

2/即使你在使用自动引用计数,你也必须完全理解保留-释放方法是如何工作的。手动使用保留-释放并不比ARC更复杂,在这两种情况下,您都必须考虑泄漏和保留周期。 考虑在大型项目或复杂的对象层次结构上手动使用保留释放。

评论

1/让你的代码自动文档化。 每个变量名和方法名都应该说明它在做什么。如果代码编写正确(这方面需要大量实践),则不需要任何代码注释(与文档注释不同)。算法可能很复杂,但代码应该总是简单的。

2/有时候,你需要别人的评论。通常用来描述一种不明显的代码行为或黑客行为。如果您觉得必须写注释,首先尝试重写代码,使其更简单,不需要注释。

缩进

1/不要增加太多缩进。 大多数方法代码应该在方法级别上缩进。嵌套块(if, for等)降低了可读性。如果您有三个嵌套块,您应该尝试将内部块放入一个单独的方法中。四个或更多嵌套的块永远不应该使用。 如果大部分方法代码都在If中,则对If条件求反,例如:


if (self) {
   //... long initialization code ...
}

return self;


if (!self) {
   return nil;
}

//... long initialization code ...

return self;

了解C代码,主要是C结构

注意Obj-C只是C语言之上的一个轻量级OOP层。你应该了解C语言的基本代码结构(枚举、结构体、数组、指针等)是如何工作的。 例子:


view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height + 20);

等于:


CGRect frame = view.frame;
frame.size.height += 20;
view.frame = frame;

还有更多

维护自己的编码标准文档,并经常更新它。试着从错误中学习。理解错误产生的原因,并尝试使用编码标准来避免它。

我们的编码标准目前大约有20页,混合了Java编码标准,谷歌Obj-C/ c++标准和我们自己的添加。记录你的代码,在正确的地方使用标准的缩进,空格和空行等等。

这是一个微妙但很方便的方法。如果你将自己作为委托传递给另一个对象,在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;
#import "MyClass.h"

@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end

@implementation MyClass

其中一些已经被提到过,但以下是我能想到的:

Follow KVO naming rules. Even if you don't use KVO now, in my experience often times it's still beneficial in the future. And if you are using KVO or bindings, you need to know things are going work the way they are supposed to. This covers not just accessor methods and instance variables, but to-many relationships, validation, auto-notifying dependent keys, and so on. Put private methods in a category. Not just the interface, but the implementation as well. It's good to have some distance conceptually between private and non-private methods. I include everything in my .m file. Put background thread methods in a category. Same as above. I've found it's good to keep a clear conceptual barrier when you're thinking about what's on the main thread and what's not. Use #pragma mark [section]. Usually I group by my own methods, each subclass's overrides, and any information or formal protocols. This makes it a lot easier to jump to exactly what I'm looking for. On the same topic, group similar methods (like a table view's delegate methods) together, don't just stick them anywhere. Prefix private methods & ivars with _. I like the way it looks, and I'm less likely to use an ivar when I mean a property by accident. Don't use mutator methods / properties in init & dealloc. I've never had anything bad happen because of it, but I can see the logic if you change the method to do something that depends on the state of your object. Put IBOutlets in properties. I actually just read this one here, but I'm going to start doing it. Regardless of any memory benefits, it seems better stylistically (at least to me). Avoid writing code you don't absolutely need. This really covers a lot of things, like making ivars when a #define will do, or caching an array instead of sorting it each time the data is needed. There's a lot I could say about this, but the bottom line is don't write code until you need it, or the profiler tells you to. It makes things a lot easier to maintain in the long run. Finish what you start. Having a lot of half-finished, buggy code is the fastest way to kill a project dead. If you need a stub method that's fine, just indicate it by putting NSLog( @"stub" ) inside, or however you want to keep track of things.

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

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

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

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

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

    NSLog(@"%@", aString);