objective-C中的接口与泛型

简介: 先承认我是标题党,因为在obj-c的世界中,官方根本没有"接口"与"泛型"这样的说法。 不过在obj-c中有二个与之接近的概念"非正式协议(interface)"与"正式协议(protocol)"。
先承认我是标题党,因为在obj-c的世界中,官方根本没有"接口"与"泛型"这样的说法。

不过在obj-c中有二个与之接近的概念" 非正式协议(interface)"与" 正式协议(protocol)"。 非正式协议在obj-c中的关键字虽然也是interface,但是这个跟c#中的接口(interface)并不完全相同。
 
回忆一下前面学过的内容,我们定义一个类Sample时,总是会先生成一个Sample.h,代码如下:
#import <Foundation/Foundation.h>

@interface Sample : NSObject {

}

-(void) HelloWorld;

@end
它表明Sample类中,约定了" 应该"有一个名为HelloWorld的方法(注:我这里说的是 应该,而不是 必须),它只是一种 君子协定

 

如果我们在Sample.m中,并不遵守这个约定(即:不实现这个方法),编译时xcode会给出警告,如下图。但最后还是会编译成功(即:编译器对此是睁一只眼闭一只眼,默认了Sample类的这种不忠行为)

 

上图中的提示:Incomplete implementation of class "Sample". 意为:Sample类并未完全实现interface中约定的方法。
这就是 obj-c中的协议跟c#中的接口不一样的地方:在c#中接口是强制必须实现的,否则编译这一关就过不了,而obj-c虽然在编译时会警告,但是最终能编译通过。



正式协议(protocol)
其实就是非正式协议(interface)换了一种写法而已,看上去更正规一些,语义上更强烈一些:要求采用该协议的类,"必须"实现协议中约定的方法。但是比较娱乐的是,即使是号称 正式协议,编译器在编译时,遇到不守规矩的情况,仍然只是给出警告。(当然正式协议也有它存在的意义,后面会提到)
 
这里我们定义一个IQuery的协议
IQuery.h
@protocol IQuery

-(void) Query:(NSString*) sql;

@end
除了把关键字@interface换成了@protocol,其它的基本上没变化。下面定义一个类DBQuery,并采用这个正式协议
DBQuery.h
#import <Foundation/Foundation.h>
#import "IQuery.h"

@interface DBQuery : NSObject<IQuery> {

}

@end
注意这里的DBQuery: NSObject<IQuery>,它表明DBQuery继承自NSObject,同时要实现接口IQuery。
DBQuery.m
#import "DBQuery.h"

@implementation DBQuery

-(void) Query:(NSString *)sql
{
	NSLog(@"Query is called. sql:%@",sql);
}

@end
当然,如果在DBQuery.m中不实现方法Query,也能编译通过,只是会收到一个警告。
也许到目前为止,你会觉得protocol跟interface比起来,都是类似的概念,protocol设计纯属多余。其实不然,protocol存在的一个重要意义在于:
正式协议(protocol)可以将业务中的方法定义剥离出来,形成一个单独的文件,这跟传统OO中的提取接口是不谋而合的。如果遇到二个系统需要交换数据,可以制定一套双方都遵守的protocol,然后这二个系统中都把这个协议文件添加到项目中,实现它即可。这一功能,非正式协议(@interface)就做不到。(不信大家可以把NSObject<IQuery>中的IQuery改成其它类的interface定义名称试试,编译根本通不过)
 
此外,obj-C 2.0中对正式协议还做了一些扩展,允许把正式协议中的方法标识为“必须实现( @requied)”和“可选实现( @optional)”二类,如果协议中的方法被标识为@optional,即使采用该协议的类不实现这些方法,编译器也不会给出警告。这赋予了正式协议更多的灵活性。示例如下:
@protocol IQuery

@required
-(void) Query:(NSString*) sql;

@optional
-(void) HelloWorld; 

@end

 

有了@optional关键字以后,其实“非正式协议”在语义上完全可以被“正式协议”所取代,事实上Cocoa中的非正式协议都在逐渐被标有@optional方法的正式协议所代替。

如果你在XCode的代码中,选中NSObject,右击-->Jump to Definition,会发现NSObject其实就是一个interface或protocol

选择protocol NSObject 继续,会看到NSObject.h文件中关于protocol NSObject的定义

同样的,你还可以看到interface NSObject的定义

从这里可以看到,非正式协议的interface NSObject其实最终采用的还是正式协议protocol NSObject.

也就是说,在obj-c的OO世界中,身为万物之祖的NSObject其实也就一个"正式协议”,所以从NSObject派生出的所有类,都只是在遵守一个或多个协议而已。

 

另一个话题泛型

在obj-c中,一切皆为指针。前面的学习中,我们已经接触到了一种特殊的类型id,它可以认为是一种特殊的指针:可以指向任何类型的对象。id 再加上正式协议,能够达到形似c#中泛型的效果(注:只是形似,并非神似)

#import <Foundation/Foundation.h>
#import "IQuery.h"

@interface DBQuery : NSObject<IQuery> {	

}

-(void) test:(id<IQuery>) obj;
@end

注意这里的 -(void) test:(id<IQuery>) obj; 这表明test方法接受一个任意类型的对象做为参数,但是该参数对象必须实现接口IQuery(也可以说成该参数对象必须采用正式协议IQuery),是不是跟c#中的

void test(List<IQuery> obj) 长得很象? 

目录
相关文章
|
Java C# iOS开发
Objective-C初步研究 - 接口文件(interface file)
1. Exploring the Objective-C File Structure     建立一个Objective-C的类会新建两个文件, 一个接口文件(头文件)(interface file), 后缀为.
768 0
|
6月前
|
安全 编译器 Swift
IOS开发基础知识: 对比 Swift 和 Objective-C 的优缺点。
IOS开发基础知识: 对比 Swift 和 Objective-C 的优缺点。
377 2
|
4月前
|
开发工具 iOS开发 容器
【Azure Blob】关闭Blob 匿名访问,iOS Objective-C SDK连接Storage Account报错
iOS Objective-C 应用连接Azure Storage时,若不关闭账号的匿名访问,程序能正常运行。但关闭匿名访问后,上传到容器时会出现错误:“Public access is not permitted”。解决方法是将创建容器时的公共访问类型从`AZSContainerPublicAccessTypeContainer`改为`AZSContainerPublicAccessTypeOff`,以确保通过授权请求访问。
【Azure Blob】关闭Blob 匿名访问,iOS Objective-C SDK连接Storage Account报错
|
6月前
|
缓存 开发工具 iOS开发
优化iOS中Objective-C代码调起支付流程的速度
优化iOS中Objective-C代码调起支付流程的速度
94 2
|
6月前
|
安全 JavaScript 前端开发
IOS开发基础知识:介绍一下 Swift 和 Objective-C,它们之间有什么区别?
IOS开发基础知识:介绍一下 Swift 和 Objective-C,它们之间有什么区别?
259 0
|
iOS开发 容器
iOS 代码规范格式 Objective-C(上)
iOS 代码规范格式 Objective-C
429 0
iOS 代码规范格式 Objective-C(上)
|
编译器 API iOS开发
iOS 代码规范格式 Objective-C(下)
iOS 代码规范格式 Objective-C(下)
235 0
|
机器学习/深度学习 API iOS开发
【IOS 开发】Objective-C Foundation 框架 -- 字符串 | 日期 | 对象复制 | NSArray | NSSet | NSDictionary | 谓词(一)
【IOS 开发】Objective-C Foundation 框架 -- 字符串 | 日期 | 对象复制 | NSArray | NSSet | NSDictionary | 谓词(一)
178 0