学习objc时,尤为是先学过其余编程语言再来看objc时,总会对objc的类声明的关键字interface
感到有点奇怪,在其它面向对象的语言中一般由class
关键字来表示,而interface
在java中表示的却大约至关于objc的protocol
,这个关键字的区别究竟表明了objc语言的设计者怎样的思想呢,在objc类设计中须要注意哪些问题呢?接下来对这个问题进行一些思考和探究.java
先来段Wiki:c++
In object-oriented programming, a protocol or interface is a common means for unrelated objects to communicate with each other. These are definitions of methods and values which the objects agree upon in order to cooperate.git
接口约定了对象间交互的属性和方法,使得对象间无需了解对方就能够协做。
说的洋气点就是解耦
嘛,细心点也能发现Wiki中interface
和protocol
表示了相近的语义。
引用我和项目组架构师讨论有关interface的问题时他的说法:github
interface就是一个object定义的能够被外界影响的方式编程
说着他指了下旁边桌子上放着的一把伞,说,这把伞我能够打开它,打开这个动做就是它的一个interface,桌子旁边还放着一个盒子,虽然它和伞都放在这张桌子上,可是它们之间永远不会互相影响,因此:微信
interface只存在于能互相影响的二者间架构
学习objc时最先接触的就是怎么写一个类了,从.h
中写@interface
声明类,再从.m
中写@implementation
实现方法,因此,objc中写一个@interface
就至关于c++中写一个class
。但这是真的么?app
写个小test验证一下:
有两个类,Sark
和Dark
,Sark
类只有.m
文件,其中只写@implementation
;Dark
类只有.h
头文件,其中只写@interface
,而后以下测试代码:编程语言
1 |
Class sarkClass = NSClassFromString(@"Sark"); |
NSClassFromString
方法调用了runtime方法,根据类名将加载进runtime的这个类找出来,没有这个类就回返回空(Nil)。
结果是sarkClass
存在,而darkClass
为空,说明什么?是否说明其实@implementation
才是真正的Class?
进一步,不止能取到这个没有@interface的类,还能够正常调用方法(由于万能的runtime)ide
以下面的测试代码:
1 |
Sark *sark = [Sark new]; |
要是没有@interface
的声明,类名,方法名都会报错说找不到,可是能够像下面同样绕一下:
1 |
Class cls = NSClassFromString(@"Sark"); |
其实,从rewrite
后的objc代码能够发现,对于消息的发送,偏偏就是会被处理成相似上面的代码,使用字符串mapping出Class
,selctor
等再使用objc_msgSend()
进行函数调用,以下面所示:
1 |
// 通过clang -rewrite-objc 命令重写后的代码 |
@interface
咱们干过的事:
@implementation
咱们干过的和能够干的事:
在@implementation
干一些事情用的相对较少,可是是彻底合法的,如这样用:
1 |
@implementation Sark : NSObject { |
经过对比能够发现,@interface对objc类结构的合成并没有决定性做用,加上无决定性是由于若是没有@interface
会丢失一些类自省的原始数据,如属性列表和协议列表,但对于纯粹的对象消息发送并没有影响。
因此说,能够得出这么一个结论,objc中@interface就是为了给调用者看的,是和调用者的一个protocol,没错,就是protocol。
与其把@implementation
扯进来不如对比下@protocol
我理解objc的@interface
和@protocal
间惟一的区别就是是否和一个类型绑定,这让我想起来鸭子类型
(Duck typing), wiki连接
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就能够被称为鸭子。”
Duck type在objc的体现无疑就是@protocol
了,咱们经常使用id<XXXDelegate> delegate
的方式声明一个delegate,咱们无需care这货究竟是什么类型,咱们只知道他能干什么就能够work了。一样的功能我也可使用XXXDelegate *delegate
的方式来定义,只不过这样的话这个类又须要耦合一个XXXDelegate
类型,而这个delegate类是它本来并不须要关心的。
因此说,@interface
是@protocol
的强类型升级版。
举个NSObject
的栗子最合适:
1 |
@interface NSObject <NSObject> { |
NSObject之因此成为NSObject,绝大多数都是<NSObject>
协议定义的方法,实体类@interface定义的惟一一个变量isa
指针,为了继承链和消息传递。
除了<NSObject>
协议外,NSObject还有不少Category来补充它的功能,其实仔细想一想,Category更像protocol,一个补充协议
,一样不能添加实例变量,可是和@interface
同样须要与Class绑定。
进一步来说,自从属性能自动合成变量以后,在头文件@interface
中写大括号声明实例变量的状况愈来愈少(能够参见近几个版本iOS SDK中类头文件里这种写法几乎消失),所以,@interface
和@protocol
的差异进一步缩小。
我喜欢将Class
和interface
的关系比喻成电视+遥控器
,那么objc中的消息机制就能够理解成:
用户(caller)经过遥控器(interface)上的按钮(methods)发送红外线(message)来操纵电视(object)
因此,有没有遥控器,电视都在那儿,也就是说,有没有interface,class都是存在的,只是这种存在并无意义,就好像这个电视没人会打开,没人会用,没人能看,一堆废铁摆在那儿。
对比简洁的遥控器,一个拥有不少按钮的老式电视遥控器,咱们常常会用到的按钮能有几个呢?
因此,在设计一个类的interface的时候,如同在设计遥控器应该有怎样功能的按钮,要从调用者的角度出发,区分边界,应该时刻有如下几点考虑:
.h
中(而不是放在.m
的类扩展中)么?看过很多代码,从@interface设计上多少就能看出做者的水平,分享下我对于这个问题的一些拙见。
好比,有以下一个类(这个类无心义,主要关注写法):
1 |
// Sark.h |
这个interface出现的问题:
<NSXMLParserDelegate>
不该该在头文件@interface中声明,而应该在类扩展中声明;公开由外部调用的协议,如<NSCopying>
则写在这儿是正确的。实例变量
和IBOutlet
不该出如今这儿定义,这将类的内部实现暴露了出去,自从属性能够自动合成后,这里就更应该清净了。使用这个类或者对其进行修改时,通常都是从功能上找,因此把同一功能模块的一组属性或方法写在一块
Category
分块类扩展
将interface按功能分区Category
里不能添加实例变量,可是类扩展能够,通常都在.m
中做为私有interface使用,一样在头文件里做为分区使用,如,ReactiveCocoa中的RACStream.h
首先,类实现内部.m文件中使用的其余interface应该在.m文件import,若是也写在header中就会形成对调用者的污染;当interface中出现其余Class
或protocol
时,可使用前置声明@class XXX
, @protocol XXX
;当模块(一组类)内部间须要有一些定义(如常量、类型)而又不须要模块使用者知道时,使用一个内部头文件在模块中使用。
考虑调用者的使用方即是很必要的,过火了反而增长了复杂度:
1 |
@interface Sark : NSObject |
提供了一组这样的方法,调用者可能只能用到其中的一个,那这样倒不如只留一个接口。
单例模式当然好用,但感受有点过分,将接口设计成单例入口前须要考虑一下:
感谢@像条狗在飞
在留言中提出的问题,问题大概能够总结为:当子类须要使用父类的一个私有属性(方法)时,须要把这个属性(方法)放到父类的header中,但暴露给子类的同时暴露给了外部调用者,如何解决?
个人方案是:创建一个私有header
,使用类扩展
定义父类须要暴露给子类的属性(方法),而后在各自的.m
文件中引用,如:
有Father类和Son类,继承关系,能够考虑建一个如FatherPrivate.h
的私有header:
1 |
// FatherPrivate.h |
同时在Father.m和Son.m中同时import这个私有header,这样,Father和Son内部对于定义的属性和方法都是透明的,而对外部是隐藏的(由于两个类的header中都没有import这个私有header)
@implementation
合成了Class,而非@interface
,@interface
是@protocol
的强类型升级版,它们和Category
都表示了相近的含义最少知识原则
@interface
自己就是最好的文档http://en.m.wikipedia.org/wiki/Interface_(object-oriented_programming)
http://zh.wikipedia.org/wiki/%E9%B8%AD%E5%AD%90%E7%B1%BB%E5%9E%8B
原创文章,转载请注明源地址,blog.sunnyxx.com
原创文章,转载请注明原地址:blog.sunnyxx.com
对博主有意思?新浪微博@我就叫Sunny怎么了
or 微信搜索订阅号sunnyxx或扫下面的逗比狗