我知道的 (这是很方便!), 但是,编程的做法时使用的写作目标,更具体地说当使用的可可(或CocoaTouch).

有帮助吗?

解决方案

有几件事情我已经开始这样做,我不认为是标准:

1)随着特性,我不再使用"_"为前缀"私人"类别的变量。毕竟,如果一个变量可以通过其他类不应该有一个酒店的呢?我总是不喜欢"_"前缀为使码丑陋的,现在我可以留下它。

2)发言的私人的事情,我喜欢的地方私人的方法的定义内。m文件在类扩展,像这样:

#import "MyClass.h"

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

@implementation MyClass

为什么凌乱的.h文件事情外人应该不关心?Empty()作为私人的类别。m文件,并问题编制的警告,如果不实现的方法宣布。

3)我已经把dealloc的顶部.m文件,只是下面的@综合的指令。不什么你dealloc是在该列表的东西,你要想想在一个类?这是尤其如此,在环境样本。

3.5)中表的细胞,可使每一个元素(包括细胞本身)的不透明性能。这意味着设置适当的背景色中的一切。

3.6)当使用NSURLConnection,作为一项规则你可能想要实施的代理方法:

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
      return nil;
}

我发现大多数网络通话是非常奇异和它的更多的异常比规则你会想要的答复缓存,特别是对于网络的服务电话。实现的方法,如禁用缓存的反应。

还感兴趣,是一些良好的iPhone具体的提示从约瑟夫*Mattiello(在收到的iPhone的邮件列表)。还有更多,但这些是最常有用我以为(注意,几位现在已经略有编辑的原始包含的细节提供的答复):

4)只使用双精确度如果有必要,例如工作时与CoreLocation.确保你结束你的常量'f'使海湾合作委员会的商店它们作为浮动。

float val = someFloat * 2.2f;

这主要是重要的时候 someFloat 实际上可能是一个双人,你不需要混合模式的数学,由于你失去了精密的'val上储存。虽然浮点数是硬件支持在iphone,它可能仍然需要更多的时间来做的双精算术而不是单的精确度。参考文献:

在旧手机的所谓的计算工作在相同的速度但是你可以拥有多个单一的精密部件在注册于一倍,因此对于许多计算单精度将最终正在得更快。

5)设置你的性质为 nonatomic.他们 atomic 默认情况下和在合成信号的代码将创建,以防止多线程的问题。99%的可能你不需要担心这个和代码是多少臃肿的和更多的存储器的有效的当设定为非原子.

6)源码可以是一个非常,非常快速的方式来缓存的大数据集。地图应用程序的实例可以缓其砖到源码文件。最昂贵的部分是盘I/O.避免许多小写通过发送 BEGIN;COMMIT; 之间的大块。我们使用了2秒计时器,例如重置上的每一个新的提交。到期时,我们发送提交;,这引起所有你写进去一大块。源码存储交易数据的磁盘,这样做开始/端的包装可以避免创造的许多交易文件、分组的所有交易成一个文件。

此外,SQL会阻止你的闺如果这是你的主线。如果你有一个很长的查询,这是一个好主意,要储存你的查询作为静态目的,和运行SQL在一个单独的螺纹。确保包裹的任何修改的数据库查询的字符串 @synchronize() {} 块。对短暂的查询只是离开的事情,在主要线更容易提供便利。

更源码优化技巧在这里,虽然文献显示出日期的许多要点可能仍然良好;

http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html

其他提示

不要将未知字符串用作格式字符串

当方法或函数采用格式字符串参数时,应确保您可以控制格式字符串的内容。

例如,在记录字符串时,很有可能将字符串变量作为唯一参数传递给 NSLog

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

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

    NSLog(@"%@", aString);

使用标准的可可命名和格式的公约和术语,而不是任何你们用来从另一个环境。还有 大量的可可开发商那里,当一个又一个的他们开始工作时与你的代码,就会更加平易近人的如果它的外观和感觉类似于其他可可代码。

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

  • 不要宣布 id m_something; 在对象的接口和调用这一个 成员可变;使用 something_something 对于其名称,并呼吁它的一个 例变量.
  • 不名的吸气 -getSomething;适当的可可粉仅仅是名字 -something.
  • 不一定器 -something:;它应该是 -setSomething:
  • 该法的名称是穿插的参数,包括冒号;它的 -[NSObject performSelector:withObject:], ,不 NSObject::performSelector.
  • 使用中间上限(驼峰式)在方法的名称、参数、变量、分类名称,等等。而不是下(强调).
  • 类名称开始与上层的情况下信、变量和方法的名字较低的情况。

任何你做的, 不不 使用Win16/Win32风格的匈牙利表示法。即使微软放弃了与移动。网平台。

IBOutlets

从历史上看,网点的内存管理一直很差。 目前的最佳做法是将出口声明为财产:

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

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

使用LLVM / Clang静态分析器

注意:在Xcode 4下,它现在内置于IDE中。

您使用 Clang Static Analyzer - 毫不奇怪 - 分析您的C和目标在Mac OS X 10.5上的-C代码(还没有C ++)。安装和使用它是微不足道的:

  1. 此页下载最新版本。
  2. 从命令行, cd 到您的项目目录。
  3. 执行 scan-build -k -V xcodebuild
  4. (还有一些额外的约束等,特别是你应该在其“Debug”配置中分析一个项目 - 参见 http://clang.llvm.org/StaticAnalysisUsage.html 了解详情 - 但这或多或少都归结为它。)

    然后,分析器会为您生成一组网页,显示可能的内存管理以及编译器无法检测到的其他基本问题。

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

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

通过这样做,您可以确保不再发送任何委托方法。当你要 dealloc 并消失在以太中时,你要确保没有任何东西可以偶然发送给你更多的消息。记住self.someObject可以被另一个对象保留(它可以是单个或自动释放池或其他任何对象),直到你告诉它“停止向我发送消息!”,它认为你的即将成为 - 解除对象是公平的游戏。

养成这种习惯可以避免许多奇怪的崩溃,这些崩溃很难调试。

同样的原则也适用于Key Value Observation和NSNotifications。

编辑:

更具防御性,改变:

self.someObject.delegate = NULL;

成:

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

@kendell

而不是:

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

使用:

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

Objective-C 2.0中的新功能。

类扩展在Apple的Objective-C 2.0 Reference中描述。

“类扩展允许您在主类@interface块以外的位置为类声明其他必需的API”

所以他们是实际课程的一部分 - 而不是课堂上的(私人)课程。微妙但重要的区别。

避免自动释放

由于您通常(1)无法直接控制其生命周期,因此自动释放的对象可能会持续相当长的时间并不必要地增加应用程序的内存占用量。虽然在桌面上这可能没什么影响,但在更受限制的平台上,这可能是一个重要问题。因此,在所有平台上,特别是在更受约束的平台上,最好的做法是避免使用会导致自动释放对象的方法,而是鼓励您使用alloc / init模式。

因此,而不是:

aVariable = [AClass convenienceMethod];

如果能够,你应该使用:

aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];

当您编写自己的返回新创建对象的方法时,您可以利用 Cocoa的命名约定通过在方法名称前添加”new“来向接收者标记必须释放它。

因此,而不是:

- (MyClass *)convenienceMethod {
    MyClass *instance = [[[self alloc] init] autorelease];
    // configure instance
    return instance;
}
你可以写:

- (MyClass *)newInstance {
    MyClass *instance = [[self alloc] init];
    // configure instance
    return instance;
}

由于方法名称以“new”开头,因此API的使用者知道他们负责释放收到的对象(例如,参见 NSObjectController的 newObject 方法 )。

(1)您可以使用自己的本地自动释放池来控制。有关详细信息,请参阅自动释放池

这些已经提到,但这是我能想到的我的头顶:

  • 按照韩国国际志愿者组织命名的规则。 甚至如果你不使用韩国国际志愿者组织现在,在我的经验很多时候,它仍然是有益的未来。如果您使用的是韩国国际志愿者组织或绑,你需要知道事情会工作的方式,他们应该。这涵盖了不仅仅是存取方法和实例的变量,但对多关系、验证、自动通知依赖的钥匙,等等。
  • 把私人方法中的一个类别。 不仅仅是接口,但是执行情况。这是很好的有一些距离的概念之间的私营和非私人的方法。包括我的一切都在我的。m文件。
  • 把背景线方法中的一个类别。 上述相同。我发现这是很好的保持一个清晰的概念阻挡的时候你在想什么是对的主要线和什么不是。
  • 使用 #pragma mark [section]. 通常我团通过我自己的方法,每个子类的复盖,以及任何信息或正式协议。这使得它很容易跳到底什么我要找的。在同一主题小组类似的方法(如表景的委托方法)结合在一起,不要只是坚持他们的任何地方。
  • 前缀私营方法和实例变量与_. 我喜欢它的样子,和我不可能使用一个伊娃的时候我指的是财产的事故。
  • 不要使用增变方法/属性在init&dealloc. 我从来没有过任何坏事发生因为它,但我可以看到的逻辑,如果你改变的方法来做的事情取决于国家的对象。
  • 把IBOutlets在性质。 实际上我刚刚读这个,但我要开始这样做。无论任何记忆好处,但它似乎更好的风格(至少对我)。
  • 避免编写代码,你并不绝对需要。 这真涵盖了很多的事情,就像当一个实例变量 #define 将这样做,或缓存阵列,而不是排它的每一个时间的数据是必要的。有很多我可以说,关于这一点,但底线是不要写代码,直到你需要它,或探查会告诉你。这使事情很容易保持长期运行。
  • 完成什么你开始。 有很多的半成品,越野车码是最快的方式杀死一个项目死亡。如果你需要一根的方法,很好,只是表示它通过把 NSLog( @"stub" ) 在内部,或是你想到跟踪的事情。

编写单元测试。您可以在Cocoa中测试很多的东西,这些东西在其他框架中可能更难。例如,使用UI代码,您通常可以验证事物是否应该连接,并相信它们在使用时会起作用。你可以设置状态和轻松调用委托方法来测试它们。

您也没有公开与受保护与隐私方法的关联,从而妨碍为您的内部编写测试。

黄金法则:如果您 alloc ,那么 release

更新:除非您使用ARC

不要将Objective-C写成Java / C#/ C ++ /等。

我曾经看到一个用来编写Java EE Web应用程序的团队尝试编写一个Cocoa桌面应用程序。好像它是一个Java EE Web应用程序。有很多AbstractFooFactory和FooFactory以及IFoo和Foo飞来飞去时他们真正需要的只是一个Foo类,可能还有一个Fooable协议。

确保您不这样做的一部分是真正理解语言的差异。例如,您不需要上面的抽象工厂和工厂类,因为Objective-C类方法与实例方法一样动态调度,并且可以在子类中重写。

确保为调试魔术页面添加书签。当你试图找到可可虫的来源时,这应该是你头撞墙的第一站。

例如,它会告诉您如何找到首次分配内存的方法,以后会导致崩溃(例如在应用程序终止期间)。

按用户需要对字符串进行排序

对字符串进行排序以呈现给用户时,不应使用简单的 compare:方法。相反,您应该始终使用本地化比较方法,例如 localizedCompare: localizedCaseInsensitiveCompare:

有关详细信息,请参阅搜索,比较和排序串的。

尽量避免我现在决定称之为Newbiecategoryaholism。当Objective-C的新手发现类别时,他们经常会疯狂,为现有的每个类添加有用的小类别(“什么?我可以添加一个方法将数字转换成罗马数字到NSNumber摇滚!” )。

不要这样做。

您的代码将更易于理解,并且可以通过在二十几个基础课程中使用的几十个小类别方法来理解。

大多数情况下,当你真的认为需要一种类别方法来帮助简化某些代码时,你会发现你永远不会重复使用这种方法。

还有其他的危险,除非你的命名空间是你的类别方法(除了完全疯狂的ddribin之外的人是谁?),你的地址空间中运行的Apple,插件或其他东西也有可能定义具有相同名称且具有略微不同副作用的相同类别方法....

行。既然您已被警告,请忽略“不要做这个部分”。但要保持极度克制。

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

例如,在Java中,您经常使用匿名 * Listener 子类的实例,而在.NET中,您经常使用 EventArgs 子类。在Cocoa,你不会做任何一次—而是使用目标动作。

声明的属性

您通常应该为所有属性使用Objective-C 2.0声明的属性功能。如果它们不公开,请将它们添加到类扩展中。使用声明的属性可以立即清除内存管理语义,并使您更容易检查dealloc方法 - 如果将属性声明组合在一起,则可以快速扫描它们并与dealloc方法的实现进行比较。

在不将属性标记为“非原子”之前,您应该认真思考。正如 Objective C Programming Language Guide 中所述,属性是默认情况下为原子,并产生相当大的开销。而且,简单地使所有属性成为原子并不会使您的应用程序成为线程安全的。当然,还要注意,如果你没有指定'nonatomic'并实现你自己的访问器方法(而不是合成它们),你必须以原子方式实现它们。

考虑零值

此问题注意到, nil 的消息在Objective-C中有效。虽然这通常是一个优势 - 导致更清晰,更自然的代码 - 如果你没有获得 nil 值,该功能偶尔会导致特殊且难以追踪的错误期待它。

使用NSAssert和朋友。 我一直使用nil作为有效对象...尤其是将消息发送到nil在Obj-C中完全有效。 但是,如果我真的想确定变量的状态,我会使用NSAssert和NSParameterAssert,这有助于轻松追踪问题。

简单但经常被遗忘的人。根据规范:

  

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

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

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

如果您使用的是Leopard(Mac OS X 10.5)或更高版本,则可以使用Instruments应用程序查找和跟踪内存泄漏。在Xcode中构建程序后,选择Run>从Performance Tool开始>泄漏。

即使您的应用程序没有显示任何泄漏,您可能会将对象保留太长时间。在Instruments中,您可以使用ObjectAlloc仪器。在Instruments文档中选择ObjectAlloc仪器,然后选择View>调出仪器的详细信息(如果尚未显示)。细节(旁边应该有一个复选标记)。在“分配寿命”下在ObjectAlloc详细信息中,请确保选择“Created& amp;”旁边的单选按钮。仍然活着“。

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

以dealloc清理。

这是最容易忘记的事情之一 - 尤其是当编码为150英里每小时。始终,始终始终在dealloc中清理属性/成员变量。

我喜欢使用Objc 2属性 - 新的点符号 - 所以这使得清理无痛。通常很简单:

- (void)dealloc
{
    self.someAttribute = NULL;
    [super dealloc];
}

这将照顾你的释放并将属性设置为NULL(我考虑防御性编程 - 如果dealloc中的另一个方法再次访问成员变量 - 很少但可能发生)。

在10.5中打开GC时,不再需要这么多 - 但您可能仍需要清理您创建的其他资源,而是可以在finalize方法中执行此操作。

所有这些评论都很棒,但我真的很惊讶没人提到 Google的一段时间后发布的Objective-C风格指南。我认为他们做得非常彻底。

此外,半相关主题(有更多回复的空间!):

那些小Xcode技巧和提示是什么?你希望你在2年前知道的技巧吗?

不要忘记NSWindowController和NSViewController将释放他们管理的NIB文件的顶级对象。

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

初学者使用的一个相当明显的一个:利用Xcode的自动缩进功能为您的代码。即使您从其他来源复制/粘贴,一旦粘贴了代码,您可以选择整个代码块,右键单击它,然后选择重新缩进该块中的所有内容的选项。

Xcode实际上会解析该部分,并根据括号,循环等缩进它。它比点击每一行的空格键或制表键要高效得多。

我知道在第一次进入Cocoa编程时我忽略了这一点。

确保您了解有关NIB文件的内存管理职责。您负责释放加载的任何NIB文件中的顶级对象。阅读关于此主题的Apple文档

打开所有GCC警告,然后关闭经常由Apple标头引起的警告,以减少噪音。

经常运行Clang静态分析;您可以通过“运行静态分析器”为所有版本启用它。建立设置。

编写单元测试并在每次构建时运行它们。

变量和属性

1 /保持标题清洁,隐藏实现
不要在标题中包含实例变量。私有变量作为属性放入类继续。公共变量在标头中声明为公共属性。 如果只应读取它,则将其声明为readonly并在类连续中将其覆盖为readwrite。 基本上我根本不使用变量,只使用属性。

2 /为您的属性提供非默认变量名称,例如:


@synthesize property = property_;

原因1:您将捕获因遗忘“自我”而导致的错误。在分配财产时。 原因2:根据我的实验,仪器中的泄漏分析仪在检测泄漏属性方面存在问题。

3 /切勿直接在属性上使用保留或释放(或仅在特殊情况下使用)。在你的dealloc中只给他们一个零。保留属性意味着自己处理保留/释放。你永远不知道setter是不是,例如,添加或删除观察者。您应该仅在其setter和getter中直接使用该变量。

<强>视图

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

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

3 / IBOutlets不必总是保留(或强)。请注意,大多数IBOutlet都是视图层次结构的一部分,因此会隐式保留。

4 /在viewDidUnload中释放所有IBOutlets

5 /从dealloc方法调用viewDidUnload。它没有被隐含地称为。

<强>内存

1 /创建对象时自动释放对象。将释放调用移动到一个if-else分支或返回语句之后会导致许多错误。仅在特殊情况下才应使用释放而不是自动释放 - 例如当你在等待一个runloop并且你不希望你的对象过早自动释放时。

2 /即使您使用的是Authomatic Reference Counting,也必须完全理解retain-release方法的工作原理。手动使用retain-release并不比ARC复杂,在这两种情况下你都需要关于泄漏和保留周期的事情。 考虑在大项目或复杂的对象层次结构上手动使用retain-release。

<强>评论

1 /使您的代码自动记录。 每个变量名称和方法名称都应该告诉它正在做什么。如果代码编写正确(您需要进行大量练习),则不需要任何代码注释(与文档注释不同)。算法可能很复杂,但代码应该总是很简单。

2 /有时候,你需要发表评论。通常用于描述非明显的代码行为或hack。如果您认为必须撰写评论,请首先尝试将代码重写为更简单且无需注释。

<强>压痕

1 /不要过多增加压痕。 大多数方法代码都应该在方法级别缩进。嵌套块(如果,等等)会降低可读性。如果您有三个嵌套块,则应尝试将内部块放入单独的方法中。应该永远不要使用四个或更多嵌套块。 如果您的大多数方法代码都在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中的基本代码结构(枚举,结构,数组,指针等)。 例:

更强功能

Objective-C是面向对象的语言,但Cocoa框架功能风格意识,并且在很多情况下都是设计的功能风格。

  1. 存在可变性的分离。使用不可变类作为主要类,将可变对象用作辅助类。例如,主要使用NSArray,并仅在需要时使用NSMutableArray。

  2. 有纯粹的功能。没有那么多,购买许多框架API的设计就像纯函数一样。查看 CGRectMake() CGAffineTransformMake()等函数。显然指针形式看起来更有效。然而,使用指针的间接参数不能提供无副作用。尽可能地设计结构。 甚至分离状态对象。将值传递给其他对象时,请使用 -copy 而不是 -retain 。因为共享状态可以默默地影响其他对象中的值突变。所以不能无副作用。如果您有来自object的外部值,请复制它。因此,尽可能减少设计共享状态也很重要。

  3. 但是也不要害怕使用不纯的功能。

    1. 有懒惰的评价。请参阅 - [UIViewController view] 属性。创建对象时不会创建视图。它将在调用者第一次读取 view 属性时创建。在实际绘制之前, UIImage 不会被加载。这种设计有很多实现方式。这种设计对资源管理非常有帮助,但如果你不了解懒惰评估的概念,就不容易理解它们的行为。

    2. 有封闭。尽可能使用C块。这将大大简化您的生活。但在使用之前,请再次阅读有关块内存管理的内容。

    3. 有半自动GC。 NSAutoreleasePool。使用 -autorelease primary。在您真正需要时,请使用手动 -retain / -release secondary。 (例如:内存优化,显式资源删除)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top