iOS小技能:本地通知的机制

407 阅读4分钟

「这是我参与2022首次更文挑战的第41天,活动详情查看:2022首次更文挑战」。

前言

  1. 通知的发布
  2. 通知的监听
  3. 通知的移除

本地通知和代理的选择:

  1. 共同点:都能饿按此对象间的通信
  2. 不同点:代理是一对一关系;通知是多对多的关系(1个对象能告诉N个对象发生了什么事情,1个对象能得知N个对象发生了什么事情)

I 本地通知的使用

1.1 通知中心(NSNotificationCenter)

每个应用程序都有一个通知中心:专门负责协助不同对象间的消息通信 1.任何一个对象都可以向通知中心发布通知(NSNotification),来描述自己在做什么事情。 其他感兴趣的监听器(Observer)可以申请在某个特定通知发布时(或者某个特定的对象发布通知时),收到这个通知。

这里写图片描述

1.2 通知对象(NSNotification)

  1. 一个完整的通知通常包含三个属性:通知名称name、通知的发布者、一些额外的信息UserInfo
  2. 初始化一个通知对象
  3. 发布通知(通知中心NSNotificationCenter 提供了相应的方法来帮助发布通知)

1.3 注册通知监听器

NSNotificationCenter 提供了相应方法来注册一个监听通知的监听器(observer)

- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;
 
/**
observer:监听器,即谁要接收这个通知;
aSelector:收到通知后,回调监听器的这个方法,并且把通知对象当做参数传入;
aName:通知的名称。如果为nil,那么无论通知的名称是什么,监听器都能收到这个通知;
anObject:通知的发布者。如果为anObject和aName都为nil,监听器都收到所有的通知
- (id)addObserverForName:(NSString*)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification* note))block;
/**
name:通知的名称;
obj:通知发布者;
block:收到对应的通知时,会回调这个block;
queue:决定了block在哪个操作队列中执行,如果传nil,默认在当前操作队列中同步执行;

1.4 取消注册通知监听器

通知中心不会retain监听器对象,在通知中心注册过的对象,必须在该对象释放前取消注册;否则,当相应的通知再次出现时,通知中心仍然会向该监听器发送消息,可能会导致应用的崩溃。--- 尤其再iOS8,7 系统经常发生

NSNotificationCenter 提供了相应的方法来取消注册observer。

- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;
//一般在监听器销毁之前取消注册(如在监听器中加入下列代码):
- (void)dealloc
{
  //[super dealloc];  非ARC中需要调用此句   
[[NSNotificationCenter defaultCenter] removeObserver:self];
 
}

1.5 键盘通知

我们经常需要在键盘弹出或者隐藏的时候做一些特定的操作,因此需要监听键盘的状态

  1. 键盘状态改变的时候,系统会发出一些特色的通知
//1. 注册Observer
 
[center addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
  1. 系统发出键盘通知的时候,会附带一下跟键盘有关的额外字典信息
  2. 通知处理示例
/**
 
 处理键盘通知
 
 处理好view的frame和键盘frame的关系--移动view
 
 */
 
- (void)keyboardWillChangeFrame: (NSNotification *) notification{
 
    NSLog(@"%@",notification.userInfo);
 
    //修改UIWindow的背景颜色
 
    //    UIWindow  *keyWindow =[UIApplication sharedApplication].keyWindow;
 
    [self.view.window setBackgroundColor:self.tableView.backgroundColor];
 
 
 
 
    //键盘的弹出完成时的frame    UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 227}, {320, 253}}";
 
    //键盘隐藏结束之后的frame   UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 480}, {320, 253}}";
 
    CGRect keyBoardFrame  = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
 
    //2.动画平移view控件
 
   // UIKeyboardAnimationDurationUserInfoKey = "0.25";
 
    //1>获取动画的持续时间
 
    CGFloat keyBoardAnimationDuration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];
 
    //2>计算平移的y值
 
    CGFloat keyBoardY =  keyBoardFrame.origin.y ;//键盘的实时y值
 
    CGFloat y = keyBoardY- KScreenHeight;//平移的y值
 
    [UIView animateWithDuration:keyBoardAnimationDuration animations:^{
 
        [self.view setTransform:CGAffineTransformMakeTranslation(0, y)];//设置平移的x、y值
 
    }];
 
}
 
#pragma mark - scrollView 的代理方法
 
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
 
    NSLog(@"%s",__func__);
 
    //关闭键盘,此时view的frame要还原
 
    [self.view endEditing:YES];
 
}

II block的使用

2.1 使用typeblock实现消息的传递



/**  使用typeblock实现消息的传递*/
 
typedef void(^HSHeaderViewBlockForClick)(id);//定义block,常常使用copy
 
@property (nonatomic,copy) HSHeaderViewBlockForClick block;//属性定义
 
/** 执行自己的block*/
#pragma mark - titleButtonViewClick事件的处理
/**
 合并cell,展开cell的触发处理
 */
- (void) titleButtonViewClick: (HSHeaderView *) headerView{
    //当分组的cell个数为0 的时候,即使合上,设置一个展开、合上标志属性,以便进行操作方法:(CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    [self.friendsGroup setIsOpen:!self.friendsGroup.isOpen];
    //方式一、通知代理
//    //先判断代理对象是否实现了代理方法
//    if ([self.delegate respondsToSelector:@selector(headerViewForclick:)]) {
//        [self.delegate headerViewForclick:self];
//    }
    //方式二、block
    if (self.block) {
        self.block(self);//执行block
    }
 
}
 
 

2.2 例子

#pragma mark -  
#if 1
 
/**
 
 自定义UITableViewHeaderFooterView
 
 关于控件没显示的经验小结:
 
 1》父控件的frame
 
 2》当前控件的frame
 
 3》当前控件的hidden属性
 
 4》当前控件的alpha<= 0.01
 
 */
 
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
 
    HSFriendsGroup *friendsGroupModel = self.fridendsGroupArray[section];
 
    HSHeaderView *headerView = [HSHeaderView tableHeaderViewWithFriendsGroup:friendsGroupModel TableView:tableView];
 
    //设置代理对象
 
//    [HeaderView setDelegate:self];
 
    //设置block,定义具体实现
 
    [headerView setBlock:^(HSHeaderView * view ){
 
        //刷新分组数据
 
        NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:section];
 
        [tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];
 
    }];
 
    [headerView setSection:section];
 
    return headerView;
 
}
 
#endif

see also

案例:QQ聊天界面&QQ好友列表:kunnan.blog.csdn.net/article/det…