我知道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)

其他回答

还有一个半相关的话题(还有更多的回复空间!):

有哪些Xcode的小技巧和技巧是你希望2年前就知道的?

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

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

2)说到私有的东西,我更喜欢把私有方法定义放在.m文件的类扩展名中,就像这样:

#import "MyClass.h"

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

@implementation MyClass

为什么要用外人不应该关心的东西把.h文件弄得乱七八糟呢?empty()适用于.m文件中的私有类别,如果您没有实现声明的方法,则会发出编译警告。

3)我已经开始把dealloc放在。m文件的顶部,就在@synthesize指令的下面。你在课堂上想要思考的事情不应该排在最前面吗?在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实际上可能是double类型时,这是非常重要的,你不需要混合模式数学,因为你在存储上失去了'val'的精度。虽然iphone的硬件支持浮点数,但与单精度相比,执行双精度算术可能仍需要更多时间。引用:

iPhone上的Double vs float iPhone/iPad双精度数学

在老式手机上,计算的速度应该是相同的,但你可以在寄存器中使用更多的单精度组件,所以对于许多计算来说,单精度最终会更快。

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

6) SQLite can be a very, very fast way to cache large data sets. A map application for instance can cache its tiles into SQLite files. The most expensive part is disk I/O. Avoid many small writes by sending BEGIN; and COMMIT; between large blocks. We use a 2 second timer for instance that resets on each new submit. When it expires, we send COMMIT; , which causes all your writes to go in one large chunk. SQLite stores transaction data to disk and doing this Begin/End wrapping avoids creation of many transaction files, grouping all of the transactions into one file.

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

更多的SQLite优化技巧在这里,虽然文档看起来过时了,但许多要点可能仍然是好的;

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

变量和属性

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++标准和我们自己的添加。记录你的代码,在正确的地方使用标准的缩进,空格和空行等等。

#import "MyClass.h"

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

@implementation MyClass

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

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

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