[代码编程规范][代码样式][cocoa]Cocoa Style For Objective-C 下
【原文链接:http://cocoadevcentral.com/articles/000083.php】
Method Names: Returning Objects 方法命名:返回值 除了简单的存取函数,类和对象可以根据条件或输入参数的不同返回对象。 格式如: [object/class thing+condition]; [object/class thing+input:input]; [object/class thing+identifer:input]; In addition to simple accessors, classes or objects can also return objects based on various conditions or input. The format is simple: Examples realPath = [path stringByExpandingTildeInPath]; fullString = [string stringByAppendingString:@"Extra Text"]; object = [array objectAtIndex:3]; // class methods newString = [NSString stringWithFormat:@"%f",1.5]; newArray = [NSArray arrayWithObject:newString]; 当我们自己写时,应该写成这样 If I wrote some of my own, this is what they might look like. recipients = [email recipientsSortedByLastName]; newEmail = [CDCEmail emailWithSubjectLine:@"Extra Text"]; emails = [mailbox messagesReceivedAfterDate:yesterdayDate]; 主意:所有这些方法命名时,首先表明要返回对象的类型,接着是返回条件的详细说明。同时也要注意最好用冒号之前最后的一个单词表明输入参数的类型。 Note that all of these messages first indicate what kind of thing will be returned, followed by what the circumstances will be for returning it. Also note that the last word right before the colon describes the type of the supplied argument. 有时,你希望修改变量,在这种情况下,格式应该入如下: Sometimes, you want a variation on a value. In that case, the format is generally: [object adjective+thing]; [object adjective+thing+condition]; [object adjective+thing+input:input]; Examples capitalized = [name capitalizedString]; rate = [number floatValue]; newString = [string decomposedStringWithCanonicalMapping]; subarray = [array subarrayWithRange:segment]; 通常消息函数都会比较短,很少像-decomposedStringWithCanonicalMapping这么长的 Messages are rarely quite as long as -decomposedStringWithCanonicalMapping Avoid Ambiguity、 避免含糊不清 Bugs are scarce where code doesn't leave questions unanswered. 如果解决了所有问题,那么bug也会减少。 Ambiguous Messages 含糊不清的消息函数 -sortInfo -refreshTimer -update -fetchInfo: On the surface, these methods may seem good. For example, they all have vowels. But what they share is the potential for different interpretations because of the language used. 从表明看来,这些消息函数都不错,但是却会根据不同的语境,产生不同的意思。 * sortInfo - returns sort info, or sort something called "info"? 是返回选择排序信息,亦或者返回叫info的对象? * refreshTimer - return a timer used for refreshing, or refresh a timer? 是返回一个用来刷新的timer,亦或者是用来刷新一个timer * update - a verb? what is updated and how? 一个动词?更新什么,怎么更新? * fetchInfo - fetch info about something or give info about a fetch? 获取的某个对象的信息还是获取fetch对象的信息。 这些问题只要使用一些短语就可以避免 This is all fixed by slightly modifying the phrases: Clear Messages 清楚明确的消息函数 -currentSortInfo // "current" obviously describes the noun "sort info" current明确“sort info”将作为名词 -refreshDefaultTimer // refresh is now clearly a verb refresh在这里明显是一个动作。 -updateMenuItemTitle // an action is taking place 表明要发生的动作 -infoForFetch: // now we know info is returned for a fetch 现在我们清楚要返回的是fetch的信息 By just adding a few characters to each method, we've removed almost all ambiguity. And there was much rejoicing. 通过添加一些单词,我们就可以去除方法名中潜在的歧义。 Note that the -updateMenuItem method doesn't put the NS prefix on menu item 注意,-updateMenuItem函数方法这里的menu items 前不加NS前缀。 Global C Functions 全局c函数 Global C functions generally use one of a few simple formulas: 全局c函数,一般只用以下几种简单的格式 Prefix + Value () 前缀+值 Prefix + Value + With/From/For + Input () 前缀+值+with/From/For + 形参() Prefix + Action () 前缀+动作() Prefix + Action + Type () 前缀+动作+类型() Just like classes, functions are prefixed with initials in order to prevent namespace issues. Since C functions are free-standing by nature, the function name needs to indicate data types they interact with, if any. Functions from Cocoa 和类一样,函数也要加前缀,为了预防命名空间的错误,由于c函数是可以随意调用的,所以在函数名中最好能体现出与之交互的数据类型(如果有交互的数据)。 NSHomeDirectory() NSHomeDirectoryForUser() NSClassFromString() NSBeginAlertSheet() NSDrawGrayBezel() Core Services Functions 核心服务函数 In Core Services frameworks such as Core Foundation and Core Graphics, functions are prefixed with the most-relevant opaque type, and the "get" prefix is used even when there's no indirection involved: Core Foundation CFArrayGetValueAtIndex() // returned directly, but "get" is still used CFDictionaryGetValue() CFDateGetAbsoluteTime() Core Graphics / Quartz CGImageCreate() CGImageGetHeight() CGImageGetTypeID() 在核心服务框架中,如在Core Foundation核心基础库和Core Graphics核心图库,函数都带有与之对应最近的库名前缀缩写。而且“get”前缀在没有必然联系时也会使用。 /*关于get的翻译很有问题*/ Other Global Symbols 其他的全局变量 There are several types of symbols with global scope in addition to C functions. 除了全局的c函数外,还有几种全局变量 For example: * Constants 常量 * Typedef'd structs 结构体 * Typedef'd enums 枚举 * Individual enum values 单个的枚举值 * Objective-C Protocols obj-c 协议 Protocols, constants, structs, enums and enum values are basically named according to the same rules as classes or C functions. 协议,常量,结构体,枚举类型,和枚举值的命名方式和类名,c函数名的命名方式一样 Capitalized with initials at the front: 大写首字母 Structs NSPoint point; // struct NSRange range; // struct NSRectArray * rects; // c-style array of structs In Cocoa, enums are frequently used as "modes" for methods: 在cocoa框架中,枚举类型常常用作“modes”指定方法的模式,如: range = [string rangeOfString:@"find me" options:NSLiteralSearch]; Both constants and enums have a suffix that indicates what kind of thing they are: 对于常量和枚举类型,都会有后缀来表明其类型 Constants and Enums // search modes (enums) NSLiteralSearch NSCaseInsensitiveSearch // exception names (constants) NSMallocException NSInvalidArgumentException // notification names (constants) NSTaskDidTerminateNotification NSWindowWillMoveNotification Also, note that notification names have a slightly different formula: 同样需要注意,通告的命名方式稍有不同: 收到影响的类名+Did/Will +动作+“notification”后缀 Class of Affected Object + Did/Will + Action + "Notification" Dynamic Typing 动态类型绑定 Objective-C is a dynamically-typed language, meaning that you don't have to tell the compiler what type of object you're working with at compile time. Objective-c 是支持动态绑定的语言。即在编译阶段你可以不用明确告诉编译器要使用的对象是那个类型的。 Declaring a type for a varible is merely a promise which can be broken at runtime if the code leaves room for such a thing. You can declare your variables as type id, which is suitable for any Objective-C object. 声明一个变量的类型仅仅是一个允诺,在运行阶段可能会打破。如果代码需要处理这种情况, 你就可以定义变量为ID类型--能指向所有objectiv-c对象。 Dynamically-Typed Variables 动态类型变量 id hostName; id ipAddress; id keyedAccountNames; id theObject; // the compiler is fine with this //此时,编译以下代码都不会有错 theObject = [NSString string]; theObject = [NSNumber numberWithInt:1]; theObject = [NSDictionary dictionary]; So why specify type at all? Three basic reasons: 那为什么还要指定类型那?三个原因: 1. To be clear: Makes it clear what you intend to do with the variable 为了明确:明确你打算怎么使用这个变量 2. To avoid useless warnings: If multiple classes share the same method name, the compiler may warn you when you send that message to a generic object. 为了避免不必要的警告:如果几个类都使用相同的方法名称,编译器在你给一个实例对象发送消息时发出警告。 3. To get useful warnings: If you misspell a message name, such as "-stringg", the compiler will tell you that NSMutableString does not implement such a method 为了提供有用的警告:如果你拼错了一个消息方法的名称,如“-stringg”,此时编译器就会提示你NSMutableString没有该方法 In addition, there are situations where the id type makes the most sense. Some are: 此外的一些状况下,使用id类型更容易理解。 1. A delegate or datasource 一个代理,或者数据源 2. Object for a notification 一个通知对象 3. Contents for a generic container 一个通用容器的内容。 4. Objects involved in target/action target/action 目标/动作 调用的相关对象 So no hard rules here, but a good basic practice is to specify the type if you have reason to believe other types of objects wouldn't make sense in a given situation. 所以没有严格的规则,但是良好的基本用法是在一定条件下你确定使用其他类型都没有意义时,就要指定类型。 When to Use Accessors 什么时候使用属性 Short answer:always 答案很简单:总是。 Why not just directly access instance variables within a class? It's a lot less code, right? 为什么不直接存取一个类型的成员变量(实例变量)?这样会节省很多代码,对吗? The reason is flexibility. If your code gets to data via accessors, it's easy to change how that data is manipulated later. 原因是灵活性。如果你通过访问器访问数据,那么以后在修改这些数据的操作时也会方便很多。 For example, it gives you a good entry point for registering the previous value with NSUndoManager. Or when debugging, it might help to log when a particular instance variable is fetched. 例如,NSUndoManager是一个很好的入口点用来保存之前的值,或者在debugging时,它可以有助于我们生产某个特定的实例对象的日志信息。 But there's an even better reason to create accessors: Key-Value Coding. KVC is a protocol used throughout Cocoa, most notably in bindings. It will look for accessors for your keys first, and only access data directly as a last resort. You can shorten KVC's search and thus speedup data access by implementing accessors. 但是还有一个更好的理由来使用访问器:键值编码格式。KVC是cocoa框架遵循的一个协议,特别明显的是在绑定过程中,首先会寻找键值的访问器,如果没有其他方法最后才会直接访问数据。所以你可以通过实现访问器方法来减少KVC的查询和数据读取时间。 Also be aware that if you set instance variables directly, in the form of var = value, Key-Value Observing will not notice the change and bound objects will not get the new value. 同样要明白如果你直接的设置了成员变量(实例变量),以赋值的形式 var=value KVC不会注意到这种变化,在绑定对象时将不能获取到新值。 Naming Parameters 参数命名。 Let's take a quick visit to method parameters. What's the standard here? The guidelines are considerably more loose, but typically you prefix the input name with "the", "an" or "new" 让我们快速查看下方法的参数,这里的标准是什么?指导方针相当的宽松,但是具有代表性的输入参数带有"the", "an" 或者 "new"的前缀 Prefixes for Method Parameters - (void) setTitle: (NSString *) aTitle; - (void) setName: (NSString *) newName; - (id) keyForOption: (CDCOption *) anOption - (NSArray *) emailsForMailbox: (CDCMailbox *) theMailbox; - (CDCEmail *) emailForRecipients: (NSArray *) theRecipients; Also worth noting is the naming convention for a loop. Typically, the current object in the loop is prefixed with "one" or "a/an". Some also simply refer to the individual object as "item": 另外值得一提的是在循环中的命名规则。通常情况下,循环体重当前对象要加”one“”a/an“的前缀。也可以简单的命名这个对象为”item“ Variable Names in Loops 循环体中的变量命名规则 for (i = 0; i < count; i++) { oneObject = [allObjects objectAtIndex: i]; NSLog (@"oneObject: %@", oneObject); } NSEnumerator *e = [allObjects objectEnumerator]; id item; while (item = [e nextObject]) NSLog (@"item: %@", item); Odds and Ends 零碎的东西 If you're sending a message with a particularly long name, break it up into multiple lines: 如果消息方法名特别长,可以断成多行 Splitting Up Long Message Names color = [NSColor colorWithCalibratedHue: 0.10 saturation: 0.82 brightness: 0.89 alpha: 1.00]; Classes that return one and only one instance of themselves (singletons) are named and implemented as follows: 单件 一个类只返回有且仅有一个其自身的实例对象常常使用如下的命名和实现方式: Singleton @implementation CDCMailboxManager + (id) sharedMailboxManager { static CDCMailboxManager * shared = nil; if ( !shared ) { shared = [[self alloc] init]; } return shared; } |