1、protocol协议的基本用途:
(1)可以用来声明一大堆方法(不能声明成员变量)
(2)只要某个类遵守了这个协议,就相当于拥有了这个协议中的所有方法声明。
(3)只要父类遵守了某个协议,就相当于子类也遵守了。
注意:协议内仅仅写方法声明,不能写实现,不能写成员变量
2、对协议的简单理解:
(1)protocol声明的方法可以交给任何类去实现。
(2)protocol的作用仅仅就是声明方法,所以新建协议就是.h文件。
(3)@protocol关键字表示声明协议,同样以@end结尾。例如:@protocol MyProtocol
@end
表示声明了一个名为MyProtocol的协议。
(4)@protocol声明的方法要交给类去实现,即类遵守协议。也就是说只要类遵守了这个协议,就相当于拥有了这个协议内的所有方法声明。(协议仅仅用来声明方法,以交给多个类去实现(去遵守))
(5)协议与分类一样只能写方法,不能声明成员变量。但是和分类不同的是协议只能写方法声明,分类是给某个类扩充一些方法。
3、类遵守协议的方式:
在类的.h文件中导入协议所在的.h文件,类遵守协议的格式是在类继承的父类之后用尖括号“<>”括住协议名。即如下所示
@interface类名:父类名<协议名> @end;类遵守了一个协议就相当于没遵守协议之前把协议中声明的所有方法拷贝到类的声明之中。
4、正式协议与非正式协议简单介绍:
(1)在协议声明的方法之前加@required,表示要求实现,如果遵守了这个协议的类不实现@required标示的方法,就会出现警告。(仅仅警告,不会报错)。
(2)@optional表示不要求必须实现,遵守了这个协议的类无论实不实现协议中用@required标示的方法,都不会出现警告。
(3)如果协议内声明的方法前不加任何标示,协议将默认此方法是@required。
5、类不可以多继承但是可以遵守多个协议。遵守多个协议的格式是用尖括号括住多个协议名,协议名之间必须用逗号隔开。即@interface 类名:父类名<协议名1,协议名2,.....> @end;
6、协议经常用于代理模式和观察者模式。
7、协议遵守协议
(1)一个类可以继承别的类,同样协议也可以遵守协议。
(2)一个协议可以遵守多个协议,多个协议之间用逗号隔开
(3)一个协议遵守了其他协议,就相当于拥有了其他协议中的所有方法声明。
格式:@protocol 协议名称 <协议1,协议2>
@end
8、基协议详解:
(1)NSObject是一个基类,最根本最基本的类,任何其它类最终都要继承它。
(2)同样还有一个协议名字也为NSObject,它是一个基协议,最根本最基本的协议。
(3)NSObject协议中声明了很多最基本的方法,比如description、retain、release等。
(4)建议每个协议都要遵守NSObject协议,如果一个协议最终遵守了基协议那么就相当于拥有了基协议中声明的所有方法
注意:Xcode新建协议时,默认情况下都会遵守基协议。例如新建了一个MyProtocol协议,会自动生成如下语句:
@protocolMyProtocol <protocol>
@end
切记:以后在写每个协议时都要在最后遵守基协议;
9、限制对象类型:
前提——多态;当我们想让遵守了某个协议的子类对象赋给父类对象指针,即让父类指针对子类对象进行筛选使其只能指向遵守了制订协议子类对象。
(情况一):要求父类指针只能指向遵守了某个协议的子类对象;使用如下格式限制父类指针指向的子类对象:
父类名<指定的协议> *父类指针=[[子类名 alloc] init];如果我们将没有遵守指定协议的子类对象赋给父类指针时将会报错。
例1:NSObject<MyProtocol> *obj=[[Person alloc] init];
以这种形式的obj指针可以指向遵守了MyProtocol协议的任何子类对象。这种常用形式也可以换成另外一种方式进行代替:
id<MyProtocol> obj=[[Person alloc] init];
(情况二):要求父类指针只能指向遵守了某个协议且继承了某个类的子类对象,把情况一中的NSObject换成要求子类继承的那个类名即可。语法格式如下:假设要求子类继承的父类名为Person,要求子类遵守的协议为:MyProtocol。这样就可以写成如下格式:
Person<MyProtocol> *obj=[[子类名 alloc] init];表示obj只能指向遵守了MyProtocol协议且继承了Person类的子类对象。
10、在@property中限制对象类型:例如在类(假设为Person)的声明中如下:
@property(nonatomic,strong)id<MyProtocol> obj或
@property(nonatomic,strong)NSObject<MyProtocol> *obj; 其中 id:表示任意对象的指针。MyProtocol:表示要遵守的协议。obj:表示为其提供set/get方法的对象(对象指针)。意思就是调用set/get方法设置obj这个对象的时候,obj这个对象必须遵守了MyProtocol这个协议。假设在这种情况下:把一个Dog类的对象d对一个Person类对象p的对象变量obj赋值时,即p.obj=d;会调用obj的set方法进行赋值,如果Dog类没有遵守Myprotocol协议就会报错。
11、前向声明:已知类的前向声明如@class Person;等于在当前文件中告诉编译器Person是个类,这样即使没有在当前文件中导入前向声明的类所在的头文件也不会报错,因为前向声明仅仅告诉别的文件这是个类,并没有把声明的类的文件内容给导进来。但是必须在当前类的.m实现文件中导入前向声明的类所在的头文件,这样在实现当前类的成员方法时才能使用Person类定义的方法及公共成员变量。同理协议也是如此:协议的前向声明的关键字是@protocol+协议名;然后在当前类的.m文件中导入前向声明中的协议所在的头文件。
注意:在一个类中使用别的文件中声明的类和协议时有两种解决方法 —>
(1)不使用前向声明。仅仅在当前类的头文件中导入所使用的类或协议所在的头文件即可。
(2)使用前向声明。在当前类的声明(@interface)前用“@protocol 别的文件中定义的的协议”或“@class 在别的文件中声明的类”,然后在当前类的实现文件(.m)文件中导入前向声明中的类或协议所在的头文件即可。
12、知识点补充:类的协议可以单独写在一个头文件。也可以写在类的头文件中,即和类的声明写在一块;即和类的声明同占一个头文件。这要根据具体情况进行选择:当这个协议仅仅用于这个类时,就写在这个类的声明所在的头文件。当这个协议交给多个类去实现时,就单独写在一个.h头文件之中。
类的分类与此类似:但是针对的情况不同,当分类的方法声明较少时完全可以将分类的声明写在类声明所在的.h头文件中同时将分类的实现写在类实现所在的.m文件中。
13、协议的语法格式总结:
(1)协议的定义
@protocol协议名称 <NSObject>
//方法声明列表,,,,
@end
(2)如何遵守协议
1> 类遵守协议
@interface 类名:父类名 <协议名称1,协议名称2>
@end;
2> 协议遵守协议
@protocol 协议名称 <其他协议名称1,其他协议名称2>
//方法声明列表,,,,
@end
(3)协议中方法声明的关键字
1>@required(默认) 要求实现,若没实现,将出现警告。
2>@optional 不要求实现,实不实现都不会有警告。
(4)定义一个变量的时候,限制这个变量保存的对象遵守某个协议
“类名<协议名称> *变量名”或”id<协议名称> 变量名”。
如果没有遵守对应的协议,编译器会发出严重警告(代码下面带黄色下划线,必须修复)。
(5)@property中声明的属性也可以用做一个遵守协议的限制:
“@property (nonatomic,strong)类名<协议名称> *属性名”
或“@property(nonatomic,strong)id<协议名称> 属性名”
(6)协议可以定义在单独的.h文件中,也可以定义在某个类中
1>如果这个协议只用在某个类中,应该把协议定义在该类中
2>如果这个协议用在很多类中,就应该定义在单独文件中
(7)分类可用于定义在单独的.h和.m文件中,也可以定义在原来的类中
1>一般情况下,都是定义在单独的文件中。
2>当分类方法很少时,就定义在原来的类中。
14、