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面试准备

    今天我们会分为四个部分来谈论这个问题,由于我本身是Java出身,因此关于主语言的问题,都是与Java相关,其它语言的同学可以选择性忽略.此外,面试的时候一般面试官的问题都是环环相扣,逐渐深入的,这点在 ...

  2. 易语言 【寻找文本】命令的bug

    最近在重写易语言模块的时候,在取子文本操作时老是出错,经常出现一些奇怪的问题,一开始以为是代码问题,可是找半天硬是找不到问题所在. 于是进入了找bug模式,这么几行代码,看了我半个小时,左改右改,总感 ...

  3. 【DDD】领域驱动设计实践 —— UI层实现

    前面几篇blog主要介绍了DDD落地架构及业务建模战术,后续几篇blog会在此基础上,讲解具体的架构实现,通过完整代码demo的形式,更好地将DDD的落地方案呈现出来.本文是架构实现讲解的第一篇,主要 ...

  4. 《MATLAB从入门到放弃》打通 “矩阵” 障碍

    目录: »   矩阵的生成与大小  >   简单矩阵的生成  >  随机矩阵的生成  >   矩阵的大小 »  矩阵的索引与访问 »  矩阵的拼接与裁剪 >  矩阵的拼接 &g ...

  5. 关于form表单或者Ajax向后台发送数据时,数据格式的探究

    最近在做一个资产管理系统项目,其中有一个部分是客户端向服务端发送采集到的数据的,服务端是Django写的,客户端需要用rrequests模块模拟发送请求 假设发送的数据是这样的: data = {'s ...

  6. javascript正则表达式入门

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  7. 有趣的flash例子

    仓鼠 <object type="application/x-shockwave-flash" data="http://cdn.abowman.com/widge ...

  8. Spring事务管理配置示例

    (一).Spring事务特性 1.事务隔离级别 隔离级别是指若干个并发的事务之间的隔离程度. ISOLATION_DEFAULT:默认值,使用数据库的默认隔离级别,就是ISOLATION_READ_C ...

  9. Jquery Ajax和getJSON获取后台普通Json数据和层级Json数据解析

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. zookeeper curator使用caches实现各种监听

    1.篇首语 curator是zookeeper的一个高级api开发包.封装了zookeeper众多的recipes,并且实现了一些新的recipes原语,最重要的是基于zookeeper提供的各种机制 ...