OC 课程笔记总结12-block,protocol

 课程:其他

block:

block是一种数据类型,官方推荐使用的数据类型,block 在实际项目中非常常见,效率高,好用。block 的本质是源自 C 语音。并且 block 中也有 isa 指针,说明在oc 中 block 也是一种对象。block 的作用就是封装和 保存代码,用 block 保存的代码可以在任何时候调用,类似于函数,但是函数在编译之前就必须确定函数即函数的代码是确定的,而在运行过程中,函数是无法改变的。 block 则可以在程序运行中可以产生一段代码并且保存起来。对于内存管理而言,使用 ARC 和不使用 ARC中的 block 是有区别的,因为 block 在存储上有时存在于堆中,有时候存在栈中。block 也称为代码块,因为 block 有保存代码的功能,block 要配合大括号使用,格式如下:

^(参数 参数名,如果没有形参,那么这个括号可以省略){

代码;

};          

^  尖号有两种表示意义,1是异或,2是表示一个 block 块,通过符号来说明一个 block 块,

block 和函数相似的地方有3个:都可以保存代码,都有返回值,都有形参,但要记住,block 是一种数据类型,必须有接收方,标准格式如下:


void (^block变量名)(参数类型,可以只写参数类型,不用写参数名,实际代码中通常不写参数名) = ^(参数类型 参数名)    //  对于 block 的返回数据类型不用加上括号,这点比较特殊,要注意。

{

 代码

 };  //  不要忘记分号,这其实是一个赋值语句。


类似于赋值函数指针,函数指针是指向函数的变量,通过指针来操作函数。每个函数都有一个地址,既然有地址就能通过指针来进行操作。函数指针可以完成两个功能,1是调用函数,1个是作为函数的参数。但是函数指针不常用,除了是写高性能和底层相关的代码。利用 block 变量调用 block 块中的代码,即block 中代码块是需要调用才会生效的,调用格式如下:block变量名(参数);在实际编程中,能使用 block 就使用 block。

可以通过结合 typedef 来简化代码的书写。和定义 typedef 的函数指针一样,也可以通过 typedef 来定义 block 变量。在这里typedef 的作用其实是用一个类型名去代替一个block类型,要定义一个block类型需要写返回类型,形参类型(如果有形参),而如果用 typedef 来定义这个 block 类型,只需要写一个 block 类型名就可以了,可以简化一些代码书写。即定义一次 typedef,可以代替多次书写。注意的是 typedef 并不能定义 block 块中的代码(实现功能),具体实现的功能还是要多次书写,typedef 能够简化的是=号左边的部分:void (^block变量名)(参数类型,可以只写参数类型,不用写参数名,实际代码中通常不写参数名),这一部分可以简化为: block 类型名 block 变量名 = XXXXXX;右边的部分还是要自己去写。只要记住=号左边相当于一个变量类型和变量名,=号右边才是这个变量实际的东西就可以了, 

block 总结:

1.如何定义一个 block 变量;

2.如何使用 block 封装代码;

3.block 访问外面的变量:

* block 内部可以访问外面的变量;

* 默认情况下,block 内部不能对外面的变量进行修改;

* 如果给局部变量加上__block(双下划线)的关键字(不用@),这个局部变量就能够在 block 内部进行修改;

4.利用 typedef 定义 block 类型:

* 示例: typedef int (^MyBlock) (int int),定义之后就可以使用 MyBlock 来代替一个 block 声明了,表示 MyBlock 就是某种已经定义好了的 block 类型,可以简化代码书写。

5.不要忘记在写分号,定义一个block 变量其实是一种赋值操作,尽管有大括号,但是一定要记得在大括号后面写上分号,因为这是一个赋值语句。

6.一般在编写 block 时先把主体功能编写好,再根据形参和返回类型写 block 的声明。即先写完等号右边,在根据右边去写等号左边。

7.block几乎和函数一样,可以给通过调用block来执行block中的代码,不同的是如果在主函数中定义了某个函数,那么当执行到这个函数时,函数会被立即执行,而block不同,将block赋值给一个block变量后,当调用这个变量时block中的代码才会被执行,使用场景比如说是监测某一个值的变化,因为block可以访问外部的变量,所以block]相对函数而言更加灵活. 

protocol:

protocol 也是在 oc 中经常使用的,在 oc 中天天见的有:protocol,枚举,block,结构体,ARC,这些都是实际开发中必须使用的。protocol 只有一个功能:就是声明多个方法,就是用来声明方法的,不能声明其他的东西。使用 protocol 声明的方法可以让任意的类去实现,而普通声明的方法只能是特定的类去实现。protocol 即协议,在protocol 中声明方法,声明方法唯一目的就是让方法可以实现,实现方法必须由类来操作,只要是遵守了 protocol,即遵守了协议的类,都能实现 protocol 中声明过的方法。

protocol 只是声明方法,因此只会生成一个。h 文件,并且由关键字@protocol 来表示这是一份协议。和category 分类一样,协议中不能写成员变量,但是不同的是分类可以实现方法,而协议不能实现方法,只能够声明方法。只要一个类遵守了某个协议,那么这个类就相当于声明了这个协议中的所有方法。遵守协议是规定的术语,在类的声明中使用<协议名> 来表示遵守某个协议,而使用:来表示继承某个类,继承是单继承,协议可以遵守多个,类似于JAVA中的接口。在协议的。h 文件中,可以对协议加上一些参数,定义协议的某些要求,关键字如下:

@require:遵守了当前协议就必须实现以下方法,默认就是 require,都要实现,如果不实现,系统会发出警告,但是不会报错,在 java 中,如果没有实现接口中的所有方法,java 就会报错;

@optional:遵守了当前协议可以选择实现以下方法,也可以不实现,都不会有警告;

这两个关键字多用于合作项目中,方便不同编程人员之间的交流,看哪些方法是必须实现的,哪些可以不实现。

如果父类遵守类某个协议,相当于子类野遵守了这个协议, 其实就是方法的继承。

协议格式如下:

@protocol 协议名

协议中的方法声明;

@end

类遵守某些协议:

@interface 类名 : 父类明  <协议名1,协议名2,协议名3.。。。。。>       // 可以遵守多个协议。遵守多个协议中不会发生方法名冲突,因为方法声明可以多次,只能实现一次方法,以实现的方法为准。

类的成员变量和方法声明;

@end


协议 protocol 常用于设计模式中的代理模式和观察者模式中,这两种设计模式都常用协议 ,从本质上而言,代理模式和观察者模式是一样的,思想都是类似的,区别是代码的细微不同而已。一个好的设计模式可以定义一个好的架构。


基协议:

类似于类,有一个基类,即超类,协议也有基协议,所有的协议都会遵守的协议,注意基协议不是所有类都会遵守的协议,而是所有协议都会遵守的协议。一个协议也可以遵守多个协议,只要遵守了其他的协议,也就相当于有了其他协议中声明的方法。

要遵守一个协议,必须也要#improt ”协议名。h”,添加。h 文件后才能遵守相关的协议,如果没有。h 文件,系统会认为这个协议没有定义,找不到,会报错。在 oc 中,这个基协议名也是 NSObject,和超类名一致。 并且基协议是声明在 Foundation 框架中的。

超类 NSObject 遵守的 协议就是基协议。所以,只要继承了超类(基本上可以说所有的 OC 类都继承了超类),那么这个类也都遵守了基协议。所以,在定义某个协议时,一定要写上遵守<NSObject> 基协议。


限制传递的对象类型:

可以限制传递给某个指针的对象是遵守了某些协议的,格式如下:

类型名  <协议名1,协议名2.。。。。>  *指针变量名  =  对象;           // 只有遵守了规定协议的对象才能够赋值给这个指针变量;

实际中的写法是:

id <协议名1,协议名2.。。。。。。。>  指针变量名 = 对象;            // 表示这个指针可以指向任何遵守了规定协议的对象,要注意的时,不需要再在指针变量名前面加上 * 号,因为 id = NSObject *,id 本身就带有 * 号了。


不论遵守了什么协议,在相关的文件中都要 improt 这个协议的。h 文件,这点不要忘记。


协议的高级用途是用于设计模式。


类似于类中的@class,在遵守协议中也可以有提高性能的写法,就是用 @protocol 协议名 (注意不用加。h ) 来代替 #import ”协议名。h”   。同样的,这只是告诉编译器 xxx 是一个协议,只能在类的。h 文件中这么写,当要真正实现一个协议中的方法时,即在。m 文件中实现方法是,还是要使用#import “协议名。h”,和类的@class 使用方法一样,在实际开放中,都是使用@class 和@protocol,用于告诉编译器对应的是什么就行,当需要真正用到时,即在。m 文件时才使用#improt “xxx.h”来告诉编译器具体的实际构造是怎么样的。。h 文件的作用就是告诉编译器内部的实际构造是怎么样的。如果内部构造有所改变,那么编译器就重新编译一次,非常浪费性能,所以为了提高性能,使用@class 和@protocol 是实际项目中的做法。


协议 protocol 的总结:

1.协议的定义 

@protocol 协议名  <NSObject>       //  遵守基协议,必须要写上遵守基协议,否则就不能继承基协议中的方法。

协议中的方法声明列表;

@end

2.如何遵守协议

1》 类遵守协议:

@interface 类名 :父类名  <协议名1,协议名2.。。。>

@end

2》 协议遵守协议:

@protocol 协议名 <NSObject ,其他协议名1,协议名2.。。。。>            // 开发中遵守的首协议必须是 NSObject

@end

3.协议中方法声明的关键字

* require    :必须实现的方法,但是如果没有实现,系统只会警告,不会报错,所以这个关键字主要是用于程序员之间的交流

* optional   : 可选实现的方法,不实现也不会警告

4.定义一个变量的时候,限制这个变量保存的对象必须是遵守了某些协议

类名  <协议名称1.。。> * 变量名;

id  <协议名称1.。。。>   变量名 ; // 定义类型为 id 时不需要在加上 *号

5.在@property 中也可以使用协议来限制传入的对象参数

@propety (nonatomic,strong) 类型名 <协议名1.。。。> * 属性名;

@propety (nonatomic,strong) id  <协议名1.。。。>   属性名;

6.协议的位置:

1》当某个协议只用在某个类中时,可以把这个协议写在这个类的头文件里面,而不用单独写一个协议的。h文件;

2》当某个协议需要被多个类遵守时,就必须把这个协议单独写成一个协议的。h文件。方便其他对象@protocol 引用和#improt “协议名。h”实际调用。

(类似的,分类也可以写在一个类中,也可以单独的写,当分类中的方法比较少时,可以写在这个分类的类中,实现野写在这个类的实现中。即可以把所有的声明都写在同一个文件中,把所有的实现都写在一个文件中,这样是没有语法错误的。

不过在实际开放中这样的情况很少见,如果是方法少的话,完全可以不使用分类,而直接在类方法中增加。所以分类大部分实际开放的情况下都是单独文件。分类只需要是在类名后面加上(分类名)即表示是一个分类。)

7.OC 代码中常见的:

冒号:表示继承;

<> 尖括号表示协议(是指在代码中,如果是在头文件中表示系统自定义的头文件);

括号()表示分类。



protocol 的实际应用:代理设计模式

 代理设计模式实际上是类与类之间的互动。类与类之间的相互沟通是通过发送消息来实现,发送消息即调用方法。在开发中经常使用代理模式。如果不使用代理模式,要想进行类与类之间的互动,会使得类之间的耦合性太强,如果缺少某一个类那么程序就会无法运行,在程序设计中,一定要尽量减少耦合性。而通过协议,就可以减少类之间的耦合性,只要遵守了某些属性,不管是什么类,哪个类,都能够进行互动,而不是只和某个特定的类互动。同时,使用协议也可以限制和哪些对象可以互动,和哪些对象不能互动。在实际开发中,如果某个协议名是以“delegate”结尾的,说明这个协议是用于代理模式的。delegate:委托,委派的意思。通常代理模式下的协议名也是以 delegate 作为结尾的。在 ios 中,UITableView,就经常使用代理模式。
















































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值