KVO:Key-Value Observing
每次指定的被观察者的对象属性改变后,KVO自动通知相应的观察者。
与代理模式有异曲同工之妙。
实现步骤:
1.注册 确定观察者,被观察者着,和指定的被观察者的属性
2.实现回调方法(在观察者类中实现)
3.移除观察 由被观察者调用
观察者
// ViewController.m
// 907重做图片排列
#import "ViewController.h"
#import "SecondViewController.h"
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
#define SPACE_SMALL 40
#define IMAGE_SIZE 40
@interface ViewController ()
{
UISegmentedControl *sortSegment;//排列分段
NSMutableArray *btnAry;//按钮数组
SecondViewController *nextView;//下一页
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
nextView=[[SecondViewController alloc] init];
//添加分段
[self addSortSegment];
//添加默认的按钮
[self addSolarBtns];
sortSegment.selectedSegmentIndex=1;
[self clickSegment:sortSegment];
//下一页按钮
[self addToNextBtn];
//1.注册
[nextView addObserver:self forKeyPath:@"tag" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
}
#pragma mark-2.回调函数
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
NSLog(@"KVO 回调方法。。。。。");
//当被观察者,被观察的属性有多个时,需要根据被观察对象,被观察属性进行判断
if ([object isEqual:nextView]) {
if ([keyPath isEqualToString:@"tag"] ) {
NSUInteger tag=[[change objectForKey:@"new"] integerValue];
if (tag==1) {
//加
[self addOneFace];
}
if(tag==2){
[self subOneFace];
}
}
}
}
#pragma mark-3.移除观察
-(void)dealloc{
[self removeObserver:nextView forKeyPath:@"tag"];
}
#pragma mark-添加一个表情到数组
-(void)addOneFace{
UIButton *btn=[[UIButton alloc] initWithFrame:CGRectMake(0,0,IMAGE_SIZE, IMAGE_SIZE)];
[btn setBackgroundImage:[UIImage imageNamed: [NSString stringWithFormat:@"icon%i.gif",arc4random()%12+1]] forState:UIControlStateNormal];
[btnAry addObject:btn];
[self.view addSubview:btn];
[self clickSegment:sortSegment];
}
#pragma mark-删除一个表情
-(void)subOneFace{
UIButton *btn=[btnAry objectAtIndex:arc4random()%btnAry.count];
NSLog(@"last:%lu",btnAry.count);
[btnAry removeObject:btn];
NSLog(@"删除后:%lu",btnAry.count);
[btn removeFromSuperview];
[self clickSegment:sortSegment];
}
#pragma mark-添加跳转到下一页的按钮
-(void)addToNextBtn{
UIButton *nextBnt=[[UIButton alloc] initWithFrame:CGRectMake(SCREEN_WIDTH-SPACE_SMALL*3,SCREEN_HEIGHT-2*SPACE_SMALL, SPACE_SMALL*2, SPACE_SMALL)];
[nextBnt setTitle:@"下一页" forState:UIControlStateNormal];
nextBnt.backgroundColor=[UIColor redColor];
[self.view addSubview:nextBnt];
[nextBnt addTarget:self action:@selector(clickTonextBtn:) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark-下一页按钮监听
-(void)clickTonextBtn:(UIButton *)sender{
self.modalTransitionStyle=UIModalTransitionStyleCoverVertical;
[self presentViewController:nextView animated:YES completion:nil];
}
#pragma mark-排列
-(void)clickSegment:(UISegmentedControl *)sender{
//列数
NSUInteger line=sender.selectedSegmentIndex+2;
//宽度间隙
float space=(SCREEN_WIDTH-line*IMAGE_SIZE)/(line+1);
for (int i=0; i<btnAry.count; i++) {
UIButton *btn=[btnAry objectAtIndex:i];
int row=i/line;//所在行
int col=i%line;//所在列
float xx=space+(space+IMAGE_SIZE)*col;
float yy=CGRectGetMaxY(sortSegment.frame)+SPACE_SMALL+ (SPACE_SMALL/4+IMAGE_SIZE)*row;
[UIView animateWithDuration:0.5 animations:^{
btn.frame=CGRectMake(xx, yy, IMAGE_SIZE, IMAGE_SIZE);
}];
}
}
#pragma mark-添加默认的星座按钮
-(void)addSolarBtns{
btnAry=[NSMutableArray array];
for (int i=0; i<12; i++) {
UIButton *btn=[[UIButton alloc] initWithFrame:CGRectMake(SPACE_SMALL,CGRectGetMaxY(sortSegment.frame)+SPACE_SMALL+ (SPACE_SMALL/4+IMAGE_SIZE)*i,IMAGE_SIZE, IMAGE_SIZE)];
[btn setBackgroundImage:[UIImage imageNamed: [NSString stringWithFormat:@"icon%i.gif",i+1]] forState:UIControlStateNormal];
[self.view addSubview:btn];
[btnAry addObject:btn];
// NSLog(@"%f",CGRectGetMaxY(sortSegment.frame));
}
}
#pragma mark-添加
-(void)addSortSegment{
sortSegment=[[UISegmentedControl alloc] initWithItems:@[@"两列",@"三列",@"四列",@"五列"]];
sortSegment.frame=CGRectMake(SPACE_SMALL,SPACE_SMALL, 240,SPACE_SMALL);
sortSegment.tintColor=[UIColor redColor];
[self.view addSubview:sortSegment];
sortSegment.selectedSegmentIndex=1;
[sortSegment addTarget:self action:@selector(clickSegment:) forControlEvents:UIControlEventValueChanged];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
被观察者
//
// SecondViewController.m
// 907重做图片排列
//
// Created by jerehedu on 16/9/7.
// Copyright © 2016年 jerehedu. All rights reserved.
//
#import "SecondViewController.h"
@interface SecondViewController ()
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
#pragma mark-返回按钮监听
- (IBAction)clickToBack:(UIButton *)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark-添加或者删除表情
- (IBAction)clickTochangeImageCount:(UIButton *)sender {
[self setValue:@(sender.tag) forKey:@"tag"];
NSLog(@"tag=%lu",self.tag);
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end