十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
关于API的设计与实现
创新互联建站长期为1000+客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为李沧企业提供专业的成都网站制作、做网站,李沧网站改版等技术服务。拥有十多年丰富建站经验和众多成功案例,为您定制开发。
API的设计是软件开发中一个独特的领域。
特殊点在于API是供开发者使用的界面,即Application Programmer Interfaces。类似于用户可以直接使用到的GUI的作用一样。所以相对于依据软件设计的原则,考虑用户的”体验”会更加重要。
狭义上API可能只是一个动态库(共享库)提供功能的接口定义。广义上API分为public API,以及internal API之分。既有整体软件系统对外输出的接口(包括与设备通讯的接口),也有系统内一个底层模块提供给上层模块使用的接口定义。
对于一般的开发任务,常常思考的是保证功能的正确性和设计的完美,可以不断尝试做创新和重构。但这些原则放到API设计上就不一定正确了,反而需要有些保守。
一.基本知识
iPhone中的API除了公开的 API:Published API外(或者叫文档中记录的API:Documented API),还有两类API:私有API:Private API和未公开的API:UnPublished API(或者叫文档中未记录的API:Undocumented API)。其中私有API是指放在PrivateFrameworks框架中的API,未公开的API是指虽然放在Frameworks框架中,但是却没有在苹果的官方文档中有使用说明、代码介绍等记录的API。后两种API是有区别的,按苹果的说法,未公开的API是还不够成熟,可能还会变动的API,等完全成型了后会变成公开的API,但是目前不对其提供承诺,就是系统版本升级后可能会失效。而私有API是苹果明确不能使用的API。虽然两者有所区别,但是在具体使用方法上是类似的。
二.具体介绍
1.导出生成私有API的头文件声明
使用私有或未公开的API,首先需要导出其对应的头文件,在头文件里有相关函数的声明。
工具:
class-dump
class-dump可以从编译后的Objective-C的二进制文件中提取对应的数据结构及函数等声明。
使用方法:
为了能在任意目录下使用class-dump命令,首先建议把class-dump文件拷贝到/user/local/bin/目录下,然后就可以在任意目录下执行以下命令:
class-dump /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator3.0.sdk/System/Library/Frameworks/UIKit.framework/ UIKit.h
以上命令就可以把 iPhoneSimulator3.0.Sdk中Frameworks框架里的UIKit.Framework框架的数据结构及函数声明等给提取出来,并且放在UIKit.h这个文件中,之后你就可以在这个头文件中找需要API的声明及其使用方式。以同样的方法,就可以挨个导出你需要那个框架中的API 声明。
也可以用ericasadun写的DumpFrameworks.pl(文件中有部分注释说明)这个文件把私有框架下的API头文件全部提取出来。使用方法也是首先把class-dump文件拷贝到/user/local/bin/目录下,然后在任意一个目录下执行./DumpFrameworks.pl,然后就会在家目录下产生一个Headers文件夹,里面罗列了私有框架下的API头文件。
2.使用私有API
导出了私有API的头文件声明后,使用方法就比较简单了,首先在工程中包含进头文件,然后导入对应的框架,之后就可以类似提供了静态库的方式在代码中使用这些私有API函数。
三.附加说明
iPhone编程中一些非常精致好玩的API都包含在私有API或未公开的API中,虽然可以以这种方式使用这些非常好的API,但是这样做是存在一定风险的,首先为公开的API有变更的可能,这样在每个固件版本中,代码都有可能中断。同时,最大的问题是使用了私有API的程序是不能放在App Store上销售的。因此如果只是为了好玩体验iPhone中这些精彩的API,那没关系。如果是为了做出程序放在App Store上销售的,那就不要动私有API的主意了。
runtime 在iOS中是“运行时”的含义,是一套用c语言写的api,很多人会用但是也仅仅用过最最常用的几个函数,这次,我将详细的带着大家探索下 runtime 的API,这一章就说下 objc/runtime.h 这个文件里的 API ,并且我会把不适用于 ARC 和不支持64位的API剔除掉。
首先,我们先看一个简单的函数:
这个函数是通过传入 Class 类型的 cls 来得到 Class 的名字。那我们测试下这个函数:
其中 [Person class] OC中获得 Class 的方法,当然,你也可以用 runtime 里面的 objc_getClass 等函数,后面我也会讲到。
运行结果:
我们可以看到打印出来的结果就是类的名字。
上面既然用到了 [Person class] ,那我们就看下在 runtime 中 [Person class] 的替代函数,都是通过名字来获得 Class
那这三个有什么区别,从结论上讲, objc_getClass 和 objc_lookUpClass 的效果是一致的,在最新的源码里面,这两个方法调用的底层也是一致的,当你要找的类不存在的话,就返回nil,而 objc_getRequiredClass 里你要找的类不存在的话,就会崩溃。下面我们来测试下,我们创建一个 Person 类。
运行结果:
最后也确实崩溃了,所以大家使用 objc_getRequiredClass 这个函数时候要慎重小心。
除了用名字获得类对象以外,还可以用实例对象来获取:
我们测试下:
运行结果:
完全没问题。
Class 不仅可以代表类对象,也可以代表元类对象,下面这个函数就是通过名字获取元类对象。
如果你读过源码的话,你就会清楚元类对象储存的是类方法,类对象储存的是实例方法,在后面讲到Method相关的API的时候,我们在具体讲他们之间的区别。
讲到元类对象,我们还要关注下这个函数,
这个函数是用来判断是否是元类对象。
运行结果:
我们可以看到 objc_getMetaClass 生成才是元类对象, objc_getClass 生成的只是类对象。
那么有没有函数区分类(元类)对象和实例对象呢?当然有:
这个方法只要是类对象或者元类对象都会返回YES:
运行结果:
当然也可以获得父类对象。
我们新建一个继承 Person 的类 Student ,然后我们通过 Student 类来获得 Person 类。
运行结果:
Student 的父类确实是 Person 。
我们知道OC里面可以强转类型,当然, runtime 里面也有相关方法
这个方法的意思是给一个实例对象设置新的类,返回旧的类
运行结果:
我们可以看出开始的时候 student 的类是 Student ,用了 object_setClass 后就是 Person 类了。
runtime 的动态性还可以动态新增类,下面四个函数分别表示为一个类分配内存,注册一个类,复制一个类,销毁一个类
创建一个新类, superclass 是新类所继承的类,如果为 nil , superclass 就默认为根类,也就是 NSObject , extraBytes 是在类和元类对象的末尾为索引ivars分配的字节数。这一般是0, name 是新类的名字。
注册类,如果这个类 objc_allocateClassPair 好了,就必须 objc_registerClassPair 才能使用。
这个方法在系统KVO的底层用过,系统不推荐我们自己用。
objc_disposeClassPair 只能销毁通过 objc_allocateClassPair 创建的类。
我们写个demo来测试这些方法, objc_duplicateClass 官方不建议使用,那么我们就不测试这函数。
运行结果:
我们可以知道如果仅仅只是 objc_allocateClassPair 的话,你是找不到这个类的,必须再 objc_registerClassPair 才可以找到, objc_disposeClassPair 则是把类销毁掉,所以再实际开发中,如果我们不再使用自建类的时候,就要及时销毁,节省内存。
下面两个函数是关于整个工程的类列表的函数:
这个函数是获得所有注册类的列表,我们试用下:
运行结果:
我们看到注册的类有15765个。
objc_getClassList 也是获取注册类的方法.
第一个参数 buffer 已分配好内存空间的数组指针, bufferCount 是数组的个数,如果 bufferCount 的数量小于实际的数组数量,那么 buffer 返回的是所有数组集合的任意一个子类。如果 buffer 为NULL,那么 bufferCount 为0。无论那种情况,返回结果都是当前注册类的总数。
运行结果:
返回类实例的大小。
运行结果
一个没有变量或属性的继承于NSObject的类占有8个字节。
还有个方法是:
这是一个创建实例的方法, cls 是要创建的类, extraBytes 是额外的字节内存,用来存储类定义中的实例变量之外的其他实例变量。在源码中 alloc 方法底层就是用的这个函数。那么,我们用这个函数来初始化 Person 类:
运行结果:
确实能够成功创建出来。
最后剩下两个方法:
这两个方法都和 version 有关,这个version在实际中我也没发现用处,可能是在改变类的变量或者方法时给定一个标识.
运行结果
下面我们将使用runtime里面最最常用的api,也就是给分类绑定对象,这里,我们先了解下,一个枚举:
objc_AssociationPolicy 是一个枚举,里面的枚举值分别代表要添加的属性的修饰类型。
OBJC_ASSOCIATION_ASSIGN 相当于 weak
OBJC_ASSOCIATION_RETAIN_NONATOMIC 相当于 strong 和 nonatomic
OBJC_ASSOCIATION_COPY_NONATOMIC 相当于 copy 和 nonatomic
OBJC_ASSOCIATION_RETAIN 相当于 strong 和 atomic
OBJC_ASSOCIATION_COPY 相当于 copy 和 atomic
关于分类的runtime函数,主要有下面3个:
含义分别为设置关联对象,获得关联对象,删除关联对象。
我们知道如果在分类的 .h 文件设置属性并没有用,调用的时候会发生闪退,这是因为系统并没有自动为属性生成 Set 和 Get 方法,所以,我们用上面三个方法来手动关联对象。
我们创建一个 Person 的分类 Person+Actor.h ,在.h文件里新建一个新属性 @property(nonatomic, assign)float actingSkill 而不做其他任何处理,这时候, .m 文件就会有警告。
这时候就绑定好了。
在 ViewController 里面去使用下这个属性
运行结果:
说明set和get方法都成功了。
那么还有一个 objc_removeAssociatedObjects 方法还没用,这个方法是解除绑定,为了测试这个效果,我们在ViewController里面 touchesBegan 里面去调用这个方法。
运行结果:
之前绑定的结果被移除了。
今天我们这一篇就讲到这, runtime 还有很多其他的用法我们下一篇见。
对了,这个是 demo ,喜欢的可以点个星。
IOS API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。
基于互联网的应用正变得越来越普及,在这个过程中,有更多的站点将自身的资源开放给开发者来调用。对外提供的API 调用使得站点之间的内容关联性更强,同时这些开放的平台也为用户、开发者和中小网站带来了更大的价值。
开放是目前的发展趋势,越来越多的产品走向开放。目前的网站不能靠限制用户离开来留住用户,开放的架构反而更增加了用户的粘性。在Web 2.0的浪潮到来之前,开放的API 甚至源代码主要体现在桌面应用上,而现在越来越多的Web应用面向开发者开放了API。
具备分享、标准、去中心化、开放、模块化的Web 2.0站点,在为使用者带来价值的同时,更希望通过开放的API 来让站点提供的服务拥有更大的用户群和服务访问数量。
站点在推出基于开放API 标准的产品和服务后,无需花费力气做大量的市场推广,只要提供的服务或应用出色易用,其他站点就会主动将开放API 提供的服务整合到自己的应用之中。同时,这种整合API 带来的服务应用,也会激发更多富有创意的应用产生。
为了对外提供统一的API 接口,需要对开发者开放资源调用API 的站点提供开放统一的API接口环境,来帮助使用者访问站点的功能和资源。
当然,开放API 的站点为第三方的开发者提供良好的社区支持也是很有意义的,这有助于吸引更多的技术人员参与到开放的开发平台中,并开发出更为有趣的第三方应用。