读书人

Objective-C 2.0 with Cocoa Foundati

发布时间: 2012-06-29 15:48:46 作者: rapoo

Objective-C 2.0 with Cocoa Foundation--- 8,类方法以及私有方法
8,类方法以及私有方法

本系列讲座有着很强的前后相关性,如果你是第一次阅读本篇文章,为了更好的理解本章内容,笔者建议你最好从本系列讲座的第1章开始阅读,请点击这里。

?

Objective-C里面区别于实例方法,和Java或者C++一样,也支持类方法。类方法(Class Method) 有时被称为工厂方法(Factory Method)或者方便方法(Convenience method)。工厂方法的称谓明显和一般意义上的工厂方法不同,从本质上来说,类方法可以独立于对象而执行,所以在其他的语言里面类方法有的时候被称为静态方法。就像@interface曾经给我们带来的混乱一样,现在我们就不去追究和争论工厂方法的问题了,我们看到Objective-C的文章说工厂方法,就把它当作类方法好了。

?

在Objective-C里面,最受大家欢迎的类方法应该是alloc,我们需要使用alloc来为我们的对象分配内存。可以想象,如果没有alloc,我们将要如何来为我们的类分配内存!

?

和其他的语言类似,下面是类方法的一些规则,请大家务必记住。

?

1,类方法可以调用类方法。

2,类方法不可以调用实例方法,但是类方法可以通过创建对象来访问实例方法。

3,类方法不可以使用实例变量。类方法可以使用self,因为self不是实例变量。

4,类方法作为消息,可以被发送到类或者对象里面去(实际上,就是可以通过类或者对象调用类方法的意思)。

?

如果大家观察一下Cocoa的类库,会发现类方法被大量的应用于方便的对象创建和操作对象的,考虑到类方法的上述的特性,同学们在设计自己的类的时候,为了谋求这种方便,可以考虑使用类方法来创建或者操作对象。笔者认为,这个就是类方法的潜规则,在本章的范例程序里面,笔者将要遵守这个潜规则。

?

在上一章我们讲了一下实例变量的作用域,实例变量的作用域的方式和其他面向对象的语言没有什么不同。对于方法,非常遗憾的是,Objective-C并没有为我们提供诸如public,private和protected这样的限定,这就意味着在Objective-C里面,从理论上来说所有的方法都是公有的。但是,我们可以利用Objective-C的语言的特性,我们自己来实现方法的私有化。当然我们自己的私有化手段没有得到任何的编译器的支持,只是告诉使用者:“这是一个私有的方法,请不要使用这个方法”。所以,无论作为类的设计者和使用者都应该清楚在Objective-C里面的方法私有化的所有手段,这样就在类的设计者和使用者之间达成了一种默契,这种方式明显不是Objective-C语法所硬性规定的,所以也可以把这种手法成为一种潜规则。

?

关于潜规则经常看英文文档的同学,应该可以遇到这样一个词,de facto standard,也就是笔者所说的潜规则。

?

本章所述的方法的私有化是一种有缺陷的手段,有一定的风险而且也没有完全实现私有化,在后面的章节里面笔者会陆续的给出其他的实现方法私有化的方法。

?

另外,Objective-C里面有一个其他不支持指针的语言没有的一个动态特性,那就是程序在执行的时候,可以动态的替换类的手段。动态的方法替换有很多种应用,本章实现了一个类似java里面的final函数。和final函数不同的是,如果子类重写了这个方法,编译器不会报错,但是执行的时候总是执行的你的超类的方法。

?

类方法,方法私有化和动态方法替换将是本章的主题。

8.1,本章程序的执行结果

在本章里面,我们将要继续使用我们在第4章已经构筑好的类Cattle和Bull。

?

笔者在这里暂时违反一下不修改已经生效的代码规则改写了一下Cattle和Bull类,在里面追加了一些类方法,用于创建Cattle系列的对象。

?

笔者也改写了Cattle的头文件用来实现方法的私有化。

?

面向对象的程序有一个很大的特色就是动态性,但是由于某种原因我们在设计超类的时候,也许会考虑把某个方法设定成为静态的,这样就有了诸如final的概念。在本章我们将要使用动态的方法替换来实现这个功能。我们将要构筑一个新类,名字叫做UnknownBull,我们使用动态方法替换导致即使UnknownBull重载了Cattle类的saySomething,但是向UnknownBull发送saySomething的时候,仍然执行的是Cattle的saySomething。本章程序的执行结果请参照下图:

?

Objective-C 2.0 with Cocoa Foundation- 八,类方法以及私有方法?

图8-1,本章程序的执行结果。

?

本章程序可以点击这里下载。

8.2,实现步骤

第一步,按照我们在第2章所述的方法,新建一个项目,项目的名字叫做07-InitWithAndIvarScope。如果你是第一次看本篇文章,请到这里参看第二章的内容。

?

第二步,按照我们在第4章的4.2节的第二,三,四步所述的方法,把在第4章已经使用过的“Cattle.h”,“Cattle.m”,“Bull.h”还有“Bull.m”, 导入本章的项目里面。

?

第三步,打开“Cattle.h”和“Cattle.m”,分别修改成为下面的代码并且保存:

typedef struct objc_method *Method;struct objc_method {  SEL method_name;  char *method_types;  IMP method_imp;};
??

其中SEL和IMP我们已经很熟悉了,method_types是方法的类型信息,Objective-C使用一些预定义的宏来表示方法的类型,然后把这些信息放到method_types里面。

?

需要强调的是,苹果在10.5之后就降级了很多Objective-C 底层的函数,并且在64位的应用当中使得这些函数失效,笔者对剥夺了众多程序员的自由而感到遗憾。

?

第14行的代码,我们把子类的函数指针的地址替换成为Cattle类的saySomething,这样无论子类是否重写saySomething, 执行的时候由于runtime需要找到方法的入口地址,但是这个地址总是被我们替换为Cattle的saySomething,所以子类通过 cattleWithLegsCountVersionD取得对象之后,总是调用的Cattle的saySomething,也就实现了final。当 然,这种方法有些粗鲁,我们强行的不顾后果的替换了子类的重写。

?

重要本节提到的final的实现方法,没有任何苹果官方的文档建议这样做,纯属笔者自创仅供大家参考,如果使用风险自担。

?

替换的结果,就是虽然我们在“08-Class_Method_And_Private_Method.m”里面的cattle[4]l里面使用UnknownBull是图返回UnknownBull对象,我们也确实得到了UnknownBull对象,但是不同的是,我们在cattleWithLegsCountVersionD里面狸猫换太子,把UnknownBull的saySomething变成了Cattle的saySomething。

?

让我们回到图8-1,我们发现最后一行的输出为Cattle的saySomething。

?

关于final的实现方式,我们当然可以使用一个文明的方法来告知子类的使用者,我们不想让某个方法被重写。我们只需要定义一个宏

?

#define?FINAL

类的使用者看到这个FINAL之后,笔者相信在绝大多数时候,他会很配合你不会重写带FINAL定义的方法的。

8.5,本章总结

我们在本章里面讲述了方法私有化,类方法的定义和使用,动态方法替换等技术手段,也给大家强调和澄清了self的概念。
更重要的是,笔者向大家介绍了一些潜规则,希望大家可以遵守。
非常感谢大家这些天对我的鼓励以及支持!

?

来源:http://www.cnblogs.com/yaski/archive/2009/04/29/1444035.html

?

?

?

前置加号(+)的方法为类方法,这类方法是可以直接用类名来调用的,它的作用主要是创建一个实例。前置减号(-)的方法为实例方法,必须使用类的实例才可以调用的。

?

?

?

?

读书人网 >移动开发

热点推荐