我知道HIG(这非常方便!),但是在编写Objective-C时,更具体地说,在使用Cocoa(或CocoaTouch)时,您使用了什么编程实践?
当前回答
声明属性
对于所有属性,您通常应该使用Objective-C 2.0声明属性特性。如果它们不是公共的,将它们添加到类扩展中。使用声明的属性使内存管理语义立即清晰,并使您更容易检查dealloc方法——如果您将属性声明分组在一起,您可以快速扫描它们并与dealloc方法的实现进行比较。
在不将属性标记为“nonatomic”之前,您应该仔细考虑一下。正如《Objective C编程语言指南》所指出的,属性在默认情况下是原子的,并且会产生相当大的开销。此外,简单地将所有属性都设置为原子化并不能使应用程序具有线程安全性。当然,还要注意,如果你没有指定“nonatomic”,并且实现你自己的访问方法(而不是合成它们),你必须以原子的方式实现它们。
其他回答
避免生成
Since you typically(1) don't have direct control over their lifetime, autoreleased objects can persist for a comparatively long time and unnecessarily increase the memory footprint of your application. Whilst on the desktop this may be of little consequence, on more constrained platforms this can be a significant issue. On all platforms, therefore, and especially on more constrained platforms, it is considered best practice to avoid using methods that would lead to autoreleased objects and instead you are encouraged to use the alloc/init pattern.
因此,而不是:
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方法)。
你可以通过使用你自己的本地自动释放池来控制。有关这方面的更多信息,请参见自动释放池。
编写单元测试。您可以在Cocoa中测试许多在其他框架中可能比较困难的事情。例如,对于UI代码,您通常可以验证事物是否按照应有的方式连接,并相信它们在使用时能够正常工作。你可以很容易地设置状态和调用委托方法来测试它们。
在编写内部测试时,也不会有公共、受保护和私有方法可见性。
对于初学者来说,一个很明显的方法是:利用Xcode的自动缩进功能。即使是从其他源复制/粘贴代码,粘贴完代码后,也可以选择整个代码块,右键单击它,然后选择选项重新缩进该代码块中的所有内容。
Xcode会解析这个section并根据括号,循环等缩进它。这比每一行都按空格键或tab键要有效率得多。
我已经开始做的一些事情,我认为不是标准的:
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
其中一些已经被提到过,但以下是我能想到的:
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.
推荐文章
- 保留HTML字体大小时,iPhone的方向从纵向改变为横向
- iPhone上UIView和UILabels的渐变
- keychain上的分发证书中缺少私钥
- 在实现API时,我如何避免在块中捕获自我?
- 如何创建一个Swift Date对象?
- Xcode 4在目标设备上说“finished running <my app>”——什么都没有发生
- 从另一个应用程序打开设置应用程序
- 快速提取正则表达式匹配
- 如何应用梯度的背景视图的iOS Swift应用程序
- 图书馆吗?静态的?动态吗?或框架?另一个项目中的项目
- 如何用SwiftUI调整图像大小?
- Xcode 6 gitignore文件应该包括什么?
- 如何在iPhone/iOS上删除电话号码的蓝色样式?
- 检测视网膜显示
- 如何在UIImageView中动画图像的变化?