一、在IOS开发中,有一个非常常见的定义,就像property一样,它就是protocol。
下面我就protocol做一个初层次的概述;
1、首先,讲讲protocol的定义;作为一个OC里面的一个专门用来定义协议的关键字,通常格式为:@protocol 协议名称 <NSObject> ..... @end;
2、如何遵守协议;它包括了:
1)类的遵守协议;比较常见的格式为:
@interface 类名 :父类 <协议1,协议2> .......... @end
2)协议遵守协议;比较常见的格式为:
@protocol 协议名称 <其他协议>................. @end
3、协议的方法实现中声明关键字
1)@required 这后面的方法表示一定要实现的。如果没有写明,默认一定要实现
2)@optional 这后面的方法表示不一定要实现的,可以选择性实现
4、在定义一个变量的时候,可以用协议来限制变量,使这变量遵循某一协议。例如,NSObject <协议名称> *变量名
5、@property 中声明的属性也可以用一个需要遵守协议的限制。例如,@property (nonatomic,stong)类名 *属性名
6、protocol定义的协议以作为一个独立的协议单独使用,也有可以在一个类中使用。但是要注意,当多个类都要用时,只能单独放在一边。而只有一个类用才可以写在这个类一起。
7、有一个关键字的使用与protocol有相似一处,它就是分类。分类也可以单独使用,也可以放在类一起,但是也同时也要注意,多个要用时,也只能单独放一个文件。
综上述,protocol在我们IOS中很常见,经常使用,创建一些合理的协议,对整个程序的架构有很大帮助。所以需要更深入的去学习protocol的相关用法,最后使自己成为一个优秀的IT人!
二、通知
1、通知中心(NSNotificationCenter)实际是在程序内部提供了一种广播机制。把接收到的消息,根据内部的消息转发表,将消息转发给需要的对象。这句话其实已经很明显的告诉我们要如何使用通知了。第一步:在需要的地方注册要观察的通知,第二步:在某地方发送通知。(这里注意:发送的通知可能是我们自定义的,也可能是系统的)。
- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary*)aUserInfo;
一般来说,发送通知主要是上面的三个方法;aName,通知的名称,一般取一个与这通知的作用类似的名称,并且给一个宏定义,以防接收通知时写错名称。
anObject,传递的一个对象(当然也包括对象中的各个属性)。aUserInfo,这主要是传递值的字典(注意非对象存字典的时候,需要转化为对象才能存),通知传值一般情况下都用它来传。接收通知:
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;
- (id <NSObject>)addObserverForName:(nullable NSNotificationName)name
object:(nullable id)obj
queue:(nullableNSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block;
使用以上方法接收通知的时候,第一个方法的接收参数等操作在aSelector中处理。在处理过程,selector 的方法实现中 eg:- (void)receive:(NSNotification *)notification ,NSNotification有object和userInfo两个属性处理其传过来的对象和值。第二个主要是要在其block中处理其传过来的对象和值,当然我们一般把queue 定义在主线程里面。其实是用过程中建议使用这个方法。
3、使用注意事项
在接收通知的时候,我们一般是在主线程操作的,有时候,有特殊需求要在次线程中处理的,但是要注意,操作UI的时候要回到主线程。
在接收完通知的地方都需要把监听在dealloc移除、移除、移除(重要的事情说三遍):
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObject;
三、block
1、一个类似C语言函数的待执行的代码块。
- int outA = 8;
- int (^myPtr)(int) = ^(int a){ return outA + a;};
- //block里面可以读取同一类型的outA的值
- int result = myPtr(3); // result is 11
-
NSLog(@"result=%d", result);
2、使用过程中我们可以把它当成一个参数。
- -(void)objcMethod:(int(^)(int))square; //square参数的类型是int(^)(int)
3、使用注意
A、block在读取内存变量的时候,如果是一个非对象量时,它只是复制其值,而不会改变其原值,eg
- {
- int outA = 8;
- int (^myPtr)(int) = ^(int a){ return outA + a;}; //block里面可以读取同一类型的outA的值
- outA = 5; //在调用myPtr之前改变outA的值
- int result = myPtr(3); // result的值仍然是11,并不是8
- NSLog(@"result=%d", result);
- }
B、在读取一个对象变量的时候,它是读取其内存地址,因此在block里面做变量的赋值或者改变值的时候,会改变其原来的值,eg
- {
- NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];
- int result = ^(int a){[mutableArray removeLastObject]; return a*a;}(5);
- NSLog(@"test array :%@", mutableArray); // 输出的值是@{@"one", @"two"}
- }
C、如果我们要在block中改变一个非对象量的时候,我们可以用__block 来修饰这个量。实际上这样一修饰,它就成为了Block Variable类型,eg
- {
- __block int num = 5;
- int (^myPtr)(int) = ^(int a){return num++;};
- int (^myPtr2)(int) = ^(int a){return num++;};
- int result = myPtr(0); //result的值为5,num的值为6
- result = myPtr2(0); //result的值为6,num的值为7
- NSLog(@"result=%d", result);
- }
__weak __typeof(&*self)weakSelf = self
四、代理、通知、block使用差别
1、代理和block的使用都大同小异的,但是实际使用过程我们还是有一定的区别:
代理,使用的时候比较繁琐,必须有三大步骤写完整,但是我们在提供给第三方使用的时候,代理更加具有可读性和可使用性(比如我们写一个供别人使用的框架或者什么的时候,代理就是一个很好的选择)
block,使用方便,还可以当参数传,但是如果大量的用会增加代码的可读性
代理是一对一的,设置 delegate 属性,在需要的时候,通过 delegate 调用 selector 方法!
通知是一对多的,只要发生事件,会以广播的形式,通知所有的监听者
通知中心/发布通知的对象不需要知道谁是监听者,发布对象和监听者之间的耦合度很低
监听者需要知道通知的名称字符串,如果发布者还传递 userInfo 字典,监听者同时需要知道字典的键名 --(技巧:在 OC 的框架中,如果定义通知,通常通知的名字包含"Notification"字样,同时 key 会和 通知定义在一起!)
通知监听方法不能有返回值!
代理可以有返回值!
通知,一般说来能不用就不用,他的性能比较低。在我们不同的控制器之间的传值(逆传)可以选择用它。