NSNotificationCenter 和安全多线程

2023-11-21

鉴于即使方法调用正在进行中,对象也可能被释放(link)*,对象注册并接收将在与其预期释放的线程不同的线程上传递的通知是否安全?

作为参考,文档指出

在多线程应用程序中,通知始终在发布通知的线程中传递,该线程可能与观察者注册自身的线程不同。

同样重要的是,NSNotificationCenter 不会保留对注册接收通知的对象的强引用。

这是一个可能使情况更加具体的示例:

- (id)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:SomeNotification object:nil];
    }
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)handleNotification:(NSNotification *)notification {
    // do something
}

具有此实现的对象在线程 X 上接收 SomeNotification。在 -handleNotification: 返回之前,对该对象的最后一个强引用(在我可以看到的代码中)被破坏。

  1. 我的想法是否正确:

    A。如果 NSNotificationCenter 在调用 -handleNotification: 之前对该对象进行了强引用,那么直到 -handleNotification: 返回之后该对象才会被释放,并且

    b.如果 NSNotificationCenter 在调用 -handleNotification: 之前没有对该对象进行强引用,那么该对象可能会在 -handleNotification: 返回之前被释放

  2. 它以哪种方式(a 或 b)起作用?我还没有在文档中找到这个主题,但是在多线程环境中安全地使用 NSNotificationCenter 似乎有些重要。

UPDATE:上述链接中的答案已更新,表明“ARC 围绕弱引用的调用保留和释放”。这意味着在方法调用正在进行时不应释放对象。


我总是建议,如果您看到通知在主线程以外的线程上飞来飞去,并且您看到在后台发生释放,则您的线程可能太复杂了。 ObjC 不是一种线程友好的语言。大多数线程工作应该以队列上的短期块的形式存在。他们可以轻松地将通知发布回主线程,但不应经常使用通知。

也就是说,当今管理多线程通知的最佳方法是addObserverForName:object:queue:usingBlock:。这使您可以更好地控制生命周期。该模式应该看起来像这样:

__weak id weakself = self;
id notificationObserver = [[NSNotificationCenter defaultCenter]
 addObserverForName:...
 object:...
 queue:[NSOperationQueue mainQueue]
 usingBlock:^(NSNotification *note){
   id strongself = weakself;
   if (strongself) {
     [strongself handleNotification:note];
   }
 }];

注意weakself/strongself 的使用。我们使用weakself 来避免retain 循环。当我们回来时,我们首先采取强有力的参考。如果我们仍然存在,那么我们将被锁定在该块的其余部分(因此我们无法释放handleNotification:)。如果我们不存在,则通知将被丢弃。 (请注意,弱引用在调用之前实际上已归零dealloc. See objc_loadWeak。) 我在用着mainQueue在这里,但您当然可以使用另一个队列。

在“过去”(10.6 之前),我通过控制对象生命周期来解决这个问题。基本上,我的设计是使短期对象不会侦听可能来自其他线程的通知。这比听起来容易得多,因为在 10.6 之前的代码中,线程可以保持非常罕见(在我看来,仍然应该保持在较低水平)。NSNotificationCenter是为低线程世界而设计的。

另请注意,与-[NSNotificationCenter addObserver:selector:name:object:], -[NSNotificationCenter addObserverForName:object:queue:usingBlock:]返回一个充当观察者的不透明对象。您必须跟踪该对象,以便稍后可以删除观察者。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NSNotificationCenter 和安全多线程 的相关文章

  • 如何使用 iPhone SDK 实现可滑动的图像堆栈(例如照片应用程序)?

    我想获取一堆图像 或者可能是一组用于下载图像的 URL 并以全屏方式显示它们 一次一个 使用 iPhone SDK 使用用户滑动来平滑地为堆栈中的下一个图像设置动画 Apple 的 Photo app 似乎可以做到这一点 此外 如果尚未检索
  • 是否有适用于 iPad 2 的条码扫描仪 SDK? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 从 UIImagePickerController 相机视图推送 viewController

    我正在开发一款消息应用程序 类似于 WhatsApp 用户可以互相发送文本和图像消息 当用户想要发送图像时 他可以从相机胶卷中选择一张图像 也可以用相机拍摄一张图像 这就是我介绍的方式UIImagePickerController对于这两种
  • iPhone 应用程序中的异步、同步、线程

    我正处于一个应用程序的设计阶段 该应用程序将利用 REST Web 服务 并且在使用异步 同步和线程方面遇到了困境 这是场景 假设您有三个选项可供深入研究 每个选项都有自己的基于 REST 的资源 我可以使用同步请求延迟加载每个请求 但这会
  • 如何在 iOS 9 上可靠地检测是否连接了外部键盘?

    在 iOS 9 之前 确定是否连接外部键盘的最可靠方法是监听UIKeyboardWillShowNotification并使文本字段成为第一响应者 如中所述这个问题 https stackoverflow com questions 289
  • 使用 gcc 在 Linux 上运行线程构建块 (Intel TBB)

    我正在尝试为线程构建块构建一些测试 不幸的是 我无法配置 tbb 库 链接器找不到库 tbb 我尝试在 bin 目录中运行脚本 但这没有帮助 我什至尝试将库文件移动到 usr local lib 但这又失败了 任何的意见都将会有帮助 确定您
  • 覆盖层不与 UITableView 一起滚动 - iOS

    我有一个 UITableView 类 它使用以下方法在转到下一个屏幕时调用加载覆盖 问题是这个加载屏幕不随列表滚动 所以如果你滚动一点并单击某些东西 加载屏幕不会显示 因为它位于顶部 如何让加载屏幕始终保持在 UITableView 的顶部
  • insertNewObjectForEntityForName:

    我使用 Xcode xcdatamodel 文件编辑器设置了一个实体 我创建了一个名为 Person 的实体 添加了一些属性 然后生成了一个 m 文件来表示它 一切都很好 现在 当我去编写一行代码时 例如 Person person Per
  • UIImageJPEGRepresentation 在视网膜显示屏上提供 2x 图像

    我有这段代码 它创建一个图像 然后向其添加一些效果并缩小其大小以使其largeThumbnail UIImage originalImage UIImage imageWithData self originalImage thumbnai
  • 在 UIScrollview 上显示缩略图的最佳方法是什么(从服务器下载)

    我想在 UIScrollview 如照片应用程序 上显示许多图像 作为缩略图 所有图像将从服务器下载 据我所知 有几种选择 1 通过创建 UIImageviews 然后将它们添加为主滚动视图上的子视图 2 通过子类化一个UIView类 然后
  • 如何在 NSTextView 中使用 SPACE 而不是 TAB

    我只知道如何修改 NSTextView 中的制表符宽度 NSMutableParagraphStyle paragraphStyle self defaultParagraphStyle mutableCopy paragraphStyle
  • 从 robovm 项目创建 iOS 静态库(JNI 中的 BAD_ACCESS)

    我有大量的Java代码 只有计算函数 没有UI 我想在iOS中将其重用为静态库 我的方法是使用robovm http www robovm com并按照robovm论坛中两篇文章中描述的非官方方式创建静态库 1 基本方式 https gro
  • 防止重入并确保某些操作获取锁的正确方法是什么?

    我正在设计一个基类 当继承该基类时 它将针对多线程环境中的上下文提供业务功能 每个实例可能都有长时间运行的初始化操作 所以我想让这些对象可重用 为此 我需要能够 为这些对象之一分配上下文以允许其完成工作 防止对象在已有上下文的情况下被分配新
  • Objective-C 中是否有相当于 C++ 动态转换的功能?

    如果我有两个类 子类和超类 SuperClass super new SuperClass SubClass sub new SubClass SubClass sub pointer The nice one line cast belo
  • Spring Batch 多线程 - 如何使每个线程读取唯一的记录?

    这个问题在很多论坛上都被问过很多次了 但我没有看到适合我的答案 我正在尝试在我的 Spring Batch 实现中实现多线程步骤 有一个包含 100k 条记录的临时表 想要在 10 个线程中处理它 每个线程的提交间隔为 300 因此在任何时
  • Final字段的线程安全

    假设我有一个 JavaBeanUser这是从另一个线程更新的 如下所示 public class A private final User user public A User user this user user public void
  • 在 Objective-C 中的 Swift 类上调用 NSStringFromClass 返回模块损坏的名称

    我知道这个问题 https stackoverflow com questions 24107658 get a user readable version of the class name in swift in objc nsstri
  • 无法将项目添加到 NSMutableArray ivar

    我的目标是将字符串添加到数组中 并在我调用的方法中执行此操作 在这个方法中 我在数组中得到一个空值 但不知道为什么 我在课程开始时有这样的内容 NSMutableArray listOfEvents 以及我在每个事件上调用的方法 void
  • Java列表的线程安全

    我有一个列表 它将在线程安全上下文或非线程安全上下文中使用 究竟会是哪一个 无法提前确定 在这种特殊情况下 每当列表进入非线程安全上下文时 我都会使用它来包装它 Collections synchronizedList 但如果不进入非线程安
  • 使用强光混合模式时突出显示伪影

    我正在 iPhone 应用程序中使用顶部图像的 HardLight 混合模式混合两个图像 它看起来像这样 UIGraphicsBeginImageContext size sourceImage drawInRect rectangle b

随机推荐

  • JQuery/Javascript 以及 && 运算符的使用

    我试图让一个简单的条件语句起作用 但遇到了问题 失败的代码 document ready function var wwidth window width if wwidth lt 321 alert I am 320 pixels wid
  • FCM/GCM 在 iOS 上按“标签”对通知进行分组

    因此 当向 Android 设备发送通知时 您可以指定标签属性 notification title title body message sound sound tag STRING TO GROUP NOTIFICATIONS BY 这
  • 如何使用 C#(.NET 3.5) 获取我的机器的处理器名称?

    我需要找到我的机器上处理器的名称和速度 我正在构建一个开源帮助台套件 发现这真的很有趣 感谢各位的帮助 正如其他人指出的 使用 WMI 通过添加对 System Management dll 的引用 然后调用以下代码来执行此操作 Manag
  • Node.js 实时游戏

    是否可以使用 Node js 创建一个需要抽搐反应的实时游戏 延迟有多高 它实际上能低到多低 可以像使用任何其他语言 框架一样在 Node js 中制作实时游戏 这里的问题是您将使用什么样的服务器和客户端 使用http服务器此类游戏的功能将
  • 'heapdump.xxx.phd'。不是 HPROF 堆转储 (java.io.IOException) 不是 HPROF 堆转储

    Eclipse Memory Analyzer 文档说它可以打开 IBM 便携式堆转储文件 phd http help eclipse org luna index jsp topic org eclipse mat ui help wel
  • SQLAlchemy 多对多孤儿删除

    我正在尝试使用 SQLAlchemy 实现基本的用户组模型 其中用户可以拥有多个组 组可以拥有多个用户 当一个组变空时 我希望删除该组 以及与该组关联的其他内容 幸运的是 SQLAlchemy 的级联可以很好地处理这些更简单的情况 问题是c
  • 使用谷歌地图 API v3 折线捕捉到道路

    在谷歌地图 API v2 中这很容易 var map new GMap2 document getElementById map map setCenter new GLatLng 53 7877 2 9832 13 map addCont
  • 使用流从现有列表创建不可变列表

    有一个列表Person对象 List
  • Ruby - LoadError enc/trans/single_byte

    我在 Ruby on Rails 应用程序中使用 ActiveRecord Store 模块时遇到了一个奇怪的问题 据我了解 该模块在底层使用 序列化 方法 因此它只是使用 ruby 内置的 psych gem 将数据序列化为 yaml 格
  • Android中如何检测触摸事件

    是否可以检测活动中的所有触摸事件并捕获它 然后将事件传递给另一个视图 例如 按钮 1 和按钮 2 当按下按钮 1 时 我想捕获该触摸 单击事件并自动将该触摸事件传递给按钮 2 基本上只需一次触摸 按下即可生成单击 并将相同的单击传递给自动第
  • 软件包“Tk”的版本冲突:有 8.5.2,需要 8.5.15

    我正在尝试编译一个程序 python2 7 但无论我做什么 我都会收到此错误 C Python27 tcl tk8 5 tk tcl version conflict for package Tk have 8 5 2 need exact
  • 如何从 @Html.EditForModel() 中排除字段,但使用 Html.DisplayForModel() 显示该字段

    我正在阅读 ASP NET MVC 及其所有有趣的用途 我刚刚发现数据模板 为了急于测试这个东西 我将一个更简单的模型转换为使用 Html DisplayForModel and Html EditForModel 它就像一个幸运符 它是
  • 以秒为单位的反应日期选择器时间选择

    我还需要从反应日期选择器中选择秒 我浏览过文档发现了这个 在此解决方案中 我可以从中选择小时 分钟 上午 下午 但没有秒选项 有什么方法可以自定义也从中选择秒 需要帮助 如下例 查找输入时间 我尝试过更改日期格式 dateFormat MM
  • 如何在 Swift 的 Xcode 6 的 Storyboard 中成功添加图像?

    我对 Xcode 非常陌生 2 天 到目前为止我发现它相当令人沮丧 我只是想通过 Storyboard 将图像添加到我的应用程序的 ViewController 但它不会出现在模拟器上 有人可以帮助我吗 如果您正在尝试 XCode 的示例项
  • 彩色输出打破了 readline 的换行

    我正在使用 Ruby 中的 readline 对一些输出进行着色 但我没有运气让换行正常工作 例如 e 01 32mThis prompt is green and bold e 00m gt 期望的结果是 This prompt is g
  • 使用 csv 和 quantmod 加载多个符号

    我正在尝试使用 csv 文件加载多个符号 而不是从雅虎下载 原始代码运行良好并且使用 load packages quantmod tickers spl TLT IWM GLD data lt new env getSymbols tic
  • MySQL - 从多个具有相同结构但不同数据的表中选择数据

    好吧 这是我的困境 我有一个数据库 其中设置了大约 5 个表 所有表都具有完全相同的数据结构 以这种方式分离数据是为了本地化目的 并划分总共约 450 万条记录 大多数时候只需要一张桌子 一切都很好 但是 有时需要来自 2 个或更多表的数据
  • Node.js NODE_PATH 环境变量

    在开发过程中我曾经WebStorm node path 环境变量 我在项目设置的启动中设置了一个变量 现在我想尝试在服务器上运行该项目 但不知道如何在那里设置这个变量 帮忙解决问题 假设它是 UNIX 或 Mac OS X 服务器 请使用e
  • 无法从 Moto 360 读取心率传感器 - Android Wear

    有人成功读取 Moto 360 的心率传感器吗 mSensorManager SensorManager getSystemService SENSOR SERVICE mHeartRateSensor mSensorManager get
  • NSNotificationCenter 和安全多线程

    鉴于即使方法调用正在进行中 对象也可能被释放 link 对象注册并接收将在与其预期释放的线程不同的线程上传递的通知是否安全 作为参考 文档指出 在多线程应用程序中 通知始终在发布通知的线程中传递 该线程可能与观察者注册自身的线程不同 同样重