346

我知道HIG(非常方便!),但是在编写 Objective-C 时,尤其是在使用 Cocoa(或 CocoaTouch)时,您使用了哪些编程实践。

4

33 回答 33

398

我已经开始做一些我认为不是标准的事情:

1)随着属性的出现,我不再使用“_”作为“私有”类变量的前缀。毕竟,如果一个变量可以被其他类访问,不应该有一个属性吗?我一直不喜欢“_”前缀让代码更难看,现在我可以省略它了。

2)说到私有的东西,我更喜欢将私有方法定义放在 .m 文件中的类扩展中,如下所示:

#import "MyClass.h"

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

@implementation MyClass

为什么要在 .h 文件中塞满外人不应该关心的东西?空 () 适用于 .m 文件中的私有类别,如果您不实现声明的方法,则会发出编译警告。

3) 我已将 dealloc 放在 .m 文件的顶部,就在 @synthesize 指令的下方。你dealloc不应该在你想在课堂上考虑的事情列表的顶部吗?在 iPhone 这样的环境中尤其如此。

3.5)在表格单元格中,使每个元素(包括单元格本身)不透明以提高性能。这意味着在所有内容中设置适当的背景颜色。

3.6) 当使用 NSURLConnection 时,通常你可能想要实现委托方法:

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

我发现大多数 Web 调用都是非常单一的,它比您希望缓存响应的规则更例外,尤其是对于 Web 服务调用。实现所示方法会禁用响应缓存。

同样有趣的是,约瑟夫·马蒂洛 (Joseph Mattiello) 提供了一些针对 iPhone 的优秀技巧(在 iPhone 邮件列表中收到)。还有更多,但这些是我认为最普遍有用的(请注意,现在对原始版本进行了一些轻微编辑,以包含回复中提供的详细信息):

4) 仅在必要时使用双精度,例如在使用 CoreLocation 时。确保以“f”结束常量,以使 gcc 将它们存储为浮点数。

float val = someFloat * 2.2f;

当实际上可能是双精度时,这一点最重要someFloat,您不需要混合模式数学,因为您在存储的“val”中失去了精度。虽然 iPhone 的硬件支持浮点数,但与单精度相比,执行双精度算术可能仍需要更多时间。参考:

在较旧的手机上,据说计算以相同的速度运行,但您可以在寄存器中拥有比双精度更多的单精度组件,因此对于许多计算而言,单精度最终会更快。

5)将您的属性设置为nonatomic。它们是atomic默认的,在综合时,将创建信号量代码以防止多线程问题。99% 的人可能不需要担心这一点,并且当设置为非原子时,代码不会那么臃肿并且内存效率更高。

6) SQLite 可以是一种非常、非常快速的缓存大型数据集的方法。例如,地图应用程序可以将其切片缓存到 SQLite 文件中。最昂贵的部分是磁盘 I/O。通过在大块之间发送BEGIN;和避免许多小写。COMMIT;例如,我们使用 2 秒计时器,在每次新提交时重置。当它过期时,我们发送 COMMIT;,这会导致您的所有写入都集中在一大块中。SQLite 将事务数据存储到磁盘并执行此开始/结束包装避免创建许多事务文件,将所有事务分组到一个文件中。

此外,如果 SQL 在您的主线程上,它将阻止您的 GUI。如果您有一个很长的查询,最好将您的查询存储为静态对象,并在单独的线程上运行您的 SQL。确保将任何修改数据库的查询字符串包装在@synchronize() {}块中。对于简短的查询,只需将内容留在主线程上即可更方便。

更多 SQLite 优化技巧在这里,虽然文档看起来已经过时了,但许多点可能还是不错的;

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

于 2008-10-01T03:17:10.090 回答
109

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

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

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

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

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

    NSLog(@"%@", aString);
于 2008-10-06T16:46:23.707 回答
107

使用标准的 Cocoa 命名和格式化约定和术语,而不是您在其他环境中习惯的任何东西。那里很多 Cocoa 开发人员,当他们中的另一个人开始使用您的代码时,如果它的外观和感觉与其他 Cocoa 代码相似,将会更加平易近人。

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

  • 不要id m_something;在对象的接口中声明并称其为成员变量字段;使用somethingor_something作为它的名字并将其称为实例变量
  • 不要命名吸气剂-getSomething;正确的 Cocoa 名称是 just -something
  • 不要命名 setter -something:;它应该是-setSomething:
  • 方法名称散布在参数中并包含冒号;是-[NSObject performSelector:withObject:],不是NSObject::performSelector
  • 在方法名、参数、变量、类名等中使用大写字母(CamelCase)而不是下划线(下划线)。
  • 类名以大写字母开头,变量名和方法名以小写字母开头。

无论您做什么,都不要使用 Win16/Win32 风格的匈牙利符号。甚至微软也放弃了这一点,转向了 .NET 平台。

于 2008-10-01T15:47:25.137 回答
106

IB奥特莱斯

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

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

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

于 2008-10-03T15:43:40.280 回答
97

使用 LLVM/Clang 静态分析器

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

您使用Clang 静态分析器- 不出所料 - 在 Mac OS X 10.5 上分析您的 C 和 Objective-C 代码(还没有 C++)。安装和使用很简单:

  1. 从此页面下载最新版本。
  2. 从命令行,cd到您的项目目录。
  3. 执行scan-build -k -V xcodebuild

(还有一些额外的限制等,特别是您应该在其“调试”配置中分析一个项目——有关详细信息,请参阅http://clang.llvm.org/StaticAnalysisUsage.html ——但这或多或少它归结为什么。)

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

于 2008-10-04T05:15:29.970 回答
94

这是一种微妙但方便的方法。如果您将自己作为委托传递给另一个对象,请在您之前重置该对象的委托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;
于 2008-10-01T04:59:44.367 回答
86

@肯德尔

代替:

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

采用:

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

Objective-C 2.0 中的新功能。

Apple 的 Objective-C 2.0 参考中描述了类扩展。

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

所以他们是实际班级的一部分——而不是除了班级之外的(私人)类别。微妙但重要的区别。

于 2008-10-01T03:53:27.943 回答
75

避免自动释放

由于您通常 (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) 您可以使用自己的本地自动释放池进行控制。有关这方面的更多信息,请参阅自动释放池

于 2008-10-06T19:45:30.413 回答
69

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

  • 遵循 KVO 命名规则。即使您现在不使用 KVO,根据我的经验,它在未来仍然很有用。如果你使用 KVO 或绑定,你需要知道事情正在按照他们应该的方式工作。这不仅包括访问器方法和实例变量,还包括对多关系、验证、自动通知相关键等。
  • 将私有方法放在一个类别中。不仅是接口,还有实现。在私有方法和非私有方法之间有一些概念上的距离是很好的。我将所有内容都包含在我的 .m 文件中。
  • 将后台线程方法放在一个类别中。和上面一样。我发现当你在思考主线程上有什么和没有什么时,保持一个清晰的概念障碍是很好的。
  • 使用#pragma mark [section]. 通常我按我自己的方法、每个子类的覆盖以及任何信息或正式协议进行分组。这使得跳转到我正在寻找的内容变得更加容易。在同一个主题上,将相似的方法(如表格视图的委托方法)组合在一起,不要只是将它们粘在任何地方。
  • 使用 _ 前缀私有方法和 ivars。我喜欢它的外观,当我指的是意外财产时,我不太可能使用 ivar。
  • 不要在 init 和 dealloc 中使用 mutator 方法/属性。我从来没有因为它发生过任何不好的事情,但是如果您更改方法以执行取决于对象状态的操作,我可以看到逻辑。
  • 将 IBOutlets 放在属性中。我实际上只是在这里读到这个,但我要开始做。不管有什么记忆好处,它在风格上似乎更好(至少对我来说)。
  • 避免编写您并非绝对需要的代码。这确实涵盖了很多事情,比如在需要时制作 ivars #define,或者缓存一个数组而不是在每次需要数据时对其进行排序。关于这一点我可以说很多,但底线是在你需要它之​​前不要编写代码,或者探查器告诉你。从长远来看,它使事情更容易维护。
  • 完成你开始的事情。拥有大量半成品、有缺陷的代码是杀死项目的最快方法。如果您需要一个很好的存根方法,只需通过放入NSLog( @"stub" )内部来指示它,或者您想要跟踪事物。
于 2008-11-17T23:11:06.440 回答
56

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

您也没有公共、受保护和私有方法的可见性妨碍为您的内部编写测试。

于 2008-10-01T08:04:58.073 回答
55

黄金法则:如果你alloc就是你release

更新:除非您使用 ARC

于 2008-10-01T02:16:48.207 回答
54

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

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

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

于 2008-10-01T15:40:11.363 回答
50

确保将Debugging Magic页面添加为书签。这应该是您在试图找到 Cocoa 虫源时将头撞到墙上的第一站。

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

于 2008-10-01T16:35:03.790 回答
38

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

不要这样做。

无需在两打基础类之上散布几十个小类别方法,您的代码将更可移植且更易于理解。

大多数时候,当您真的认为需要一个类别方法来帮助简化某些代码时,您会发现您永远不会重用该方法。

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

好的。既然您已被警告过,请忽略“不要做这部分”。但要极端克制。

于 2008-10-01T05:16:50.597 回答
37

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

例如,在 Java 中,您经常使用匿名*Listener子类的实例,而在 .NET 中,您经常使用您的EventArgs子类。在 Cocoa 中,你也不会这样做——而是使用 target-action。

于 2008-10-01T08:10:26.327 回答
37

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

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

有关更多详细信息,请参阅搜索、比较和排序字符串

于 2008-10-06T16:49:19.083 回答
31

声明的属性

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

在不将属性标记为“非原子”之前,您应该三思而后行。正如《Objective C 编程语言指南》所指出的,属性默认是原子的,并且会产生相当大的开销。此外,简单地使您的所有属性原子化并不能使您的应用程序线程安全。当然,还要注意,如果您不指定“非原子”并实现自己的访问器方法(而不是综合它们),则必须以原子方式实现它们。

于 2008-10-03T15:51:39.997 回答
26

考虑 nil 值

正如这个问题所指出的,消息nil在 Objective-C 中是有效的。nil虽然这通常是一个优势——导致代码更简洁、更自然——但如果你在没有预料到的时候 得到了一个值,这个特性偶尔会导致特殊的和难以追踪的错误。

于 2008-10-12T20:14:24.740 回答
26

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

于 2009-05-07T20:57:48.947 回答
23

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

通常,具有相同选择器(相同名称)的不同类中的方法也必须共享相同的返回和参数类型。此约束由编译器强加以允许动态绑定。

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

@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;
}   
于 2010-08-27T10:17:32.057 回答
22

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

即使您的应用程序没有显示任何泄漏,您也可能将对象保留的时间过长。在 Instruments 中,您可以为此使用 ObjectAlloc 工具。在 Instruments 文档中选择 ObjectAlloc 工具,然后通过选择 View > Detail(它旁边应该有一个复选标记)调出工具的详细信息(如果它尚未显示)。在 ObjectAlloc 详细信息中的“分配生命周期”下,确保选择“已创建且仍然存在”旁边的单选按钮。

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

于 2008-10-01T16:57:52.737 回答
21

在 dealloc 中清理。

这是最容易忘记的事情之一——尤其是。以 150 英里/小时的速度进行编码时。总是,总是,总是在 dealloc 中清理你的属性/成员变量。

我喜欢使用 Objc 2 属性——使用新的点符号——所以这使得清理工作变得轻松。通常很简单:

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

这将为您处理发布并将属性设置为 NULL(我认为这是防御性编程 - 以防在 dealloc 中进一步向下的另一种方法再次访问成员变量 - 很少见但可能发生)。

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

于 2008-10-01T04:54:13.757 回答
17

所有这些评论都很棒,但我真的很惊讶没有人提到不久前发布的Google 的 Objective-C 样式指南。我认为他们已经完成了非常彻底的工作。

于 2008-12-16T19:27:06.570 回答
15

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

您希望在 2 年前了解的那些 Xcode 小技巧和窍门是什么?.

于 2008-10-01T05:31:02.607 回答
13

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

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

于 2008-10-01T17:02:07.110 回答
12

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

Xcode 实际上会解析该部分并根据括号、循环等对其进行缩进。这比在每一行都按空格键或制表键要有效得多。

于 2010-07-12T19:09:57.860 回答
10

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

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

于 2008-10-01T16:19:14.217 回答
10

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

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

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

于 2009-10-18T18:12:12.827 回答
10

变量和属性

1/ 保持标题干净,隐藏实现
不要在标题中包含实例变量。私有变量作为属性放入类延续中。公共变量在您的标头中声明为公共属性。如果它应该是只读的,则将其声明为只读并在类延续中将其覆盖为读写。基本上我根本不使用变量,只使用属性。

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


@synthesize property = property_;

原因1:你会发现忘记“自我”导致的错误。分配财产时。原因 2:根据我的实验,Instruments 中的 Leak Analyzer 在使用默认名称检测泄漏属性时存在问题。

3/ 永远不要直接在属性上使用保留或释放(或仅在非常特殊的情况下)。在您的 dealloc 中,只需为它们分配零。保留属性旨在自行处理保留/释放。例如,您永远不知道 setter 是否不是添加或删除观察者。您应该只在其 setter 和 getter 内直接使用该变量。

意见

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

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

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

4/ 释放 viewDidUnload 中的所有 IBOutlets

5/ 从你的 dealloc 方法调用 viewDidUnload。它没有被隐式调用。

记忆

1/ 创建对象时自动释放对象。许多错误是由于将您的发布调用移动到一个 if-else 分支或在 return 语句之后引起的。仅在特殊情况下才应使用释放而不是自动释放 - 例如,当您等待运行循环并且您不希望过早地自动释放对象时。

2/ 即使您使用的是 Authomatic Reference Counting,您也必须完全理解保留释放方法的工作原理。手动使用保留释放并不比 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 编码标准、Google Obj-C/C++ 标准和我们自己添加的标准。记录您的代码,在正确的位置使用标准缩进、空格和空行等。

于 2011-10-19T02:58:56.530 回答
9

实用

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

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

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

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

  1. 有懒惰的评价。看到类似-[UIViewController view]财产的东西。创建对象时不会创建视图。它会在调用者view第一次读取属性时创建。UIImage在实际绘制之前不会加载。像这种设计有很多实现。这种设计对资源管理很有帮助,但如果不了解惰性求值的概念,就很难理解它们的行为。

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

  3. 有半自动GC。NSAutoreleasePool。使用-autorelease初级。-retain/-release真正需要时使用手动辅助。(例如:内存优化、显式资源删除)

于 2011-03-29T17:51:33.770 回答
8

我看到的 Apple 提供的示例将 App 委托视为全局数据存储,某种数据管理器。那是大错特错。创建一个单例并可能在 App 委托中实例化它,但不要将 App 委托用作应用程序级事件处理之外的任何东西。我衷心赞同这篇博文中的建议。这个线程提示了我。

于 2009-05-20T22:46:02.090 回答
4

仅在dealloc方法中释放一个属性。如果要释放该属性所持有的内存,只需将其设置为 nil:

self.<property> = nil;
于 2011-08-08T03:52:07.480 回答
0
#import "MyClass.h"

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

@implementation MyClass
于 2012-04-25T11:41:31.083 回答