欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Cocoa编程指南

程序员文章站 2022-03-09 20:08:38
...

这是一篇翻译版,英文版来自apple的官方文档:
Coding Guidelines for Cocoa

介绍

Cocoa编程指南介绍

通过公开API开发Cocoa框架,插件,或者其他可执行文件需要一些不同于开发应用程序的方式和约定。开发者是你的产品的主要客户,并且让他们没有对你的编程接口感到困惑是非常重要的。这就是API命名约定派上用场,这会有助于你的接口保持一致和清晰。还有些编程技术对于这个框架来说是比较特殊的或者说更加重要,例如版本控制,二进制兼容性,错误处理和内存管理。本专题包含Cocoa命名规范和推荐的框架编程实践。

文档组织结构

本专题所包含的文章分为两类。第一部分和大部分的模块给出了对编程接口的命名规范。apple在自身的Cocoa框架中也使用这些命名规范。这些关于命名规范的包含如下内容:

1. 代码命名基础
2. 方法的命名
3. 函数的命名
4. 属性和数据类型的命名
5. 可接受的简写和缩写

第二部分(当前只有一个成员)讨论框架开发的各个方面

框架开发的小技巧    

代码命名基础

类,方法,函数,常量和其他编程接口的元素经常在面向对象编程软件设计被忽视。该部分介绍了许多在cocoa接口中实现的命名规范。

基本原则

清晰
- 尽量保持清楚和简洁很好,但是命名清晰比简洁更重要。

Code Commentary
insertObject:atIndex:
insert:at: 不清晰;插入什么?“at”表示什么?atNot clear;what is being inserted?what does “at”signify?
revmoveObjectAtIndext:
removeObject: 好,因为删除作为参数的对象。
remove: 不明确,删除什么?

- 通常,不要缩写名字。即使它们很长也要拼写出来。

代 码 评 价
destinationSelection:
destSel 不清晰
setBackgroundColor:
setBkgColor: 不清晰

你可能认为缩写是众所周知的,但它可能不是,特别是有不同的文化和语言背景开发者遇到你的方法和函数。
- 然而,有少数的缩写确实是通用的并且用了很长时间。可以继续使用,查看Acceptable Abbreviations and Acronyms.
- 避免API命名不明确,例如方法名称可能被解释为多种含义。

代码 评论
sendPort 是发送端口还是返回端口?
displayName 在用户界面中显示一个名字还是返回接受者的标题 ?

一致性
- 尝试保持在Cocoa编程接口上的命名一致性。如果不确定,请查阅现在的头文件或者之前的参看文件。
- 当一个类中的许多方法有多态性的时候,一致性是非常重要的。这些方法在不同的类中使用同样的名称做同样的操作。

代 码 评 论
    (NSInteger)tag
定义在NSView,NSCell,NSControl.
    (void)setStringValue:(NSString *)
在许多Cocoa类中有定义

也可参照:Method Arguments

不要自我引用

  • 命名不应该自我引用
代码 评论
NSString 可以
NSStringObject 自我引用

- 作为掩码的一些常量(可以按位与进行合并),这些常量常量一般不使用这种规则,例如作为通知名称的常量.

代码 评论
NSUnderlineByWordMask 可以
NSTableViewColumnDidMoveNotification 可以

前缀

书写约定

下面有几个简单的命名API的书写规范
- 名字有多个单词组成,不要使用下划线,破折号或者其他符号分割。使用驼峰命名法
对于方法命名,以小写字母开头,后面的单词首字母大写。不要使用前缀。

fileExistsAtPath:isDirectory:
  • 函数和常量的命名,对于相关的类使用同样的前缀并且首字母大写以及后边的单词
NSRunAlertPanel

NSCellDisabled
  • 避免使用下划线作为前缀

类和协议的命名

类的名称应该包含一个清晰的表达出该类的意义。类名应该有一个前缀。Foundation和许多应用程序框架都是一些案例。例如NSString,NSData,NSScanner,NSApplication …和UIButton。

Protocol 应该根据它所组成的一些行为事件来命名。
- 大多数的协议与包含的一些方法有关系而与某种类没有关系。这种协议应该避免与类名混淆。通常约定用一种动名词(“…ing”)的格式.

代 码 评论
NSLocking
NSLock 差(看起来像一个类名)

- 一些协议包含许多没有关系的方法(而不是创建很多分离的小的协议)。这些协议与某个类有关系,这个类是这些协议的主要表现。在这种情况下,应该约定将协议和类命名一致。

NSObject协议就是这种类型的协议。

头文件

方法命名

方法的命名也许是编程接口中最普通的元素,因此应该在命名过程中需要特别注意。这部分讨论方法命名的如下几个方面:

基本规则

通常有如下几项规则:
- 小写字母开头,大写包含的英文单词的首字母。不要使用前缀
- 对于表示操作于某个对象的方法,方法的命名以动词开头:

- (void)invokeWithTarget:(id)target;

- (void)selectTabViewItem:(NSTabViewItem *)tabViewItem;

不要使用“do” 或者 “does” 作为名字的一部分因为这些助动词几乎没有任何意义。并且,不要在动词前面使用副词或者形容词。
- 如果某个方法返回调用者的某个属性,直接在属性后面命名就可以。不要使用“get”,除非需要直接返回一个或者多个值。

代码 评论
    (NSSize)cellSize;
正确
    (NSSize)calcCellSize:
错误
    (NSSize)getCellSize;
错误

- 在参数前面使用关键字

代码 评价
    (void)sendAction:(SEL)aSelector toObject:(id)anObject forAllCells:(BOOL)flag;
正确
    (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;
错误

- 在参数前面描述参数

代码 评价
    (id)viewWithTag:(NSInteger)aTag;
正确
    (id)taggedView:(int)aTag;
错误

- 当创建一个比继承的方法更加明确的方法的时候,需要添加新的关键字在已经存在的方法后面。

代码 评价
    (id)initWithFrame:(CGRect)frameRect;
NSView, UIView.
    (id)initWithFrame:(NSRect)frameRect mode:(int)aMode cellClass:(Class)factoryId numberOfRows:(int)rowsHigh numberOfColumns:(int)colsWide;
NSMatrix, a subclass of NSView

- 不要使用“and”连接是调用者属性的关键字。

代码 评价
    (int)runModalForDirectory:(NSString )path file:(NSString ) name types:(NSArray *)fileTypes;
正确
    (int)runModalForDirectory:(NSString )path andFile:(NSString )name andTypes:(NSArray *)fileTypes;
错误

- 如果方法有两种不同的行为,使用“and”连接它们。

代码 评价
    (BOOL)openFile:(NSString )fullPath withApplication:(NSString )appName andDeactivate:(BOOL)flag;
NSWorkspace

访问器方法

访问器方法是一个设置和读取对象的属性值得方法。根据属性的表达方式拥有某种推荐的方式。
- 一个属性表示一个名词,格式是:

- (type)noun
- (void)setNoun:(type)aNoun;

举例:

- (NSString *)title;

- (void)setTitle:(NSString *)aTitle;
  • 一个属性表示形容词,格式是:
- (BOOL)isAdjective;

- (void)setAdjective:(BOOL)flag;

举例:

- (BOOL)isEditable;

- (void)setEditable:(BOOL)flag;
  • 属性表示动词,格式是:
- (BOOL)verbObject;

- (void)setVerbObject:(BOOL)flag;

举例:

- (BOOL)showsAlpha;

- (void)setShowsAlpha:(BOOL)flag;

动词应该使用现在时
- 不要将动词通过介词转为形容词

代码 评论
    (void)setAcceptsGlyphInfo:(BOOL)flag;
正确
    (BOOL)acceptsGlyphInfo;
正确
    (void)setGlyphInfoAccepted:(BOOL)flag;
错误
    (BOOL)glyphInfoAccepted;
错误

- 可以使用情态动词(在动词前面加 “can”,“should”,“will”等等)澄清含义,但是不要使用“do”或者“does”

代码 评论
    (void)setCanHide:(BOOL)flag;
正确
    (void)setCanHide:(BOOL)flag;
正确
    (void)setShouldCloseDocument:(BOOL)flag;
正确
    (BOOL)shouldCloseDocument;
正确
    (void)setDoesAcceptGlyphInfo:(BOOL)flag;
错误
    (BOOL)doesAcceptGlyphInfo;
错误

- 只有在间接返回对象和值的方法中才使用“get”,只有需要返回多个值得的方法菜需要使用这种格式。

代码 用处
    (void)getLineDash:(float )pattern count:(int )count phase:(float *)phase;
NSBezierPath.

代理方法

代理方法是对象能够在其代理中唤醒调用当某种事件发生的时候。它们有一种特殊的形式,这种形式同样适用于一个对象数据源的方法中。
- 以表示发送消息的对象所属类来命名开头

- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;

该类的名字省略了前缀并且以小写字母开头。

  • 冒号在类名后面(对于代理对象来说参数是一个引用)除非方法只有一个参数,这个参数就是消息发送者。
- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender;
  • 有一种例外就是消息通知发送的消息。这种情况下,唯一的参数是通知对象。
- (void)windowDidChangeScreen:(NSNotification *)notification;
  • 代理方法使用“did”或者“will”通知代理已经发生了或者将要发生什么?
- (void)browserDidScroll:(NSBrowser *)sender;
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window;
  • 尽管代理方法可以使用“did”或者“will”,我们推荐使用“should”。
- (BOOL)windowShouldClose:(id)sender;

集合方法

对于管理着一些对象(每一个对象称为一个元素)的集合对象,对一些方法如下的约定。

- (void)addElement:(elementType)anObj;

- (void)removeElement:(elementType)anObj;

- (NSArray *)elements;

例子:

- (void)addLayoutManager:(NSLayoutManager *)obj;

- (void)removeLayoutManager:(NSLayoutManager *)obj;

- (NSArray *)layoutManagers;

下面是对这个指南的一些限制条件和改进

  • 如果集合是无序的,返回一个NSSet,不要返回一个NSArray
  • 若需要将对象插入到集合的某个特定位置,使用类似于如下的方法
- (void)insertLayoutManager:(NSLayoutManager *)obj atIndex:(int)index;
- (void)removeLayoutManagerAtIndex:(int)index;

需要记忆的一些集合方法的细节

  • 这些方法需要代表与操作对象这件的所属关系,添加或者插入需要持有该对象,删除必须释放该对象。

对于上面的规范有一些自于NSWindow类的集合方法

- (void)addChildWindow:(NSWindow *)childWin ordered:(NSWindowOrderingMode)place;
- (void)removeChildWindow:(NSWindow *)childWin;
- (NSArray *)childWindows;

- (NSWindow *)parentWindow;
- (void)setParentWindow:(NSWindow *)window;

方法参数

私有方法

有两条建议
- 不要使用下划线开头,apple在使用。
- 如果子类化一个Cocoa框架类,可以使用公司或者工程名称作为前缀如“XX_”。如果你的项目为:Byte Flogger,前缀是BF_addObject;

函数命名

函数有些需要遵守的规则
- 函数命名如方法的命名很相像,但是有一些例外需要注意

1.使用在常量和类中使用的前缀

2.在前缀后的首字母大写
  • 大部分函数以描述函数意义的动词开头
NSHighlightRect

NSDeallocateObjec

查询属性的函数有更多的一些规则
- 如果函数返回其第一个参数的属性,需要省略动词。

unsigned int NSEventMaskFromType(NSEventType type)

float NSHeight(NSRect aRect)
  • 如果通过引用返回其值,使用“get”
const char *NSGetSizeAndAlignment(const char *typePtr, unsigned int *sizep, unsigned int *alignp)
  • 如果返回一个boolean值,应该以一个变形的动词开头
BOOL NSDecimalIsNotANumber(const NSDecimal *decimal)

属性和数据类型命名

声明属性和实例变量

如果属性或者实例变量是名字和动词,格式如下:
@property(__)type nounOrVerb;

举例

@property (strong) NSString *title;
@property (assign) BOOL showsAlpha;

如果属性或者变量是形容词,但是需要省略“is”前缀,但是需要详细的约定获取方法,例如:

@property (assgin,getter=isEditable) Bool editable;

许多情况下,当使用一个已经声明的属性也应该合成相应的实例变量。
确保实例变量的名字简洁地描述存储属性。通常你不应该直接访问实例变量。应该通过访问方法来访问。为了有助于标志实例变量,可以使用下划线开头,例如:

@implementation MyClass {
    BOOL _showsTitle;
}

如果使用一个已经声明的属性来合成实例变量,在@synthesize语句中详细说明实例变量。

@implementation MyClass
@synthesize showsTitle=_showsTitle;

一些注意事项
- 不要显示的声明一个公开的实例变量
- 如果需要声明一个实例变量,明确声明是@private 或者@protected
- 如果一个实例变量一个可访问的实例属性,确保为这个实例变量编写了访问器方法

常量

常量根据创建方式的不同,规则也不一样。

枚举常量

typedef enum _NSMatrixMode {
    NSRadioModeMatrix           = 0,
    NSHighlightModeMatrix       = 1,
    NSListModeMatrix            = 2,
    NSTrackModeMatrix           = 3
} NSMatrixMode;

使用const创建常量

使用const的例子

const float NSLightGray;

其他类型的常量

  • 通常,不要使用#define预处理器命令来创建常量。
  • 使用大写,举例
#ifdef DEBUG
  • 注意,编译器定义的宏前后都有两个下划线,举例:
__MACH__

通知和异常

通知和异常的命名也是类似的规则。但是两者都有它们推荐的使用方式。

通知

如果一个类有代理,那么代理会通过事先定义好的代理方法来接受大多数的通知。这些通知名称应该反映相应的代理方法。例如,全局的NSApplication对象的自动注册的代理会接受applicationDidBecomeActive:的消息当app发送一个NSApplicationDidBecomeActiveNotification的通知。

通知使用NSString来表示,使用下面的方式来命名:

[Name of associated class] + [Did | Will] + [UniquePartOfName] + Notification

例如:

NSApplicationDidBecomeActiveNotification

NSWindowDidMiniaturizeNotification

NSTextViewDidChangeSelectionNotification

NSColorPanelColorDidChangeNotification

异常

使用全局的NSString对象来表示异常,命名组成如下:

[Prefix] + [UniquePartOfName] + Exception

Unique 部分应该将单词组成在一块并且大写每一个单词的首字母。下面一些例子:

NSColorListIOException

NSColorListNotEditableException

NSDraggingException

NSFontUnavailableException

NSIllegalSelectorException

可接受的简写和缩写

通常,不应该对接口的名称进行缩写。然而,下面列出的缩写已经被创建或者在过去被使用了很久,因此,可以继续使用。关于缩写有一些其他需要注意的地方:
- 来源于标准C库的一些缩写,例如‘alloc’和‘getc’是被允许的。
- 在参数的命名中可以更加*的使用缩写。

Abbreviation Meaning and comments
alloc Allocate
alt Alternate
app Application. For example, NSApp the global application object. However, “application” is spelled out in delegate methods, notifications, and so on.
calc Calculate
dealloc Deallocate.
func Function.
horiz Horizontal.
info Information.
init Initialize (for methods that initialize new objects).
int Integer (in the context of a C int—for an NSInteger value, use integer).
max Maximum.
min Minimum.
msg Message.
nib Interface Builder archive.
pboard Pasteboard (but only in constants).
rect Rectangle.
Rep Representation (used in class name such as NSBitmapImageRep).
temp Temporary.
vert Vertical.

在计算机产业中使用的缩写和首字母缩略词你可能使用到,下面有些熟知的缩略词:

ASCII

PDF

XML

HTML

URL

RTF

HTTP

TIFF

JPG

PNG

GIF

LZW

ROM

RGB

CMYK

MIDI

FTP

对于框架开发者的小技巧

这部分是关于框架开发者的一些建议,略…

相关标签: cocoa

上一篇: CSS3之动画animation

下一篇: helloword