了解Cocoa和Objective-C一些特性

移动开发 iOS
本文介绍的是了解Cocoa和Objective-C一些特性,主要介绍了Cocoa和Objective-C相关的特性,来看本文详解。

了解CocoaObjective-C一些特性是本文要介绍的内容,对于Objective-C的一些特性,初学者应该好好的参考一番,文中介绍的夜很详细。不多说,我们来看内容。
 
1、成员变量应该定义为@private

参考代码:

  1. @interface MyClass : NSObject {  
  2.  @private  
  3.   id myInstanceVariable_;  
  4. }  
  5. // public accessors, setter takes ownership  
  6. - (id)myInstanceVariable;  
  7. - (void)setMyInstanceVariable:(id)theVar;  
  8. @end 

2、明确指定初始化

注释并说明指定的初始化。

明确指定初始化对想要子类化你的类的时候时很重要的。那样,子类化时只需要做一个或多个初始化去保证初值即可。这也有助于在以后调试你的类时明了初始化流程。

3、重写指定初始化

当重写一个子类并需要init...方法,注意要重写父类的指定初始化方法。

如果你没有正确重写父类的指定初始化方法,你的初始化方法可能不会被调用,这会导致很多微妙而难以排除的错误。

4、重写NSObject的方法

强烈建议在@implementation之后就立即重写NSObject 的方法。建议重写 init...,copyWithZone:和 dealloc 方法。init...相关的方法写在一起, 接下来是 copyWithZone: ,最后是 dealloc。

5、避免调用new方法

不要调用NSObject 的new方法,也不要在子类中重写它,而是应该使用 alloc 和 init 方法来初始化retained的对象。

Objective-C代码显式调用 alloc 和 init 方法来创建和retain一个对象。new 的方法可能会带来内存上调试的麻烦。

6、初始化变量

没必要在初始化方法里把变量初始化为0或者nil,这是多余的。

所有新分配内存的对象内容都初始化为0(除了isa),所以不要在init方法里做无谓的重初始化为0的操作。

7、保持公有API简明

保持你的类简单,如果一个方法没必要公开就不要公开。使用私有类别保证公开头文件的简洁。

和C++不同,Objective-C无法区分公有私有方法,因为它全是公有的。因此,除非就是为了让用户调用所设计,不要把其他的方法放到公有API里。这样可以减少不期调用的可能性。这还包括重写父类的方法。对于那些内部实现的方法,在实现文件里使用类别而不是将方法定义在公有头文件里。

  1. // GTMFoo.m  
  2.  
  3. #import "GTMFoo.h"   
  4. @interface GTMFoo (PrivateDelegateHandling)  
  5. - (NSString *)doSomethingWithDelegate;  // Declare private method  
  6. @end  
  7. @implementation GTMFoo(PrivateDelegateHandling)  
  8. ...  
  9. - (NSString *)doSomethingWithDelegate {  
  10.   // Implement this method  
  11. }  
  12. ...  
  13. @end 

8、#import和#include

用#import导入Objective-C或Objective-C++头文件,用#include导入C或C++头文件

根据头文件的语言去选择合适的导入方式。

当导入的头文件使用Objective-C或Objective-C++语言时,使用#import。

当导入标准C或C++头文件时,使用#include。头文件应该使用自己的#define重加载保护。

有些Objective-C头文件没有#define重加载保护,所以只应该用#import导入。因此Objective-C头文件只应该被Objective-C源文件或其他的Objective-C头文件所导入。这种情况下全部使用#import是合适的。

标准C和C++头文件不包含任何Objective-C元素都可以被一般的C或C++文件导入。因为标准C和C++里根本没有#import,所以也只能用#include导入。在Objective-C代码中使用#include一致的导入这些头文件。

本条款有助于跨平台项目的无意错误。一位Mac开发者引入一份新C或C++头文件时可能会忘记添加#define重加载保护,因为在Mac上用#import导入文件不会引发问题,但在别的使用#include的平台就可能出问题。在所有平台一致的使用#include意味着要么全部成功要么全部失败,避免了那种一些平台上可以运作而另一些不行的情况。

  1. #import <Cocoa/Cocoa.h> 
  2. #include <CoreFoundation/CoreFoundation.h> 
  3. #import "GTMFoo.h"  
  4. #include "base/basictypes.h" 

9、使用根框架

导入框架根的头文件而不是分别导入框架头文件

看起来从Cocoa或Foundation这些框架里导入个别的文件很不错,但实际上你直接导入框架根头文件效率更高。框架根已经被预编译故可更快的被加载。还有,记住用#import指令而不是#include导入Objective-C的框架。

  1. #import <Foundation/Foundation.h>     // good  
  2. #import <Foundation/NSArray.h>        // avoid  
  3. #import <Foundation/NSString.h> 

10、构建时即设定autorelease

当创建新的临时对象时,在同一行代码里就设定autorelease而不是写到这个方法的后面几行去

即使这样可能会造成一些轻微的延迟,但这样避免了谁不小心把release去掉,或在release之前就return而造成的内存泄露,如下:

  1. // AVOID (unless you have a compelling performance reason)  
  2. MyController* controller = [[MyController alloc] init];  
  3. // ... code here that might return ...  
  4. [controller release];  
  5. // BETTER  
  6. MyController* controller = [[[MyController alloc] init] autorelease]; 

11、优先autorelease而非retain

对象赋值时尽量采用autorelease而不是retian模式。

当把一个新创建的对象赋予一个变量的时候,第一件要做的事情就是先释放原来变量指向的对象以防止内存泄露。这里也有很多"正确的"方法去做这件事。我们选择autorelease时因为它更不倾向于出错。小心在密集的循环里可能会很快填满autorelease池,而且它也确实会降低效率,但权衡下来还是可以接受的。

  1. - (void)setFoo:(GMFoo *)aFoo {  
  2.   [foo_ autorelease];  // Won't dealloc if |foo_| == |aFoo|  
  3.   foo_ = [aFoo retain];  

12、以声明时的顺序dealloc处理实例变量
dealloc应该用在@interface声明时同样的顺序处理实例变量,这也有助于评审者鉴别。

代码评审者检查或修正dealloc的实现要确保所有retain的实例变量都获得了释放。

为了简化评审dealloc,将释放retain的实例变量代码保持和@interface里声明的顺序一致。如果dealloc调用了其他方法去释放实例变量,添加注释说明那些实例变量被这些方法所处理了。

13、Setters copy NSStrings

在NSString上调用Setters方法时,永远使用copy方式。永远不要retain一个字符串,这可以防止调用者在你不知到的情况下修改了字符串。不要以为你可以改变NSString的值,只有NSMutableString才能做到。

  1. - (void)setFoo:(NSString *)aFoo {  
  2.   [foo_ autorelease];  
  3.   foo_ = [aFoo copy];  

#p#

14、避免抛出异常

不要@throwObjective-C的异常,不过你还是要做好准备捕获第三方以及系统调用抛出的异常。

我们的确在编译时加入了-fobjc-exceptions指令(主要是为了获得@synchronized),但我们并不@throw。当然在使用第三方库的时候是允许使用@try,@catch,以及@finally的。如果你确实使用了,请务必明确到文档中哪个方向你想抛出什么异常。

除非你写的代码想要泡在MacOS10.2或更之前,否则不要使用NS_DURING,NS_HANDLER,NS_ENDHANDLER,NS_VALUERETURNandNS_VOIDRETURN这些宏。

另外你要小心当写Objective-C++代码的时候,如果抛出Objective-C异常,那些栈上的对象不会被清理。示例:

  1. class exceptiontest {  
  2.  public:  
  3.   exceptiontest() { NSLog(@"Created"); }  
  4.   ~exceptiontest() { NSLog(@"Destroyed"); }  
  5. };  
  6. void foo() {  
  7.   exceptiontest a;  
  8.   NSException *exception = [NSException exceptionWithName:@"foo"  
  9.                                                    reason:@"bar"  
  10.                                                  userInfo:nil];  
  11.   @throw exception;  
  12. }  
  13. int main(int argc, char *argv[]) {  
  14.   GMAutoreleasePool pool;  
  15.   @try {  
  16.     foo();  
  17.   }  
  18.   @catch(NSException *ex) {  
  19.     NSLog(@"exception raised");  
  20.   }  
  21.   return 0;  

将会有如下输出:

  1. 2006-09-28 12:34:29.244 exceptiontest[23661] Created  
  2. 2006-09-28 12:34:29.244 exceptiontest[23661] exception raised 

注意这里的析构函数永远没有机会被调用。这是在你想用栈上的智能指针比如shared_ptr,linked_ptr,还有STL对象的时候不得不关注的一个核心问题。如果你一定要在Objective-C++代码里抛出异常,那就请一定使用C++的异常。永远不要重新抛出一个Objective-C的异常,也不允许在异常块即@try,@catch,@finally里生成栈上的C++对象(比如std::string,std::vector等)。

15、nil检查

仅在校验逻辑流程时做nil检查。

使用nil检查不是为了防止程序崩溃,而是校验逻辑流程。向一个空对象发送一条消息是由Objective-C运行时处理的。方法没有返回结果,你也可以安心走下去。

注意这里和C/C++的空指针检查是完全不同的,在那些环境里,并不处理空指针情况并可能导致你的应用程序崩溃。不过你仍要自己确保提领的指针不为空。

16、 BOOL类型陷阱

整形的转换为BOOL型的时候要小心。不要直接和YES做比较。

BOOL在Objective-C里被定义为unsignedchar,这意味着它不仅仅只有YES(1)和NO(0)两个值。不要直接把整形强制转换为BOOL型。常见的错误发生在把数组大小,指针的值或者逻辑位运算的结果赋值到BOOL型中,而这样就导致BOOL值的仅取决于之前整形值的最后一个字节,有可能出现整形值不为0但被转为NO的情况。应此把整形转为BOOL型的时候请使用ternery操作符,保证返回YES或NO值。

在BOOL,_BOOL以及bool(见C++Std4.7.4,4.12以及C99Std6.3.1.2)之间可以安全的交换值或转型。但BOOL和Boolean之间不可,所以对待Boolean就像上面讲的整形一样就可以了。在Objective-C函数签名里仅使用BOOL。

对BOOL值使用逻辑运算(&&,||,!)都是有效的,返回值也可以安全的转为BOOL型而不需要ternery操作符。

  1. - (BOOL)isBold {  
  2.   return [self fontTraits] & NSFontBoldTrait;  
  3. }  
  4. - (BOOL)isValid {  
  5.   return [self stringValue];  
  6. }  
  7. - (BOOL)isBold {  
  8.   return ([self fontTraits] & NSFontBoldTrait) ? YES : NO;  
  9. }  
  10. - (BOOL)isValid {  
  11.   return [self stringValue] != nil;  
  12. }  
  13.  
  14. - (BOOL)isEnabled {  
  15.   return [self isValid] && [self isBold];  

还有,不要把BOOL型变量直接与YES比较。这样不仅对于精通C的人很有难度,而且此条款的第一点也说明了这样做未必能得到你想要的结果。

  1. BOOL great = [foo isGreat];  
  2. if (great == YES)  
  3.   // ...be great!  
  4. BOOL great = [foo isGreat];  
  5. if (great)  
  6. // ...be great! 

17、属性

属性遵循如下规则:属性是Objective-C2.0的特性,所以只能跑在iPhone以及MacOSX10.5(leopard)或更高的版本。

一个有属性关联实例变量都要在后面加下划线,而该属性的名称就是实例变量不加尾部的下划线的名字。

使用@synthesize标识以正确的重命名属性。

  1. @interface MyClass : NSObject {  
  2.  @private  
  3.   NSString *name_;  
  4. }  
  5. @property(copy, nonatomic) NSString *name;  
  6. @end  
  7. @implementation MyClass  
  8. @synthesize name = name_;  
  9. @end 

属性的声明必须紧接变量申明的括号后。属性的定义应该紧接@implementation模块后面。它和@interface 或者@implementation 的缩进是相同的。

  1. @interface MyClass : NSObject {  
  2.  @private  
  3.   NSString *name_;  
  4. }  
  5. @property(copy, nonatomic) NSString *name;  
  6. @end  
  7. @implementation MyClass  
  8. @synthesize name = name_;  
  9. - (id)init {  
  10. ...  
  11. }  
  12. @end 

18、为NSString使用Copy属性

NSString的属性定义为copy。

如果自己实现setters方法,也请使用copy而不是retain。

小结:了解CocoaObjective-C一些特性的内容介绍完了,希望本文对你有所帮助!

责任编辑:zhaolei 来源: 互联网
相关推荐

2011-08-01 11:49:05

Objective-C

2011-07-28 18:11:18

Objective-C Cocoa 编程

2011-05-11 15:19:01

CocoaObjective-C

2012-01-18 10:13:50

Objective-CiOSself

2011-07-19 13:49:19

Objective-C 数据类型

2011-08-15 16:09:44

Cocoa对象Objective-C

2011-07-07 17:17:23

Objective-C

2013-07-24 19:19:03

Objective-CiOS开发动态特性之protoc

2014-11-25 10:18:17

Objective-C

2011-08-05 15:56:03

Objective-C 消息 函数

2011-07-22 15:10:51

Objective-C 文件

2011-08-01 11:37:41

iPhone Objective- 内存

2011-06-27 15:48:09

Cocoa TouchObjective-C

2011-07-26 10:50:50

Objective-C Selector

2015-11-02 10:13:41

iOSObjective-C语法

2011-12-12 13:22:51

CocoaObjective-C

2011-08-02 15:55:31

Objective-C NSAutorele

2015-07-08 10:47:57

Using Swift CocoaObjective-C

2013-05-02 10:51:17

iOS开发Objective-C@property

2011-07-26 09:19:27

Objective-C 重载
点赞
收藏

51CTO技术栈公众号