IOS通知机制

简介

通知对象可以携带数据,然后通过通知中心(notification center)进行广播,若想要响应这个通知,接受者需要注册监听这个通知。通知机制的工作原理给我们一个机会,我们可以利用通知机制,达到解藕程序的目的。我们可以把模块的通用功能封装成组件,与业务相关的功能,可以交给组件的使用者实现。组件和组件使用者之间的通信恰好可以使用通知机制来完成。iOS中有三种类型的通知,普通通知,本地通知,以及远程通知。本文讲解的是normal notification,也就普通通知,他是一个NSNotification类型的对象。

发送通知

发送通知的过程:首先,我们需要构造一个通知对象NSNotification,然后通过通知中心NSNotificationCenter的实例方法postNotification广播出去。

头文件

static NSString *const kNotificationName=@"kNotificationName";
@interface ViewController : UIViewController
@end

发送通知实现代码

 NSNotification *notification=[NSNotification notificationWithName:kNotificationName
        object:self
        userInfo:@{@"key1":@"value1",
                   @"key2":@"value2"}];
    [[NSNotificationCenter defaultCenter] postNotification:notification];

NSNotification对象具有几个重要的属性

Name

         这是一个字符串,我们必须为每一个通知指定一个名字,当我们监听通知的时候,需要指明通知的名字。因此,当我们自定义通知的时候,在定义通知名字的头件中详细描述通知的用处,发送对象是谁,包含哪些数据。我们可以参考一下系统文件UIWindow.h中键盘显隐相关的通知的定义。

// Each notification includes a nil object and a userInfo dictionary containing the
// begining and ending keyboard frame in screen coordinates. Use the various UIView and
// UIWindow convertRect facilities to get the frame in the desired coordinate system.
// Animation key/value pairs are only available for the "will" family of notification.
UIKIT_EXTERN NSString *const UIKeyboardWillShowNotification;
UIKIT_EXTERN NSString *const UIKeyboardDidShowNotification;
UIKIT_EXTERN NSString *const UIKeyboardWillHideNotification;
UIKIT_EXTERN NSString *const UIKeyboardDidHideNotification;
Sender object

        Sender object 正如其字面意思,指明哪个对象发送通知。通常它的值是self。为什么我们需要指明到底是哪个对象发送通知?比如这样一个场景,应用程序在class1中发送了名字为MyNotification的通知,而且在另一个类class2中发送了一个相同名字的通知,如果接受者A只想接受class1发送的通知MyNotification,不想接受class2的通知,这时候我们在注册通知的时候,指明通知源头为class1就可以了。

User info dictionary

        你可以存储一些key/value键值对到字典中。你能过通过user info 传递一些重要信息给接受者。

监听和响应通知

调用NSNotificationCenter的addObserver:selector:name:object方法监听通知。这个方法的参数

addObserver

          observer确定谁来观察通知,如果是当前所在的类的话,传递self即可

selector

          selector方法接受通知notification,此方法必须有类型为NSNotification的参数

name

         通知的名字

object

        发送通知的对象

监听通知代码实现

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(responseNotification:) name:kNotificationName object:[[ViewController alloc] init]];


实例讲解(监听和响应键盘通知)

问题描述

我们创建一个简单的单视图程序,在屏幕的底部有一个textfield文本输入框,当我们点击textfield输入文字的时候,软键盘会弹出来,而且完完全全地遮住了textfield控件。

解决方案

监听键盘的通知,当键盘将要显示的时候,向上移动视图内容,键盘要隐藏的时候,向下移动视图内容。这里,为了方便视图内容的上下移动,我们放置一个UIScrollView在ViewController的view上,且填充整个view,然后将其它内容放置在UIScrollView上。
从storyboard中把scroll view,label,和text field连接到view controller的是实现文件中
#import "ViewController.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UILabel *label;
@end


在view controller的viewWillAppear:方法中添加监听UIKeyboardWillShowNotification键盘将显示通知和UIKeyboardWillHideNotification键盘将隐藏通知
- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
在view controller的viewWillDisappear:方法中移除对键盘通知的监听
- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
注意:这里有个我们常犯的错误,在viewDidLoad中开始监听通知,和在dealloc中移除监听。这会产生一些问题。我们的视图A从屏幕消失,而另一个视图B显示在屏幕中,点击B的文本输入框,系统会发出UIKeyboardWillShowNotification的通知,此时,视图A仍然能够监听到通知,因为它只是暂时地从屏幕移除,并没有被销毁,所以不会调用dealloc方法中的移除监听的操作。

实现方法handleKeyboardWilShow:
我们可以通过userInfo 字典的UIKeyboardFrameEndUserInfoKey关键字获取键盘的高度,然后调整scroll view的contentInset属性。
- (void)handleKeyboardWillShow:(NSNotification *)notification{
    //获取键盘显示过程的动画时间,以及键盘出现在屏幕中的坐标
    NSValue *animationDurationObject=[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    NSValue *keyboardFrameEndObject=[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];

    double animationDuration=0;
    CGRect keyboardFrameEnd=CGRectZero;
    [animationDurationObject getValue:&animationDuration];
    [keyboardFrameEndObject getValue:&keyboardFrameEnd];
    
    //将frame从window坐标系统转换到我们的视图坐标系统
    UIWindow *window=[[UIApplication sharedApplication] keyWindow];
    CGRect convertedKeyboardFrameEnd=[self.view convertRect:keyboardFrameEnd fromView:window];
    
    //获取键盘遮盖视图的frame
    CGRect intersectionOfKeyboardAndView=CGRectIntersection( self.view.frame,convertedKeyboardFrameEnd);
    
    //滚动scroll view
    [UIView animateWithDuration:animationDuration animations:^{
        self.scrollView.contentInset=UIEdgeInsetsMake(0.0f, 0.0f, intersectionOfKeyboardAndView.size.height, 0.0f);
    }];
}

实现方法handleKeyboardWillHide:。当键盘隐藏的时候,恢复scroll view 的contentInset属性
- (void)handleKeyboardWillHide:(NSNotification *)notification{
    NSValue *animationDurationObject=[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
    double animationDuration=0;
    [animationDurationObject getValue:&animationDuration];
    
    [UIView animateWithDuration:animationDuration animations:^{
        self.scrollView.contentInset=UIEdgeInsetsZero;
    }];
}

最后,记住实现方法text field的代理方法textFieldShouldReturn:
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
    //注销text field的作为第一响应对象,隐藏键盘
    [self.textField resignFirstResponder];
    return YES;
}


参考书名:iOS  7 programming  cookbook 
出版社:O‘Reilly
作者:Vandad Nahavandipoor

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值