注意这些都是界面回传(即从第二个界面传到第一个界面,从第一个界面传到第二个界面的时候用第二个界面的属性便可)
iOS消息的交互方式有4种,分别为:通知,代理,block,kvo
如今咱们对这个4中方式分别作详细的介绍
通知
//1通知的发送平台(信息的发布者)
[[NSNotificationCenter defaultCenter] postNotificationName:@"enterTicket" object:nil userInfo:@{@"index":@"0"}];//userInfo:通知携带的内容详情@{key:index value:须要跳转的位置}
//2通知到的接收平台(信息的接收者)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enterTicket:) name:@"enterTicket" object:nil];
//处理信息的方法
- (void)enterTicket:(NSNotification *)noti {
// 获取通知的详情信息
NSString *indexStr = [noti.userInfo objectForKey:@"index"];
NSInteger index = [indexStr integerValue];
}
//最后把通知移除
[[NSNotificationCenter defaultCenter] removeObserver:self];
代理(代理模式是ios中最经常使用的一种方式)
代理就像打电话,个人代理我不拥有(weak),我能够适时(时候我定)告诉个人代理消息(实现代理方法,代理方法中有个人数据,代理方法中含有的参数就是个人数据),协议就像电话,要想通话必须有电话(签协议)而后肯定接电话的人delegate = self,接到电话去干活(实现带来方法,若是我须要信息的话代理把信息返回给我,表示代理方法中有返回值)
所谓代理就是代理者可以处理代理事件(对代理对对象进行处理,本身能够是本身的代理)(例如小孩须要照顾,能够设置一个代理(保姆)照顾,代理(保姆)实现代理的方法(照顾小孩),这个方法中传入一个小孩的属性,就能够对小孩的全部的属性进行处理)
block 就只一个代码块,这个代码块当作参数传递,代码块的执行时间就是这个代码块的最终执行时间
block 就像个人小弟,我拥有block的变量我实实在在的拥有它(Strong)(block变量的声明),我能够适时告诉他作揍人(block变量实现同是能够向他传递揍谁即参数)啥时候揍是我说了算(啥时候实现变量block,走完人给我反馈结果)
谁主动(就是能够控制传值的时间,即控制何时调用block变量,和用代理调用代理方法)调用这个方法(代理方法或者block方法,谁里面就拥有block变量或者变量);消息的传递能够是相互的(即有参数有返回值)
1 block的声明
// 声明类型
//
sumBlock是block变量// 变量首字小写
int(^sunBlock)(int,int);
// SumB是类型别名//类名首字大写
typedef int(^SumB) (int,int);
2 block的定义
sunBlock = ^(int x , int y ){
return x +y;
};// sunBlock是变量
SumB bock_1 = ^(int x , int y ){
return x +y;
};// bock_1是变量
3 block的调用
sunBlock(1,2);//sunBlock变量的实现
bock_1(1,2);//bock_1变量的实现
方法的差数就是代码块
调用方法就是传递参数(代码块)
在这个方法中把这个代码块传递给新的block代码块
实现这个新的block代码块
要想实现两个对象数据的传递必须保证这两个对象同时存在(由于调用的对象必须有即信息传递方,blcok实现的对象必须有信息的接收方,用信息接收方的属性接收,故信息的接收方法是block代码的实现方,)
注意 :block 只能从第二个视图传入第一个视图中,不能从第一个视图中传入第二个视图
代理既能够从第一个视图传入第二个视图中,也能从第二个视图传入第一个视图
block实现和调用在两个类中,
实现 - 传差数(代码块)-调用-实现代码块内的内容
当按完调用,后再走实现的代码(即最后的才走实现)
走的是同一个视图控制器
补充: 界面传值和对象传值是不同的(明天)
2、Protocol(协议)java
(一)简介ios
1.Protocol:就一个用途,用来声明一大堆的方法(不能声明成员变量),不能写实现。objective-c
2.只要某个类遵照了这个协议,就拥有了这个协议中的全部方法声明。设计模式
3.只要父类遵照了某个协议,那么子类也遵照。app
4.Protocol声明的方法可让任何类去实现,protocol就是协议。框架
5.OC不能继承多个类(单继承)可是可以遵照多个协议。继承(:),遵照协议(< >)函数
6.基协议:<NSObject>是基协议,是最根本最基本的协议,其中声明了不少最基本的方法。post
7.协议能够遵照协议,一个协议遵照了另外一个协议,就能够拥有另外一份协议中的方法声明。测试
(二)基本使用ui
建立一个协议
遵照协议
完成协议中声明的方法的实现
测试程序
1.协议的定义
@protocol 协议名称 <NSObject>
//方法声明列表
@end;
2.如何遵照协议
(1)类遵照协议
@protocol 类名:父类名 <协议名称1,协议名称2>
@end
(2)协议遵照协议
@protocol 协议名称 <其余协议名称>
@end;
3.协议方法声明中的关键字
(1)required (默认)要求实现,若没有实现则警告但不报错
(2)Optional 不要求实现
4.定义变量时遵照协议的限制
类名<协议名称> *变量名 NSObject<.Myprotocol> *obj;
Id <协议名称> 变量名 id <.Myprotocol> obj1;
5.Property中声明的属性也能够作遵照协议的限制
@property (nonatomic ,strong ) 类名<协议名称> *属性名;
@property (nonatomic ,strong ) id<协议名称> 属性名;
6.补充知识:协议自己写在.h头文件中,但也能够定义在任何地方。当这个协议只有这个类使用遵照时,通常把协议写在这个类里边,当这个协议须要多个类去实现时,就写在外边单独的文件中。
代理就是委托对象
objective -c 协议(protocol)
协议(protocol)是object - c 中一个很是重要的语言特性,从概念上讲,很是相似于java中接口,一个协议其实就是一系列中有关联的方法的集合(为方便后面叙述,咱们把这个协议命名为myProtocol)协议中的方法并非由协议自己去实现,相反而是由遵循这个协议的其余类来实现,换句话说 协议myprotocol只是完成对协议函方法的声明而并并无论这些新协议方法的具体实现
声明一个协议的语法很是简单
@protocol myProtocol <NSObject>
@requiered
-(void)protocolNameA:(NSString*)string;
@optional
-(void)protocolNameB:(NSString*)string;
@end
第一行是声明这个协议的名字为myProtocol.尖括号中的NSObject自己也是一个协议,其中定义了不少基本的协方法。好比performSelector,isKindOfClass ,respond to Selector conformsToProtocol ,retain release 等
协议接口分为 required 和 optional 两类 required 顾名思义是说遵照这个协议的那个类“必需要”实现的接口,而optional则是能够实现也能够不实现。协议接口的定义和普通的方法定义是同样的
最后一行@end 表示协议定义结束。这个协议的定义一般是在.h文件中.。
定义一个类遵循这个协议
@interface myClass <myProtocol>
@intreface myClass :NSObject<myProtocol>
@intreface myClass : NSObject<myProtocol,NScoding>
上面分别是三种不一样的状况,编译的时候编译器会自动检查myClass是否实现了myProtocol中的必要的(@requierd)接口。若是没有实现则会发送一个警告信息,另外须要注意的是,若是有有继承myClass的子类,这些子类也是会自动遵循myClass所遵循的协议的,并且也能够重载这些接口
为何须要协议?
苹果的官方文档指出三个缘由
To declare mothods that others are expected to implement
To declare the interface to an object while concrealing its class
To capture similarties among classes that are not hierarchicallu related
其实还有第四个很重要的缘由,那就是减小继承类的复杂性。一个经典的例子就是 IOS UI框架里面的UITableViewController类。假如没有“协议”功能。用户就必须选择用继承和重载接口的方法来实现复杂的UI控制以及其余事件的处理——这就对基类的设计提出了更大的挑战了。对于像这样一个table view,一个很好的实现方法就是采用协议,由协议里的接口来控制不一样的数据源以及各类复杂的用户操做。UIKit中设计了两个很好的协议UITableViewDelegate,UITableViewDataSource来实现UITableViewController的控制。任何遵循这两个协议的类均可以实现对UITableView的控制。
关于 id类型的运用:(不喜欢钻牛角尖的朋友,能够略过这一部分)
id 类型在iOS中是一个通用类型,有点相似C语言的void*类型。编译器不能检查到定义为id类型的变量的实际类型,id类型的识别是发生在运行时阶段。可是咱们能够用 id<protocol_name> obj;这样的语法形式在编译阶段就可让编译器知道obj只能够发送protocol_name中的消息,若是所发送的消息不在protocol_name中,编译器会给一个警告信息“Instance method 'xxxx:' not found......”。这种状况多用于代理模式的实现,好比某一个类有一个delegate 的property:
id <myProtocol>delegate;
这样,在编译阶段咱们就能够知道用delegate所发送的消息是否是在它所遵循的myProtocol中的消息。好了, 到这里笔者钻起了牛角尖,我把id后面的 <myProtocol>删掉,而后用delegate发送一个并不存在于myProtocol中的消息,结果编译器仍是给了“Instance method 'xxxx:' not found......”的警告信息。更奇怪的是,当发送一个存在于myProtocol中的消息时,编译器居然没有这样的警告信息。这两个测试并不能说明以前的解释是错误的,姑且认为id<myProtocol> delegate这种写法是为了便于知道这个delegate遵循了myProtocol的协议吧.
什么是代理?
苹果的官方文档给了很清晰的解释:
Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.
意译一下就是:代理是一种简单而功能强大的设计模式,这种模式用于一个对象“表明”另一个对象和程序中其余的对象进行交互。 主对象(这里指的是delegating object)中维护一个代理(delegate)的引用而且在合适的时候向这个代理发送消息。这个消息通知“代理”主对象即将处理或是已经处理完了某一个事件。这个代理能够经过更新本身或是其它对象的UI界面或是其它状态来响应主对象所发送过来的这个事件的消息。或是在某些状况下能返回一个值来影响其它即将发生的事件该如何来处理。代理的主要价值是它可让你容易的定制各类对象的行为。注意这里的代理是个名词,它自己是一个对象,这个对象是专门表明被代理对象来和程序中其余对象打交道的。
Cocoa中的代理
Cocoa Touch框架里大量使用了代理这种设计模式,在每一个UI控件类里面都声明了一个类型为id的delegate或是dataSource,查看Cocoa的头文件能够发现不少以下的属性:
@property(nonatomic, assign)id<UIActionSheetDelegate> delegate; // weak reference
一般格式为@property(nonatomic, assign)id<protocol_name> delegate; 即这个代理要遵循某一个协议,也就是说只有遵循了这个协议的类对象才具有代理资格。这同时也要求了代理类必须在头文件中声明遵循这个protocol_name协议并实现其中的@required方法,@optional的方法是可选的。
以UIActionSheet为例,咱们定义一个View,当点击这个View中的某一个按钮时触发UIActionSheet, 当用户对UIActionSheet完成了某一项操做,好比Destruct按钮被按下,或是cancel按钮被按下,UIActionSheet会发送消息给delegate,由delegate完成对用户操做的响应,好比打印一个字符串到屏幕上。图示说明以下:
首先,咱们建立一个基于tab的工程,在FirstViewController.h中添加代码,使这个类遵循UIActionSheetDelegate协议:
- @interface FirstViewController : UIViewController <UIActionSheetDelegate>
在View中添加一个按钮用于触发这个ActionSheet,而后编写这个按钮的响应代码:
- (IBAction)invokeActionSheet:(id)sender {
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:@"Delegate Example"
delegate:self // telling this class(ViewController) to implement UIActionSheetDelegate
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:@"Destruct"
otherButtonTitles:@"Button 1",@"Button 2",nil];
[actionSheet showInView:self.tabBarController.view];
[actionSheet release];
}
注意,上面有一个很重要的设置就是参数中有个delegate:self,这个设置就是指明了UIActionSheet的代理为self, 也即FirstViewController
而后在FirstViewController.m中实现UIActionSheetDelegate中的方法:
#pragma mark --UIActionSheet delegate methods
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
switch (buttonIndex) {
case 0:
self.myTextFromActionSheet.text = @"Action Destructed!";
break;
case 1:
self.myTextFromActionSheet.text = @"Action Button 1 Clicked!";
break;
case 2:
self.myTextFromActionSheet.text = @"Action Button 2 Clicked!";
break;
case 3:
self.myTextFromActionSheet.text = @"Cancel Button Clicked!";
break;
default:
break;
}
}
上面的几步咱们完成了对Cocoa中UIActionSheet已有代理的运用。然而咱们不少时候须要本身编写定制的代理,该如何实现呢?
自定义代理
咱们要作的是,建立一个view,自定义一个代理实现更新这个view中的字符串。上面咱们已经建立好了一个tab工程,借用里面的second view。咱们拖一个按钮到上面命名为ChangeText,响应函数为- (IBAction)changeText:(id)sender;点击这个按钮进入一个modal view 名为ChangeTextView,咱们在ChangeTextView中输入一个字符串并在退出这个view后把这个字符串更新到second view上面。如何实现modal view和second view之间的数据传递呢?那就是代理!谁的代理?ChangeTextView的代理!由于咱们直接在ChangeTextView中输入数据,须要由代理把输入的字符串反馈到second view上面去。
一、建立一个新的类ChangeTextViewController,并建立相应的xib文件。
二、在ChangeTextViewController.h中声明一个协议ChangeTextViewDelegate:
@protocol ChangeTextViewDelegate <NSObject>
- (void) textEntered:(NSString*) text;
@end
和UIActionSheet相似,在ChangeTextViewController中咱们也须要添加一个代理的声明:
@property (assign, nonatomic) id<ChangeTextViewDelegate> delegate;
三、咱们还须要在ChangeTextViewController.xib中添加一个按钮save,当按下这个按钮会返回到second view中,并更新字符串。对save按钮的响应函数为:
- (IBAction)saveButtonClicked:(id)sender {
//Is anyone listening
if([delegate respondsToSelector:@selector(textEntered:)])
{
//send the delegate function with the amount entered by the user
[delegate textEntered:textEntered.text];
}
[self dismissModalViewControllerAnimated:YES];
}
[delegate textEntered:textEntered.text];这句代码的含义就是ChangeTextViewController通知代理,textEntered这个事件发生了,对textEntered这个消息的实现,即如何响应这个textEntered的事件由代理来实现。在本例中,SecondViewController就是ChangeTextViewController对象的代理。因此,咱们要对SecondViewController作相应的设置使其知足代理的条件。首先,在SecondViewController.h中声明遵循协议ChangeTextViewDelegate。而后编辑ChangeText按钮的响应函数- (IBAction)changeText:(id)sender;
- (IBAction)changeText:(id)sender {
ChangeTextViewController *CTViewController = [[ChangeTextViewController alloc] initWithNibName:@"ChangeTextViewController" bundle:nil];
//Assign this class to the delegate of ChangeTextViewController,
//remember to make thie ViewController confirm to protocol "ChangeTextViewDelegate"
//which is delared in file ChangeTextViewController.h
CTViewController.delegate = self;
[self presentModalViewController:CTViewController animated:YES];
}
注意,CTViewController.delegate = self;这句实现了SecondViewController成为ChangeTextViewController对象的代理
block (代码块)
//信息的发布者
信息发布者的类
1 Blcok 类型重命名(这个Block用Person代替,这个Block中传入参数是个字符串,返回的参数是void)
typedef void(^PersonBlock)(NSString *name);
2在这个类中声明这种Block类型的属性
PersonBlock _block;
3这个类中声明一个带有Block类型参数的方法
- (void)getPersonName:(PersonBlock)block;
4上面方法的实现
- (void)getPersonName:(PersonBlock)block {
_block = block;
}
//信息的接受者
初始化信息发布者的类
Person *per = [[Person alloc] init];
调用信息发布者的类中带有Block参数的方法
[per getPersonName:^(NSString *name) {
NSLog(@"%@",name);
}];
Block是什么?苹果推荐的类型,效率高,在运行中保存代码。用来封装和保存代码,有点像函数Block能够在任什么时候候执行。
Block和函数的类似性:(1)能够保存代码(2)有返回值(3)有参数(4)调用方式同样
(二)基本的使用
(1)定义BLOCK变量
Int(^SumBlock)(int,int) ;//有参数,返回值类型为int
Void (^MyBlock)()//无参数,返回值类型为空
(2)利用block封装代码
(3)Block访问外部变量
1)Block内部能够访问外部变量;
2)默认状况下,Block内部不能修改外部的局部变量
3)给局部变量加上__block关键字,则这个局部变量能够在block内部进行修改。
(4)利用typedef定义block类型(和指向函数的指针很像)
Typedef int(^MyBlock)(int ,int);
之后就能够利用这种类型来定义block变量了。
MyBlock a,b;
a=^(int a,int b){return a-b;};
MyBlock b2=^(int n1,int n2){return n1*n2;}
3..
//注意事项
根据程序加载顺序
初始化
//——————————————————信息发布者的类.h文件-------------------------------------
#import <Foundation/Foundation.h>
typedef void(^PersonBlock)(NSString *name);
@interface Person : NSObject
{
PersonBlock _block;
}
- (void)getPersonName:(PersonBlock)block;
@end
//--------------------
信息发布者的类.m
文件——————————————————//
#import "Person.h"
@implementation Person
{
NSString *_name;
}
- (id)init {
if (self = [super init]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
_name = @"晓彬";
_block (_name);
});
}
return self;
}
- (void)getPersonName:(PersonBlock)block {
_block = block;
}
@end
//信息接受者文件
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Person *per = [[Person alloc] init];
[per getPersonName:^(NSString *name) {
NSLog(@"%@",name);
}];
}
@end
kvo
//直接修改属性值,不能触发KVO
// _happyValue--;
//1.调用set方法来修改属性值,能够触发KVO
// self.happyValue = _happyValue - 1;
//2.使用KVC修改属性值,也能触发KVO
NSInteger value = _happyValue;
NSNumber *valueNumber = [NSNumber numberWithInteger:--value];
[self setValue:valueNumber forKey:@"happyValue"];
//修改hungryValue
self.hugryValue = _hugryValue - 2;
_children = child;
//使用KVO来监听小孩属性值的变化
//_children 做为被观察者
//observer 事件的观察者:self
//KeyPath:监听被观察者的某个属性值
//options:
//NSKeyValueObservingOptionNew:监听观察修改后的属性值
//NSKeyValueObservingOptionOld:监听观察修改前的属性值
[_children addObserver:self
forKeyPath:@"happyValue"
options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
context:nil];
/
block 是匿名的代码端
// 声明和实现
(^block名 )(参数){
代码段
}
// 调用
block 变量
/