Tony in iOS08/08/2013

iOS 通知观察者的被调函数不一定运行在主线程

今天修复Bug时候发现的一个小细节,记录下。

问题描述

事情是这样的:我在A视图(UITableView)注册了一个通知,当接收到此通知时,就重新读取数据并调用[tableView reloadData]。但是视图有时刷新后的显示的内容不对,再重新切换下视图又正常了。

代码如下:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//A视图在初始化时注册通知
- (void)viewDidLoad {
    //...
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadFavDBData:) name:@"refreshMyFavortieData" object:nil];
}
 
//接收通知后的被调函数
- (void)reloadFavDBData:(NSNotification*)sender
{
    [_dataArray release];
    _dataArray = [MusicCollectedDataOperate getSongCollectedInfoWithKeyword:nil];   //重新获取数据
    [tableView reloadData];
}
 
//调用者在一个线程中运行,调用通知告诉A视图刷新数据
[[NSNotificationCenter defaultCenter] postNotificationName:@"refreshMyFavortieData" object:nil];

分析 & 解决

经过一番调试,在被调函数reloadFavDBData打了断点后意外发现,它并不是在主线程运行的!而我们在这里做了与UI相关的[tableView reloadData]操作——在非主线程做UI刷新操作,导致了显示异常的问题。

解决办法也很简单,在被调函数中切换到主线程再做操作就行啦。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)reloadFavDBData:(NSNotification*)sender
{
    @synchronized(self) //保证线程安全
    {
     //获取新数据,请注意这里和上述代码的区别,由于获取数据操作耗时相对较长,
//原实现方式可能导致TableView获取数据时崩溃
        NSArray *tmpArray = [MusicCollectedDataOperate getSongCollectedInfoWithKeyword:nil];
        //切换到主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            [_dataArray release];
            _dataArray = [tmpArray retain];
            [self.refreshTableView.myTableView reloadData];
        });
    }
}

WHY?

测试得来的结论还是不够完整。翻了翻官方文档,在NSNotificationCenter部分看到这样一段话:

In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself.

在多线程程序中,通知总是在发送通知者的线程中调用(delivered,可以这么理解么?),结合上述所遇到的情况,我的理解是,通知观察者的被调函数总是运行在发送通知者的线程中,如下图所示:

这个结论告诉我们,通知的被调函数不一定运行在主线程中,如果需要做UI相关操作,需要手动切换到主线程。

有空再尝试看看通知的实现原理,应该会有更透彻的理解。

iOS 通知观察者的被调函数不一定运行在主线程的更多相关文章

  1. iOS通知的整理笔记

    iOS通知用于高耦合界面的传值确实方便快捷. 需要实现模态弹出的视图控制器上,有一个视图控制器可以导航.这必定要将这个视图控制器的导航视图控制器naVC.view添加到模态弹出的视图控制器presen ...

  2. iOS 推送所调用的函数详解

    AppDelegate类中: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDic ...

  3. iOS通知中心

    iOS通知中心 它是iOS程序内部的一种消息广播机制,通过它,可以实现无引用关系的对象之间的通信.通知中心他是基于观察者模式,它只能进行程序内部通信,不能跨应用程序进程通信. 当通知中心接受到消息后会 ...

  4. iOS开发25个性能调优技巧

    1. 用ARC管理内存 ARC(Automatic Reference Counting, 自动引用计数)和iOS5一起发布,它避免了最常见的也就是经常是由于我们忘记释放内存所造成的内存泄露.它自动为 ...

  5. iOS 下APNS推送处理函数具体解释

    相比起Android,iOS在推送方面无疑惯例得更好.APNS(Apple Push Notification Service)是苹果公司提供的消息推送服务.其原理就是.第三方应用将要推送给用户的信息 ...

  6. IOS 通知 alarm 记录

    所有的内容融为一体,去除某一个项不知道结果如何. 最主要的前提:APP 会长期保留在后台 1.在info.plist 文件里面,加入 audio 后台请求 2.当APP 点击home进入后台之后,请求 ...

  7. iOS 通知的变化ios9-10,新功能展示

    二.新功能展示 1  使用 /iOS通知新功能玩法 2.  全面   iOS10里的通知与推送详情 一.变化 四.Notification(通知) 自从Notification被引入之后,苹果就不断的 ...

  8. php获取当前被调函数的参数列表

    下面是php中的一个获取当前别调用函数的参数列表的测试程序,感受一下php类库的强大之处: // 测试获取参数列表 getArgs('aaa', 'bbb', 'ccc', 123, true); f ...

  9. 出于性能考虑,C语言自动地以传地址的方式将数组传递给被调函数 const 编译错误 最小权限原则

    #include <stdio.h> int main(void) { char array[5]; printf("array=%p,&array[0]=%p,& ...

随机推荐

  1. svn命令获取项目中被忽略文件情况

    第一步.通过终端进入项目目录下第二步.运行命令svn pg svn:ignore -R

  2. c++新特性实验(5)声明与定义:属性列表(C++11 起)

    1.初识属性 1.1 实验A: noreturn 属性 [[ noreturn ]] static void thread1(void *data){ cout << "nore ...

  3. 批量操作文本文件进行dos/unix格式转换

    批量将目录下所有文件进行 dos/unix 格式转换 使用 sed + grep #sed -i "s/原字符串/新字符串/g" `grep 原字符串 -rl 所在目录` eg:  ...

  4. poweroj1745: 餐巾计划问题

    传送门 最小费用最大流. 每天拆成两个点,i表示用完的餐巾,i+n表示干净的餐巾. s向i连容量为ri费用为0的边,表示每天用脏的ri条餐巾. i+n向t连容量为ri费用为0的边,表示每天需要用ri条 ...

  5. SSM3-SVN的安装和搭建环境

    1.安装svn 2.创建仓库 3.设置用户 . 4.eclipse和svn的集成 eclipse里安装SVN插件,一般来说,有两种方式: 直接下载SVN插件,将其解压到eclipse的对应目录里 使用 ...

  6. java并发系列(五)-----如何正确的关闭一个线程

    正确的关闭一个线程可不是简单的事情,由于线程调度的复杂性以及不可控性(毕竟运行都由操作系统做主),先来了解一下interrupt() 1.interrupt() 根据jdk文档的介绍,如下: inte ...

  7. 汉诺塔III HDU - 2064

    汉诺塔III HDU - 2064   约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下.由小到大顺序串着由64个圆盘构成的塔.目的是将最左边杆上的盘全部移到右 ...

  8. R语言可视化--ggplot函数

    上一篇说了qplot函数,现在说一下ggplot函数 本身不能实现,需要添加层才可以.ggplot2的核心函数 library(ggplot2) ggplot(airquality,aes(Wind, ...

  9. Javascript-选择器集合调用方法

    <script type="text/javascript"> function uu(namePd) { //判断id var reId = new RegExp(/ ...

  10. 微信小程序之项目的创建

    之前就想学习一下微信小程序,只不过前段时间在学习Java中的一些线程的知识,拖了很久也没有实行这个目标,今天终于从网上找了一个完整的视频,来从头学习完整的开发流程,现在逐渐有一种想法,就是自己构建项目 ...