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. XML解析【介绍、DOM、SAX详细说明、jaxp、dom4j、XPATH】

    什么是XML解析 前面XML章节已经说了,XML被设计为"什么都不做",XML只用于组织.存储数据,除此之外的数据生成.读取.传送等等的操作都与XML本身无关! XML解析就是读取 ...

  2. 凸包GiftWrapping GrahamScan 算法实现

    开始 游戏内有需求做多边形碰撞功能,但是接入box2d相对游戏的需求来说太重度了.所以准备自己实现碰撞. 确定多边形,必然要用到凸包的算法.在github上也找到了一些lua实现,但是这里的算法没有考 ...

  3. Windows和Linux查看和更改mysql连接池

    Windows: 查看: 进入mysql 输入:show variables like '%max_connections%'; 更改: 进入MYSQL安装目录 打开MYSQL配置文件 my.ini ...

  4. NOIP算法总结与复习

    NOIP算法总结与复习 (看了看李总的蓝皮书,收获颇多,记下此文,以明志--) (一)数论 1.最大公约数,最小公倍数 2.筛法球素数 3.mod规律公式 4.排列组合数,错排 5.Catalan数 ...

  5. Map 基础用法

    import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; p ...

  6. this到底指向哪里

    this指向调用它的对象 首先要明确,this指向调用方,谁调用,this指向谁. 直接调用 举个栗子: var test = 'window' ; function testThis () { va ...

  7. 百度地图JS调用示例

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  8. 解决Jqyery的Trigger事件中两个按钮相互触发至死循环问题

    今天做项目,其中有个功能需要两个图表的联动,用到两个按钮,这两个按钮分别控制两个图表,第一次直接在btn1的单击事件中使用了$("btn2").trigger("clic ...

  9. nginx + keepalived 实现高可靠web网站

    组网图: 配置信息: 左边nigx 服务器的 /usr/local/nginx/conf/nginx.conf #user  nobody; worker_processes  1; #error_l ...

  10. Linux命令-基本命令(1)

    1. ll dfdfdfd 2. vi dfffd