Coding GuideLines For Cocoa

Coding GuideLines For Cocoa


###基本命名规范
####通用原则
#####清晰

  • 命名应做到既清晰又简洁,两者权衡更注重于清晰
CodeCommentary
insertObject:atIndex:Good
insert:at:不清晰,插入什么的东西,at表示什么
removeObjectAtIndex:Good
removeObject:Good,清晰的指出了要移除参数中的对象
remove:不清晰,什么被移除?
  • 通常情况下不要缩写单词,即使很长
CodeCommentary
destinationSelectionGood
destSel不清晰
setBackgroundColor:Good
setBkgdColor:不清晰
  • 少数通用的缩写可以使用
缩写全称
allocAllocate
altAlternate.
appApplication
calcCalculate.
deallocDeallocate.
funcFunction.
horizHorizontal.
infoInformation.
initInitialize
intInteger
maxMaximum.
minMinimum.
msgMessage.
nibInterface Builder archive.
pboardPasteboard
rectRectangle.
RepRepresentation (used in class name such as NSBitmapImageRep).
tempTemporary.
vertVertical.
  • 避免使用有歧义的API名称,例如有的方法名不止一种解释
CodeCommentary
sendPortDoes it send the port or return it?
displayNameDoes it display a name or return the receiver’s title in the user interface?

#####一致性

  • 命名要和Cocoa框架保持一致,如果不能确定,可以参考Cocoa框架的头文件
  • 当一个类使用多态性的便利时,一致性就特别重要。在不同类中做了相同事情的方法,方法名应该相同
CodeCommentary
- (NSInteger)tagDefined in NSView, NSCell, NSControl.
- (void)setStringValue:(NSString *)Defined in a number of Cocoa classes.

#####不要自我参照

  • 命名不能自我参照
CodeCommentary
NSStringOkay.
NSStringObjectSelf-referential.
  • 作为掩码使用的常量和通知名称可以不遵守这条规则
CodeCommentary
NSUnderlineByWordMaskOkay.
NSTableViewColumnDidMoveNotificationOkay.

####前缀

  • 前缀一般有俩个或三个大写字母构成,不能使用下划线和子前缀
PrefixCocoa Framework
NSFoundation
NSApplication Kit
ABAddress Book
IBInterface Builder
  • 类名、协议名、常量、结构体、类别方法需要加前缀,普通方法名、结构体域不需要加前缀

####命名约定

  • 由多个单词组成的名称,不要使用标点符号作为名称的一部分或者单词间的分割点(例如下划线、破折号),应该使用驼峰命名法,单词的首字母大写,单词之间构成一个整体来解释名称含义

    • 对于方法名称,第一个单词首字母小写,其它嵌入的单词首字母大写,不要使用前缀。

      • fileExistsAtPath:isDirectory:
      • 一些广泛使用的单词缩写首字母可以大写,例如TIFFRepresentation
    • 部分常用单词缩写

      • ASCII
      • PDF
      • XML
      • HTML
      • URL
      • RTF
      • HTTP
      • TIFF
      • JPG
      • PNG
      • GIF
      • LZW
      • ROM
      • RGB
      • CMYK
      • MIDI
      • FTP
    • 对于函数名和常量名,相关联的类要使用相同的前缀,嵌入的单词首字母大写

      • NSRunAlertPanel
        
        NSCellDisabled
        
  • 不要使用下划线作为私有方法名的前缀,苹果保留了这种用法,第三方框架使用下划线作为前缀,容易和苹果的私有方法冲突

####类名和协议名
类名需要包含一个名词来清楚的表示这个类是做什么的,类名还需要有一个合适的前缀。

协议名取决于协议怎么分组其行为方法的

  • 大部分的协议组织了一组相关的方法,这些方法与特定的类没有关系。这种类型的协议名称不要与类名混淆,通用的解决办法是使用动名词(“ing”)
CodeCommentary
NSLockingGood
NSLockPoor (seems like a name for a class).
  • 一些协议组织了一些不相关的方法,这些协议和某一个紧密的类相关联,这个类提供了协议最主要的实现。在这种情况下,类名和协议名相同。

    NSObject协议就是一个典型的例子

####头文件
怎样命名头文件非常重要,一些约定俗成的命名方式可以表示这个文件中包含什么。

  • 声明单独的类和协议. 如果一个类或协议是独立的,则把这个类或协议的声明放到一个单独的头文件中,文件名和类或协议名相同
Header fileDeclares
NSLocale.hThe NSLocale class.
  • 声明相关的类和协议。 一组相关联的类、分类、协议的声明放到同一个头文件中
Header fileDeclares
NSString.hNSString and NSMutableString classes.
NSLock.hNSLocking protocol and NSLock, NSConditionLock, and NSRecursiveLock classes.
  • 框架头文件。每个框架都应该有一个与框架名相同的头文件,这个文件包含了框架中所有公开的头文件
Header fileFramework
Foundation.hFoundation.framework.
  • 在其他框架中为一个类添加API. 新的头文件名是在原类名后添加Additions,如NSBundleAdditions.h
  • 若有一系列相关的方法,常量,结构体等,将其声明在一个合适名称的头文件里,如NSGraphics.h (Application Kit)

###方法命名规范
####通用规则

  • 方法名首字母小写,嵌入的单词首字母大写,不要使用前缀。

    有俩种特殊的场景不用遵守这条规则,一种是方法名的首个单词是通用的缩写(TIFF/PDF), 另外一种是组织和区分私有方法的时候可能会使用前缀。

  • 表示对象动作的方法,以动词开始

    - (void)invokeWithTarget:(id)target;
    - (void)selectTabViewItem:(NSTabViewItem *)tabViewItem
    

    不要使用do或者does之类的辅助动词,基本不会增加额外的含义。也不要用副词和形容词在动词前面修饰。

  • 如果方法返回的是接收者的属性,方法名用属性名来命名,不用使用get, 除非间接返回多个值

- (NSSize)cellSize;Right.
- (NSSize)calcCellSize;Wrong.
- (NSSize)getCellSize;Wrong.
  • 在所有的参数前都使用关键字
- (void)sendAction:(SEL)aSelector toObject:(id)anObject forAllCells:(BOOL)flag;Right.
- (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag;Wrong.
  • 在参数前的单词要描述参数
- (id)viewWithTag:(NSInteger)aTag;Right
- (id)taggedView:(int)aTag;Wrong.
  • 对继承的方法扩展时,可以在原方法名后加关键字
- (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;Right.
- (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes;Wrong.
  • 如果方法描述了俩个分离的动作,可以用and链接
- (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;NSWorkspace.

####Accessor Methods

  • 属性为名词时
- (NSString *)title;
- (void)setTitle:(NSString *)aTitle;
  • 属性为形容词时
- (BOOL)isEditable;
- (void)setEditable:(BOOL)flag;
  • 属性为动词时
- (BOOL)showsAlpha;
- (void)setShowsAlpha:(BOOL)flag;
  • 不要使用过去分词来让动词和形容词组成方法名
- (void)setAcceptsGlyphInfo:(BOOL)flag;Right.
- (BOOL)acceptsGlyphInfo;Right.
- (void)setGlyphInfoAccepted:(BOOL)flag;Wrong.
- (BOOL)glyphInfoAccepted;Wrong.
  • 可以使用情态动词,不要使用do/does
- (void)setCanHide:(BOOL)flag;Right.
- (BOOL)canHide;Right.
- (void)setShouldCloseDocument:(BOOL)flag;Right.
- (BOOL)shouldCloseDocument;Right.
- (void)setDoesAcceptGlyphInfo:(BOOL)flag;Wrong.
- (BOOL)doesAcceptGlyphInfo;Wrong.
  • 间接返回多个值时,可以使用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;

类名省略前缀,并且首字母小写

  • 一个冒号总是跟在类名后面,如果只有一个参数sender像下面的方式命名

    - (BOOL)applicationOpenUntitledFile:(NSApplication *)sender;
    
  • 一种例外的情况是sender发出通知,这是只有一个通知对象作为参数

    - (void)windowDidChangeScreen:(NSNotification *)notification;
    
  • 可以使用didwill通知代理对象一些事情已经发生或即将发生

    - (void)browserDidScroll:(NSBrowser *)sender;
    - (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window;
    
  • 也可以使用didwill来向代理对象请求某些行为的发生

    - (BOOL)windowShouldClose:(id)sender;
    

####集合方法
集合对象方法模板

- (void)addElement:(elementType)anObj;
- (void)removeElement:(elementType)anObj;
- (NSArray *)elements;

注意点

  • 如果集合是无序的,返回NSSet要比NSArray

  • 如果要在集合的指定位置插入或删除元素,用下面的命名方法

    - (void)insertLayoutManager:(NSLayoutManager *)obj atIndex:(int)index;
    - (void)removeLayoutManagerAtIndex:(int)index;
    
  • 集合对象通常拥有被插入的对象,添加或插入对象的时候需要持有对象,删除对象的时候需要释放对象

  • 被插入的对象如果想用一个指针指向集合对象,可以用set方法来实现但是不要retain

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

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

####方法参数

  • 参数名首字母小写,接下来的单词首字母大写, removeObject:(id)anObject

  • 不要使用pointerptr,让参数的类型来声明

  • 避免使用one-two-letter来做参数名

  • 不要使用缩写

Cocoa中经常一起使用的关键字和参数名

...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框架类, 或者是添加分类方法,可以使用项目或公司简写作为前缀

####命名函数

  • 函数名和方法名基本一样,除了下面俩条

    • 函数名使用与类、常量相同的前缀
    • 前缀后第一个单词首字母大写
  • 大部分的函数名以动词开头,描述了函数的作用

    NSHighlightRect
    NSDeallocateObject
    
  • 如果返回值是函数第一个参数的属性,省略动词

    unsigned int NSEventMaskFromType(NSEventType type)
    float NSHeight(NSRect aRect)
    
  • 如果返回值是引用类型,使用Get

    const char *NSGetSizeAndAlignment(const char *typePtr, unsigned int *sizep, unsigned int *alignp)
    
  • 如果返回值是BOOL类型,用一个转折变化的动词开头

    BOOL NSDecimalIsNotANumber(const NSDecimal *decimal)
    

###属性和数据类型命名规范
####声明属性和实例变量
一个声明的属性实际上也声明了这个属性的存取方法, 宽泛的来说属性的命名规则和访问方法的命名规则相同。如果属性用一个动词或名词来表达,格式如下:
@property (…) type nounOrVerb;

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

如果属性用一个形容词来表达,属性名词省略is, 但是可以在get方法中添加is
@property (assign, getter=isEditable) BOOL editable;

  • 不要直接声明公有实例变量,使用属性代替

  • 如果要声明实例变量显示指出@private@protected

  • 如果一个实例变量是可访问的,确保实现访问方法

####通知

[类名] + [Did | Will] + [行为] + Notification

NSApplicationDidBecomeActiveNotification

NSWindowDidMiniaturizeNotification

NSTextViewDidChangeSelectionNotification

NSColorPanelColorDidChangeNotification

####异常

[Prefix] + [UniquePartOfName] + Exception

NSColorListIOException

NSColorListNotEditableException

NSDraggingException

NSFontUnavailableException

NSIllegalSelectorException

###框架开发技巧
####初始化
#####类初始化
可以在类方法initialize中执行一些一次性的代码,这个方法在第一次使用类的时候会调用,通常用来设置类的版本号

如果一个类没有实现initialize方法,就会调用父类的,所以为了避免一个类的initialize方法调用多次可以下面的方法来实现该方法

if (self == [NSFoo class]) {

    // the initializing code

}

永远不要直接调用initialize方法,如果需要触发初始化过程,可以调用一些无害的方法例如:

[NSImage self];

#####指定初始化方法
一个指定初始化方法是一个类的init方法,这个方法会调用父类init方法。(其它初始化方法会调用指定初始化方法)。每个公有类都应该有一个或多个指定初始化方法。NSViewinitWithFrame:NSResponderinit方法就是很好的例子。init并不意味着要重写, 只有像NSString和其它面向类簇的抽象类,子类需要实现自己的方法。

指定初始化方法应该被清晰的标识,这个信息对子类很重要。一个子类只需要重写指定初始化方法,其它初始化方法将会正常使用。

实现一个框架中的类时,总是会实现这个类的归档方法initWithCoder:encodeWithCoder:,当一个对象没有归档时,不要在这种初始化方法中添加任务代码。可以在指定初始化方法和initWithCoder:调用一段通用代码。

#####在初始化过程中的错误检测

- (id)init {

    self = [super init];  // Call a designated initializer here.

    if (self != nil) {

        // Initialize object  ...

        if (someError) {

            [self release];

            self = nil;

        }

    }

    return self;

}

####异常和错误
大部分的Cocoa 框架方法都不强制开发者捕获及处理异常。因为在一个正常的执行过程中是不会有异常抛出的,对于期望中的运行时和用户错误通常不会使用异常处理。例如

  • 文件找不到
  • 没有这个用户
  • 尝试打开错误类型的文档
  • 用指定的编码方式转换字符串发生的错误

但是对于像下面的程序或逻辑错误,Cocoa会抛出异常:

  • 数组越界
  • 尝试改变不可变对象
  • 错误的参数类型

期望的结果是开发者可以在测试过程中捕获到这些异常错误,在发布程序前处理了这些错误。这样程序就不需要在实际运行中处理异常,如果一个抛出的异常没有被捕获到,顶端的默认处理程序会捕获以及报告异常然后继续。开发者可以替换默认的异常捕获器,可以提供更加详细的错误信息以及保持数据和退出程序的选项。

错误是Cocoa框架不同于别的软件库的另一个地方。Cocoa方法通常不会反悔错误码。当一个预期的或者可能的错误发生时, Cocoa方法可以返回bool值或者nil。你不应该使用错误码来提示需要在运行时处理的程序错误,要抛出异常或者简单用日志记录。

例如,NSDictionary’s objectForKey:方法要么返回找到的对象,要么返回nil. NSArray’s objectAtIndex: 永远不能返回nil,因为NSArray对象不会存储nil值,对于越界的参数需要抛出异常。大部分的初始化方法应该返回nil在初始化失败的时候。

在少数情况下一个方法确实需要多个不同的错误码, 应该用解引用的方式返回错误信息。例如使用NSError对象,这个方法需要注意**NSError参数的可选情况,对于不关心错误信息的发送者会传nil

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值