Objective-C 的Cocoa风格:第二部分
概括地说就是Cocoa和Objective-C看起来应该是什么样的?
一旦了解了Objective-C和Cocoa的基础你就可以开始写些代码了。但是Objective-C的命名和格式规则不同于传统的C、C++以及Java程序。
Apple为了实现最大的清晰性和与框架的集成性订立利用一系列的指导原则。此外还有Cocoa开发人员经常使用的未成文规则。
从根本上说在Objective-C和Cocoa可以找到Apple为最终用户设计的产品中的人的因素。
第1部分: 类、变量、访问函数、通用方法和缩写的命名基础。
第2部分: 关于方法名、全局符号、ID类型、方法参数等等的更详细的介绍。
方法名:返回对象
除了简单的访问函数外,类和对象也会基于不同的条件或输入返回对象。格式很简单:
[object/class thing+condition]; [object/class thing+input:input]; [object/class thing+IDentifer:input];
示例:
realPath = [path stringByExpandingTildeInPath]; fullString = [string stringByAppendingString:@"Extra Text"]; object = [array objectAtIndex:3]; // 类方法
newString = [Nsstring stringWithFormat:@"%f",1.5];
newArray = [NSArray arrayWithObject:newString];
我自己写的一些例子如下:
recipIEnts = [email recipIEntsSortedByLastname]; newEmail = [CDCEmail emailWithSubjectline:@"Extra Text"]; emails = [mailBox messagesReceivedAfterDate:yesterdayDate];
请注意所有的消息首先都表明会返回什么,紧接着是返回它需要的环境。还要注意的是冒号前的最后一个单词描述了指定参数的类型。
有时你需要一个值的变种。在这样情况下,格式通常是:
[object 形容词+thing]; [object形容词+thing+条件]; [object形容词+thing+输入:input];
示例:
cAPItalized = [name cAPItalizedString]; rate = [number floatValue]; newString = [string decomposedStringWithCanonicalmapPing]; subarray = [array subarrayWithRange:segment];
通常消息不会像-decomposedStringWithCanonicalmapPing这么长。
避免歧义
如果代码让一切都很明白BUG就无处藏身了。
//有歧义的消息 -sortInfo -refreshTimer -update -fetchInfo:
表明上看这些方法还不错。比如它们都有动词。但是它们有一个共同点就是使用的语言会造成歧义。
-sortInfo – 返回排序信息,还是给信息排序? -refreshTimer – 返回用于刷新的定时器,还是刷新定时器? -update – 就一个动词?更新什么,并如何更新? -fetchInfo – 获取某些东西的信息还是给出一个获取动作的信息?
这些都可以通过如下所示的稍微的修改避免。
//清晰的消息 -currentSortInfo // "current"很明显地指明"sort info"是名词 -refreshDefaultTimer // 现在refresh显然是动词 -updateMenuItemTitle // 执行了一个动作 -infoForFetch: //现在我们可以知道info是一次fetch的返回值
仅仅给每个方法加上几个字符我们就避免了歧义。这确实很值得高兴。
注意-updateMenuItem 方法没有在menu item 前加入NS前缀。
全局C函数
全局C函数通常使用如下几个简单的格式中的一个。
前缀+值() 前缀+值+With/From/For+输入() 前缀+动作() 前缀+动作+ 类型()
和类一样,函数也会带有首字母来防止命名空间冲突问题。由于C函数的自立性,函数名必须指明和它交互的数据类型(如果有的话)。
//Cocoa中的函数 NSHomeDirectory() NSHomeDirectoryForUser() NSClassFromString() NSBeginAlertSheet() NSDrawGrayBezel()
核心服务函数
在诸如Core Foundation和Core Graphic的核心服务框架中函数带有最关联类型的前缀,即使没有涉及到间接也会用到"get"前缀:
//核心函数 CFArrayGetValueAtIndex() // 直接返回,不过还是使用"get" CFDictionaryGetValue() CFDateGetabsoluteTime() //Core Graphics / Quartz CGImageCreate() CGImageGetHeight() CGImageGetTypeID()
其他全局符号
除了C函数外还有一些需要全局符号的几个类型。比如:
•常量
•类型定义的结构体
•类型定义的枚举
•单独枚举值
•Objective-C协议
协议、常量、结构体、枚举和枚举值根据和类以及C函数一样的规则命名。首字母需要大写:
//结构体 NSPoint point; // 结构体 NSRange range; // 结构体 NSRectArray * rects; // C风格的struct数组
在Cocoa中会经常使用到枚举作为方法的"模式"。
range = [string rangeOfString:@"find me" options:NSliteralSearch];
常量和枚举都有一个可以表明它们的后缀。
//常量和枚举 //搜索模式(枚举) NSliteralSearch NSCaseInsensitiveSearch //异常名(常量) NSMallocException NSinvalidargumentexception //通知名(常量) NSTaskDIDTerminateNotification NSWindowWillMoveNotification
同时请注意通知名有一个稍微不同的格式:
受影响的对象类 + DID/Will + 动作 + "Notification"
动态类型
Objective-C是动态类型语言,意味着你不需要在编译时告诉编译器你所 *** 纵的对象是什么类型。
为一个变量声明一个类型仅仅是一个承诺,它在代码留有空间的情况下可能会被破坏。你可以将一个变量声明为ID类型,这对于任何Objective-C对象都是可行的。
// 动态类型变量 ID hostname; ID ipAddress; ID keyedAccountnames; ID theObject; //编译器允许这样 theObject = [Nsstring string]; theObject = [NSNumber numberWithInt:1]; theObject = [NSDictionary dictionary];
那为什么需要指定类型呢?有三个基本原因:
1.清晰: 使得变量在你想使用的时候清晰明了。
2.避免无用警告: 如果多个类有相同的方法名,编译器在你发送消息到一个泛型对象上时会警告。
3.获得有用警告:如果你拼错消息们名,比如"-stringg",编译器会告诉你NSMutableString没有实现该方法。
不过在有些情况下ID类型最合理。比如:
1.委托(delegate)或则数据源(datasource)
2.通知所用的对象
3.泛型容器的内容
4.目标/动作(target/action)中涉及的对象
所以这里没有硬性规定,一个好的基本做法就是在一个特定情况下如果你有理由确信不可能是其他类型那就为其指定类型。
使用访问函数的时机是什么?
简短的回答就是:一直
为什么不直接访问类中的实例变量呢?不是代码可以更少吗?
原因就是灵活性。如果你的代码通过访问函数获取数据,之后可以很容易更改数据的处理方式。
比如,NSUndoManager提供了一个注册先前值的一个很好的入口点,在调试的时候它可以帮助你在获取某个实例变量的时候记录它。
还有一个创建访问函数更重要的原因:键-值-编码(Key-Value Coding KVC)。KVC是Cocoa中普遍使用的协议,最明显地就是用在绑定(Binding)上。它会首先查找你的键所对应的访问函数,只有在最后才可能直接访问数据。你可以通过实现访问函数缩短KVC的搜索路径和加速数据访问。
此外你如果通过var = value的形式直接设定实例变量,正在观察的键-值就不会注意到变更,被绑定对象也不会获得新的值。
命名参数
让我们简单看看方法参数。标准又是什么呢?指导方针相对宽松,基本上就是在输入名前加入"the"、"an"或"new"。
//方法参数的前缀 - (voID) setTitle: (Nsstring *) aTitle; - (voID) setname: (Nsstring *) newname; - (ID) keyForOption: (CDcoption *) anoption - (NSArray *) emailsForMailBox: (CDCMailBox *) theMailBox; - (CDCEmail *) emailForRecipIEnts: (NSArray *) theRecipIEnts;
同时注意循环中的命名规则。通常,给当前对象加"one"或者"a/an"的前缀。有些就直接通过"item"来引用单个对象:
//循环中的变量名 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);
其他
如果你发送一个很长名字的消息,将其拆分成多行。
//拆分长的消息名 color = [NScolor colorWithCalibratedHue: 0.10 saturation: 0.82 brightness: 0.89 Alpha: 1.00];
仅返回单个实例的类(单例类)可以按如下所示的命名和实现:
//单例 @implementation CDCMailBoxManager + (ID) sharedMailBoxManager { static CDCMailBoxManager * shared = nil; if ( !shared ) shared = [[self alloc] init]; return shared; }
小结
如果你已经看过第一部分,你就可以开始写看起来和感觉起来像Cocoa的代码。如果你还想了解更多的风格,务必查看如下链接给出的Apple编程指导原则。
老规矩,如果对本教材有任何想法请告诉我们。
进一步阅读:
Objective-C的Cocoa风格:第一部分 本教材第一部分
Cocoa指导原则 Cocoa编程指导原则的权威文档
Objective-C命名 Apple针对该语言规则的简述
原文链接:http://cocoadevcentral.com/articles/000083.php
以上是内存溢出为你收集整理的Objective-C 的Cocoa风格:第二部分全部内容,希望文章能够帮你解决Objective-C 的Cocoa风格:第二部分所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)