1. 定义一个协议, 一个协议可以扩展子另一个协议 如果需要扩展多个协议中间使用逗号分隔

     //定义一个协议
    @protocol AnimalDelegate <NSObject, ***> @required //必须实现的方法
    -(void)eat; @optional //可选实现的方法
    -(void)run;
    -(void)say;
    -(void)sleep;
    @end
  2. 和其他高级语言中接口不同的是协议中定义的方法不一定是必须实现的。 我们可以通过关键字进行@required和@optional进行设置,如果不设置则默认是@required(注意ObjC是弱语法,即使不实现必选方法编译运行也不会报错);

  3. 协议通过<>进行实现,一个类可以同时实现多个协议,中间通过逗号分隔;

  4. 协议的实现只能在类的声明上,不能放到类的实现上(也就是说必须写成@interface Person:NSObject而不能写成@implementation Person);

  5. 协议中不能定义属性、成员变量等,只能定义方法;

     @protocol CAMediaTiming
    
     /* The begin time of the object, in relation to its parent object, if
    * applicable. Defaults to 0. */ @property CFTimeInterval beginTime; /* The basic duration of the object. Defaults to 0. */ @property CFTimeInterval duration; /* The rate of the layer. Used to scale parent time to local time, e.g.
    * if rate is 2, local time progresses twice as fast as parent time.
    * Defaults to 1. */ @property float speed; /* Additional offset in active local time. i.e. to convert from parent
    * time tp to active local time t: t = (tp - begin) * speed + offset.
    * One use of this is to "pause" a layer by setting `speed' to zero and
    * `offset' to a suitable value. Defaults to 0. */ @property CFTimeInterval timeOffset; /* The repeat count of the object. May be fractional. Defaults to 0. */ @property float repeatCount; /* The repeat duration of the object. Defaults to 0. */ @property CFTimeInterval repeatDuration; /* When true, the object plays backwards after playing forwards. Defaults
    * to NO. */ @property BOOL autoreverses; /* Defines how the timed object behaves outside its active duration.
    * Local time may be clamped to either end of the active duration, or
    * the element may be removed from the presentation. The legal values
    * are `backwards', `forwards', `both' and `removed'. Defaults to
    * `removed'. */ @property(copy) NSString *fillMode; @end

    上面的协议是苹果的原生代码,但你会看到协议里面有很多@propety,那这个不就和上面的协议中不能定义属性、成员变量等,只能定义方法;有点相违背么?这就会产生以下几个问题:

    1. @propety是什么,干了什么? 对于.m 文件中的这个 @synthesize有什么作用?

       @property与@synthesize是成对出现的,可以自动生成某个类成员变量的存取方法。在Xcode4.5以及以后的版本,@synthesize可以省略。编译器会自动帮你加上getter 和 setter 方法的实现,并且默认会去访问_XXX这个成员变量,如果找不到_XXX这个成员变量,会自动生成一个叫做 _XXX的私有成员变量。
      ---
      @interface Student : NSObject
      {
      int age;
      int no;
      } //当编译器遇到@property时,会自动展开成getter和setter的声明
      @property int age;
      @property int no;
      @end ---- @implementation Student
      //@synthesize 会自动生成getter和setter的实现
      //@synthesize 默认会去访问age,no,height同名的变量,,
      //如果找不到同名的变量,会在内部自动生成一个私有同名变量age,no
      //因此Student.h 中的这几个变量也可以省略不写。 @synthesize age,no; // @synthesize age = _age, no = _no; // 生成两个私有变量 _age, _no
      @end
    2. 如果我就自己也写一个这样的协议,然后使用它会不会有问题?

       self.fillModel = @"test"; // unrecognized selector
      
       //这只是在头文件中声明,编译器是不会自动生成实例变量的,也就是说你可以用一个对象去实现这个协议,但是你不自己存储的话实例变量的话,访问同样会崩溃.
      
       // 如何去避免这种崩溃呢,下面的例子是一种方案,同时也证明了@synthesize的作用
      
       @protocol ViewContDelegate <NSObject>
      @property float repeatCount;
      @end @interface ViewController ()<ViewContDelegate>
      @end @implementation ViewController
      @synthesize repeatCount = _repeatCount; - (void)viewDidLoad {
      [super viewDidLoad];
      self.repeatCount = 1;
      NSLog(@"%f -- %f", self.repeatCount, _repeatCount);
      } @end
    3. 类中的声明@propety 和 协议中声明@propety 有区别么?

       两则没有区别,都是申明了setter/getter. 而在类中的.m 在Xcode4.5以后版本@synthesize可以被忽略。而生成的变量的操作其实还是由@synthesize完成的。
    4. 对于category也有类似的规范,那么为什么使用关联对象可以对类添加属性,category实现的原理?

       1. 这个技术并不是category的特性,而是runtime.h的一种应用。iOS运行时机制,简单来说,就是苹果给开发这提供的一套在运行时动态创建类、添加属性/方法.
      OC把实例变量当做一种存储偏移量所用的"特殊变量",交由"类对象"保管。偏移量会在运行期查找,如果类的定义变了,那么存储的偏移量也就变了,这样的话,无论何时访问实例变量,总能使用正确的偏移量。甚至可以在运行期间向类中新增实例变量,这就是ABI,有了这种稳固的ABI,我们就可以在“class-continuation 分类”或者实现文件中定义实例变量了。所以说,不一定要在接口中把全部的实例变量都声明好,可以将某些变量从接口的public区段移走,以便保护与类实现有关的内部信息 2. 有没有主动引入 Category 的头文件,Category 中的方法都会被添加进主类中。我们可以通过 - performSelector: 等方式对 Category 中的相应方法进行调用,之所以需要在调用的地方引入 Category 的头文件,只是为了“照顾”编译器同学的感受。 在文件 objc-runtime-new.mm 中找到以下函数:
      void _read_images(header_info **hList, uint32_t hCount){}在这个函数中对 Category 做了如下处理: 1. 将 Category 和它的主类(或元类)注册到哈希表中;
      2. 如果主类(或元类)已实现,那么重建它的方法列表。 Category 中的实例方法和属性被整合到主类中;而类方法则被整合到元类中。对协议的处理比较特殊,Category 中的协议被同时整合到了主类和元类中。 不管是哪种情况,最终都是通过调用 static void remethodizeClass(Class cls) 函数来重新整理类的数据的。这个函数的主要作用是将 Category 中的方法、属性和协议整合到类(主类或元类)中,更新类的数据字段 data() 中 method_lists(或 method_list) 、 properties 和 protocols 的值。进一步,我们通过 attachCategoryMethods 函数的源码可以找到真正处理 Category 方法的 attachMethodLists 函数:主要作用就是将类中的旧有方法和 Category 中新添加的方法整合成一个新的方法列表,并赋值给 method_lists 或 method_list 。通过探究这个处理过程,我们也印证了一个结论,那就是主类中的方法和 Category 中的方法在 runtime 看来并没有区别,它们是被同等对待的,都保存在主类的方法列表中。不过,类的方法列表字段有一点特殊,它的结构是联合体, method_lists 和 method_list 共用同一块内存地址。当 newCount 的个数大于 1 时,使用 method_lists 来保存 newLists ,并将方法列表的 标志位 置为 RW_METHOD_ARRAY ,此时类的方法列表字段是 method_list_t 类型的指针数组;否则,使用 method_list 来保存 newLists ,并将方法列表的 标志位 置空,此时类的方法列表字段是 method_list_t 类型的指针。 runtime 对 Category 中方法的处理过程并没有对 +load 方法进行什么特殊地处理。因此,严格意义上讲 Category 中的 +load 方法跟普通方法一样也会对主类中的 +load 方法造成覆盖,只不过 runtime 在自动调用主类和 Category 中的 +load 方法时是直接使用各自方法的指针进行调用的。所以才会使我们觉得主类和 Category 中的 +load 方法好像互不影响一样。因此,当我们手动给主类发送 +load 消息时,调用的一直会是分类中的 +load 方法
  6. 事实上在ObjC中协议的更多作用是用于约束一个类必须实现某些方法,而从面向对象的角度而言这个类跟接口并不一定存在某种自然关系,可能是两个完全不同意义上的事物,这种模式我们称之为代理模式(Delegation)。在Cocoa框架中大量采用这种模式实现数据和UI的分离,而且基本上所有的协议都是以Delegate结尾。

文章中的引用:

  1. 深入理解Objective-C:Category
  2. iOS开发系列--Objective-C之协议、代码块、分类
  3. Objective-C Category 的实现原理

iOS 之 protocol的相关问题的更多相关文章

  1. 转:基于IOS上MDM技术相关资料整理及汇总

    一.MDM相关知识: MDM (Mobile Device Management ),即移动设备管理.在21世纪的今天,数据是企业宝贵的资产,安全问题更是重中之重,在移动互联网时代,员工个人的设备接入 ...

  2. 基于IOS上MDM技术相关资料整理及汇总

    (转自:http://www.mbaike.net/special/1542.html) 一.MDM相关知识:MDM (Mobile Device Management ),即移动设备管理.在21世纪 ...

  3. iOS音乐播放器相关

    iOS音乐播放器框架主要有两大类:AvPlayer.AvaudioPlayer AvPlayer 能播放本地及网络歌曲 AvaudioPlayer 能播放本地歌曲.有相关代理方法(其实也可以播放网络歌 ...

  4. iOS 10 开发 相机相关的适配

    升级 iOS 10 之后目测坑还是挺多的,记录一下吧,看看到时候会不会成为一个系列. 直入正题吧 今天在写 Swift 3 相关的一个项目小小练下手,发现调用相机,崩了.试试看调用相册,又特么崩了.然 ...

  5. iOS UIViewController 和 nib 相关的3个方法

    iOS UIViewController 的 awakeFromNib 以及 - (id)initWithCoder:(NSCoder *)aDecoder 和 - (instancetype)ini ...

  6. iOS,文本输入,键盘相关

    1.UIKeyboard键盘相关知识点 2.点击空白区域隐藏键盘(UIKeyboard) 3.键盘(UIKeyboard)挡住输入框处理 4.自定义键盘(UIKeyboard) 5.监听键盘弹出或消失 ...

  7. iOS之即时通讯相关理解

    Socket: 1>Socket又称"套接字" 2>网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 3>应用程序通常通 ...

  8. iOS应用程序状态切换相关

    一.iOS应用程序状态机一共有五种状态: 1. Not running:应用还没有启动,或者应用正在运行但是途中被系统停止. 2. Inactive:当前应用正在前台运行,但是并不接收事件(当前或许正 ...

  9. ios开发-获取手机相关信息

    今天在做客户端的时候,里面有个意见反馈功能. 调用系统带的邮件功能,发送邮件到指定邮箱. 然后我就想,应该在邮件正文部分添加手机相关内容,比如型号,版本,应用程序的版本等等,这样不仅使用者方便,开发者 ...

随机推荐

  1. java基础知识5--集合类(Set,List,Map)和迭代器Iterator的使用

    写的非常棒的一篇总结: http://blog.csdn.net/speedme/article/details/22398395#t1 下面主要看各个集合如何使用迭代器Iterator获取元素: 1 ...

  2. Python学习笔记012_网络_异常

    1,Python如何访问互联网? url + lib =  urllib >>> # 使用urllib包下的request模块 >>> >>> i ...

  3. Ansible系列(六):各种变量定义方式和变量引用

    本文目录:1.1 ansible facts1.2 变量引用json数据的方式 1.2.1 引用json字典数据的方式 1.2.2 引用json数组数据的方式 1.2.3 引用facts数据1.3 设 ...

  4. 基于pytorch实现HighWay Networks之Train Deep Networks

    (一)Highway Networks 与 Deep Networks 的关系 理论实践表明神经网络的深度是至关重要的,深层神经网络在很多方面都已经取得了很好的效果,例如,在1000-class Im ...

  5. ajax 发送json 后台接收 遍历保存进数据库

    前台怎么拿参数的我就不管了我也不会 反正用这个ajax没错 ajax 代码   一定要写明http请求类型  { contentType:"application/x-www-form-ur ...

  6. windows 结束进程的详细过程

    windows上如何结束进程的详细过程,下面附详细,图文说明 在cmd下,输入  netstat   -ano|findstr  8080      //说明:查看占用8080端口的进程 在cmd下, ...

  7. 我的第一个python web开发框架(1)——前言

    由于之前经验不是很丰富,写的C#系统太过复杂,所以一直想重写,但学的越多越觉得自己懂的越少,越觉的底气不足.所以一直不敢动手,在内心深处对自己讲,要静下心来认真学习,继续沉淀沉淀.这两年多以来找各种机 ...

  8. BZOJ-1012-[JSOI2008]最大数maxnumber(线段树)

    Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插 ...

  9. 使用百度ueditor的插件使得代码高亮显示

    一.在show.html模板中,引入ueditor的插件,并调用 <link rel="stylesheet" href="__ROOT__/Data/uedito ...

  10. python --- hashlib模块使用详解

    这个模块实现了一个通用的接口来实现多个不同的安全哈希和消息摘要算法.包括FIPS安全散列算法SHA1,SHA224,SHA256,SHA384和SHA512(在FIPS 180-2中定义)以及RSA的 ...