【Android基础学IOS开发】从Java转向Objective-c

和C++一样,Java含有很多Objective-C所不具备的特性和不同的实现方法。例如,传统的Objective-C没有垃圾回收器,却含有保留/释放方法和自动释放池。必要时,也可以在Objective-C程序中进行垃圾回收。

Java接口与Objective-C正式协议类似,因为它们都需要实现一组方法。Java具有抽象类,而Objective-C没有。Java具有类变量,但在Objective-C中,可以使用文件范围内的全局变量并为它们提供对应的访问器,具体内容请参考A.2部分。Objective-C的公共和私有方法的形式比较松散。我们已经说过,在Objective-C中,对象支持的任何方法都可以被调用,即使它们没有以任何外部形式出现(例如头文件中)。Java允许声明final类,以防止子类的内容被更改。而Objective-C则与此相反,允许在运行时向任何类添加方法。

通常,Objective-C中类的实现方式可以分成两个文件:头文件和自身的实现文件,但并不是一定要这样划分(例如某些小的私有类),这在本书中的某些代码中已经有所反映。头文件(带有.h扩展名)保留类的公开信息,比如调用此类的代码将使用任何新的枚举、类型、结构以及代码。其他代码段使用预处理器(使用#import)导入该文件。Java中缺少C语言的预处理器。C预处理器是一种文本替换工具,它能在C、Objective-C和C++源代码进入编译器之前,先对它们进行自动处理。以#开头的指令表示一个预处理器命令。

C预处理器实际上并不知道C语言家族的具体机制,它只是完成一些看不见的文本替换工作。预处理器是一个功能非常强大但又危险的工具。很多编程人员都认为Java中缺少预处理器正是它的特色所在。

在Java中,几乎所有错误都是通过异常来处理的。而在Objective-C中,错误处理的方式取决于所使用的APIUnix API通常会返回值1和一个全局错误编号(errno),以设置某个特定的错误。Cocoa API通常只在编程人员出现错误或无法清除时才抛出异常。

Objective-C语言提供的异常处理特性与Java及C++类似,采用@try@catch@finally结构。

在Objective-C中,空(零)对象使用nil表示。可以向nil对象发送消息,而不必担心出现NullPointerException异常。向nil对象发送的消息代表停止操作指令,因此,不必检查发送的消息是否为NULL。向nil发送消息的具体内容请参考“从C++转向Objective-C”一部分。

在Objective-C中,通过使用类别向现有类添加方法,可以改变类的行为。Objective-C中没有类似于final的类。因为编译器需要知道超类定义的对象大小,所以任何类只要包含子类头文件,就可以设置为子类。

实际上,相对于Java而言,在Objective-C中很少使用子类化行为。通过类别和动态运行时机制,可以向任何对象发送任何消息,所以可以将某些功能放到含有较少功能的类中,也可以放到最有意义的类中。例如,可以在NSString上加入类别来添加反转字符串或删除所有空格等特性,然后可以在任何NSString类中调用该方法,无论调用来自何处。当然你也可以使用自己的字符串子类来提供这些特性。

一般来说,只有当创建某个全新的对象(位于对象层次结构的顶部),需要从根本上改变某个对象的行为,或者由于类不能实现某个功能而需要使用子类时,才需要在Cocoa中设置子类。例如,Cocoa使用NSView类构造用户界面组件,却无法实现它的drawRect:方法。因此,需要设置NSView的子类并重写drawRect:方法来绘制视图。但对其他大多数对象,通常采用委托和数据源的方法。由于Objective-C可以向任何对象发送任何消息,对象不必含有特定的子类或遵从特定的接口,这样,单个类就可以成为任意个不同对象的委托和数据源。

因为类别中已经声明了数据源和委托方法,因此不必实现。在Objective-C中,Cocoa编程很少使用空存根方法,某些方法会在嵌入式对象中调用相同的方法来使编译器顺利地适应一种正式协议。

当然,功能越强,责任越大。Objective-C采用手动保留、释放和自动释放的内存管理系统,这样更容易产生棘手的内存错误。在其他类中添加类别是一种功能强大的工作机制,但如果随意滥用,会降低代码的可读性,导致其他人无法理解。另外,Objective-C是以C语言为基础的,因此,在获得C语言的所有强大功能的同时,你也会面临处理器可能带来的危险,包括与指针相关的内存管理错误。