热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

(转)objectiveC中的接口@interface与泛型(id)在objc的世界中,官方根本没有"接口"与"泛型"这样的说法。

不过在obj-c中有二个与之接近的概念"非正式协议(interface)"与"正式协议(protoca

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

@interface Sample : NSObject {

}

-(void) HelloWorld;

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

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

(转) objective-C中的接口@interface与泛型(id)
    





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


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

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

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

@interface DBQuery : NSObject {

}

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

@implementation DBQuery

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

@end
当然,如果在DBQuery.m中不实现方法Query,也能编译通过,只是会收到一个警告。
也许到目前为止,你会觉得protocal跟interface比起来,都是类似的概念,protocal设计纯属多余。其实不然,protocal存在的一个重要意义在于:
正式协议(protocal)可以将业务中的方法定义剥离出来,形成一个单独的文件,这跟传统OO中的提取接口是不谋而合的。如果遇到二个系统需要交换数据,可以制定一套双方都遵守的protocal,然后这二个系统中都把这个协议文件添加到项目中,实现它即可。这一功能,非正式协议(@interface)就做不到。(不信大家可以把NSObject中的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或protocal

(转) objective-C中的接口@interface与泛型(id)
    





		
在obj-c的世界中,官方根本没有"接口"与"泛型"这样的说法。

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

(转) objective-C中的接口@interface与泛型(id)
    





		
在obj-c的世界中,官方根本没有"接口"与"泛型"这样的说法。

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

(转) objective-C中的接口@interface与泛型(id)
    





		
在obj-c的世界中,官方根本没有"接口"与"泛型"这样的说法。

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

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


另一个话题泛型

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

#import 
#import "IQuery.h"

@interface DBQuery : NSObject {	

}

-(void) test:(id) obj;
@end

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

作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com

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

@interface Sample : NSObject {

}

-(void) HelloWorld;

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

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

(转) objective-C中的接口@interface与泛型(id)
    





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


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

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

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

@interface DBQuery : NSObject {

}

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

@implementation DBQuery

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

@end
当然,如果在DBQuery.m中不实现方法Query,也能编译通过,只是会收到一个警告。
也许到目前为止,你会觉得protocal跟interface比起来,都是类似的概念,protocal设计纯属多余。其实不然,protocal存在的一个重要意义在于:
正式协议(protocal)可以将业务中的方法定义剥离出来,形成一个单独的文件,这跟传统OO中的提取接口是不谋而合的。如果遇到二个系统需要交换数据,可以制定一套双方都遵守的protocal,然后这二个系统中都把这个协议文件添加到项目中,实现它即可。这一功能,非正式协议(@interface)就做不到。(不信大家可以把NSObject中的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或protocal

(转) objective-C中的接口@interface与泛型(id)
    





		
在obj-c的世界中,官方根本没有"接口"与"泛型"这样的说法。

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

(转) objective-C中的接口@interface与泛型(id)
    





		
在obj-c的世界中,官方根本没有"接口"与"泛型"这样的说法。

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

(转) objective-C中的接口@interface与泛型(id)
    





		
在obj-c的世界中,官方根本没有"接口"与"泛型"这样的说法。

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

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


另一个话题泛型

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

#import 
#import "IQuery.h"

@interface DBQuery : NSObject {	

}

-(void) test:(id) obj;
@end

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


推荐阅读
  • 作为一名在大型手机游戏公司工作的程序员,尽管主要负责游戏逻辑和内容的开发,但对iOS底层开发接触较少。现在有了iPhone和可以虚拟MAC环境的电脑,希望能找到有效的iOS开发学习路径。 ... [详细]
  • 20100423:Fixes:更新批处理,以兼容WIN7。第一次系统地玩QT,于是诞生了此预备式:【QT版本4.6.0&#x ... [详细]
  • 解析SQL查询结果的排序问题及其解决方案
    本文探讨了为什么某些SQL查询返回的数据集未能按预期顺序排列,并提供了详细的解决方案,帮助开发者理解并解决这一常见问题。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 本文详细介绍如何在 macOS 上编译 FFmpeg 3.1.1,并将其集成到 iOS 项目中,包括必要的环境配置和代码示例。 ... [详细]
  • 我在项目中发现设置了 GCC_NO_COMMON_BLOCKS = NO 的配置项,位于 Apple LLVM 编译器 3.1 的代码生成设置中。 ... [详细]
  • 本文详细介绍了如何在iOS5中创建和理解简单的Hello World应用,包括Interface Builder的使用、Objective-C源代码文件的结构以及事件处理机制。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 本文详细介绍了Java中的输入输出(IO)流,包括其基本概念、分类及应用。IO流是用于在程序和外部资源之间传输数据的一套API。根据数据流动的方向,可以分为输入流(从外部流向程序)和输出流(从程序流向外部)。此外,还涵盖了字节流和字符流的区别及其具体实现。 ... [详细]
  • 创建项目:Visual Studio Online 入门指南
    本文介绍如何使用微软的 Visual Studio Online(VSO)创建和管理开发项目。作为一款基于云计算的开发平台,VSO 提供了丰富的工具和服务,简化了项目的配置和部署流程。 ... [详细]
  • Python第三方库安装的多种途径及注意事项
    本文详细介绍了Python第三方库的几种常见安装方法,包括使用pip命令、集成开发环境(如Anaconda)以及手动文件安装,并提供了每种方法的具体操作步骤和适用场景。 ... [详细]
  • 在成功安装和测试MySQL及Apache之后,接下来的步骤是安装PHP。为了确保安全性和配置的一致性,建议在安装PHP前先停止MySQL和Apache服务,并将MySQL集成到PHP中。 ... [详细]
  • 异常要理解Java异常处理是如何工作的,需要掌握一下三种异常类型:检查性异常:最具代表性的检查性异常是用户错误或问题引起的异常ÿ ... [详细]
  • 本文介绍了在Xcode项目中导入第三方库后遇到的Clang编译错误——'no such file or directory',并提供了详细的解决步骤。此问题通常由工程目录结构调整引起。 ... [详细]
  • Android开发经验分享:优化用户体验的关键因素
    随着Android市场的不断扩展,用户对于移动应用的期望也在不断提高。本文探讨了在Android开发中如何优化用户体验,以及为何用户体验的重要性超过了技术本身。 ... [详细]
author-avatar
細亞米奇Mego_677
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有