所有的变量均指参数
“方法” 可能是你的程序中最常用的元素, 因此你应该特别关注 “如何命名它们”. 本章节将讨论方法命名的以下方面:
一般性规则
当你命名方法时,有一些准则需要记在头脑里.
方法名称以小写字母开头, 后续单词的首字母大写(驼峰). 不要使用前缀.
对于这些准则有两个明确的例外. 你可以以一个众所周知的大写首字母缩略词(比如 TIFF或者PDF)作为方法的开头, 你也可以使用前缀来进行分组并区分私有方法.
对于表示 一个对象所采取的动作的方法, 以动词开头
- (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, NSView的子类
不要使用’and’来连接属于调用者属性的关键字
( 换句话说, 如果这个参数是调用者的属性, 则不需要用and来连接)
- (int)runModalForDirectory:(NSString *)path file:(NSString *) name types:(NSArray *)fileTypes; 正确
- (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes; 错误
尽管’and’在这个例子中看起来很不错, 但是当你创建一个有更多更多关键字的方法时就会产生问题.
如果方法描述了两个单独的动作, 使用’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 值, can类型属性)
- (BOOL)isAdjective;
- (void)setAdjective:(BOOL)flag;
比如:
- (BOOL)isEditable;
- (void)setEditable:(BOOL)flag;
如果属性表达为动词, 格式为:
- (BOOL)verbObject;
- (void)setVerbObject:(BOOL)flag;
比如:
- (BOOL)showsAlpha;
- (void)setShowsAlpha:(BOOL)flag;
动词应该用一般现在时.
不要使用分词将动词变成形容词
(分词指 以ing, ed 等形式结尾的动词, 可表 形容词 或者 时态 使用)
- (void)setAcceptsGlyphInfo:(BOOL)flag; 正确
- (BOOL)acceptsGlyphInfo; 正确
- (void)setGlyphInfoAccepted:(BOOL)flag; 错误
- (BOOL)glyphInfoAccepted; 错误
你可以通过使用情态动词(比如 can, should, will 等等)来明确意思, 但是不要使用’do’ 或者 ‘does’
- (void)setCanHide:(BOOL)flag; 正确
- (BOOL)canHide; 正确
- (void)setShouldCloseDocument:(BOOL)flag; 正确
- (BOOL)shouldCloseDocument; 正确
- (void)setDoesAcceptGlyphInfo:(BOOL)flag; 错误
- (BOOL)doesAcceptGlyphInfo; 错误
对于间接返回 对象和值的方法, 使用’get’. 当有多个参数需要返回的时候,你应该使用下面这种格式.
(最前面一个参数使用get, 后面需要返回的参数是指针 且 不加and)
- (void)getLineDash:(float *)pattern count:(int *)count phase:(float *)phase; NSBezierPath
对于这样的方法, 应该接受为NULL的输入和输出参数, 以表明调用者对一个或者多个返回值不感兴趣.
代理方法
代理方法是指 当确定事件发生时,对象在其代理中回调的方法(如果代理对象有实现相应方法). 他们有与众不同的格式, 这个同样也适用于对象数据源中回调的方法.
以 标识正在发送消息的对象所属的类 开头
- (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’更好.
(这句话翻译过来比较奇怪, 直接看代码比较好理解. 也就是 self.delegate的self(代理所代表的对象) close(做某事))
- (BOOL)windowShouldClose:(id)sender;
集合方法
对于管理一个对象集合的对象, 以下方法的格式是约定写法:
- (void)addElement:(elementType)anObj;
- (void)removeElement:(elementType)anObj;
- (NSArray *)elements;
For example:
- (void)addLayoutManager:(NSLayoutManager *)obj;
- (void)removeLayoutManager:(NSLayoutManager *)obj;
- (NSArray *)layoutManagers;
对于这个准则而言, 下面是一些限制
如果集合是真正无序的, 返回一个NSSet对象而不是NSArray对象
如果把元素插入在集合中明确的位置是很重要的, 那么使用下面类似的方法 而不是上面的任一个
- (void)insertLayoutManager:(NSLayoutManager *)obj atIndex:(int)index;
- (void)removeLayoutManagerAtIndex:(int)index;
在集合相关的方法中有一些实现细节需要记住:
这些方法(增删)通常意味着被插入对象的所有权, 因此添加/插入对象必须retain(保留)此对象, 删除对象也必须release(释放)此对象.
如果被插入对象需要给主对象返回一个指针, 通常来说你需要一个set方法,此方法返回一个指针但是不retain(保留)此对象. 在insertLayoutManager:atIndex 方法中, NSLayoutManager类就是这么做的.
- (void)setTextStorage:(NSTextStorage *)textStorage;
- (NSTextStorage *)textStorage;
通常来说, 你不会直接调用setTextStorage: 方法, 而是会选择重写它.
另一个关于集合方法的惯例写法来自NSWindow
- (void)addChildWindow:(NSWindow *)childWin ordered:(NSWindowOrderingMode)place;
- (void)removeChildWindow:(NSWindow *)childWin;
- (NSArray *)childWindows;
- (NSWindow *)parentWindow;
- (void)setParentWindow:(NSWindow *)window;
方法参数
下面是一些有关方法参数名的一般性规则:
与方法一样, 参数也以小写字母开头, 后面连续的单词第一个字母大写
不要在名字中使用’pointer’或者’ptr’. 要让参数类型而不是参数名来表明它是否是一个指针
避免使用一个和两个单词名作为参数
避免只使用几个字母的缩写
通常, 下面的关键字和变量会被一起使用:
...action:(SEL)aSelector
...alignment:(int)mode
...atIndex:(int)index
...content:(NSRect)aRect
...doubleValue:(double)aDouble
...floatValue:(float)aFloat
...font:(NSFont *)fontObj
...frame:(NSRect)frameRect
...intValue:(int)anInt
...keyEquivalent:(NSString *)charCode
...length:(int)numBytes
...point:(NSPoint)aPoint
...stringValue:(NSString *)aString
...tag:(int)anInt
...target:(id)anObject
...title:(NSString *)aString
私有方法
大多数情况下, 私有方法名和公开方法名遵守相同的规则. 然而, 一个共同的约定是 私有方法需要有一个前缀用以更简单的和公开方法进行区分. 即使有这个约定, 私有方法名也可能造成一个奇怪的类型问题. 当你设计一个Cocoa 框架子类的时候, 你无法得知是否你的私有方法无意中重写了私有框架中同名的方法.
Cocoa框架中大多数私有方法的名称都有下划线前缀,以将它们标记为私有.
不要使用下划线作为你私有变量的前缀. 苹果保留这一惯例.
如果你正在子类化一个大的Cocoa框架类(比如UIView或者NSView)并且你想要完全确保你的私有方法和父类中方法不同, 你可以在你的私有方法前添加自己的前缀. 前缀应该尽可能独一无二, 可以基于你的公司或者项目并且形式为”XX”.