NSProxy 和键值观察

2024-01-04

NSProxy对于那些尚不存在的对象来说,它似乎可以很好地作为替代对象。例如。

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.target];
}

上面的代码将透明地将任何方法调用传递到代理代表的目标。然而,它似乎不处理目标上的 KVO 观察和通知。我尝试使用NSProxy子类代表要传递给的对象NSTableView,但我收到以下错误。

Cannot update for observer <NSAutounbinderObservance 0x105889dd0> for
 the key path "objectValue.status" from <NSTableCellView 0x105886a80>,
 most likely because the value for the key "objectValue" has changed
 without an appropriate KVO notification being sent. Check the 
KVO-compliance of the NSTableCellView class.

有没有办法让透明NSProxy符合 KVO 标准吗?


问题的关键在于键值观察的核心在于NSObject, and NSProxy不继承自NSObject。我有理由相信任何方法都需要NSProxy对象保留自己的观察列表(即外部人员希望观察它的内容)。仅此一项就会给您的 NSProxy 实现增加相当大的重量。

观察目标

看起来您已经尝试过让代理的观察者实际观察真实的对象 - 换句话说,如果目标始终被填充,并且您只是将所有调用转发到目标,那么您也将转发addObserver:... and removeObserver:...来电。问题在于你一开始就说:

NSProxy 似乎作为替代对象工作得很好 还不存在

为了完整起见,我将描述这种方法的一些核心内容以及为什么它不起作用(至少对于一般情况):

为了使其发挥作用,您的NSProxy子类必须收集在设置目标之前调用的注册方法的调用,然后在设置目标时将它们传递给目标。当您考虑还必须处理删除时,这很快就会变得棘手;您不想添加随后被删除的观察(因为观察对象可能已被释放)。您可能也不希望跟踪观察的方法保留任何观察者,以免造成意外的保留周期。我看到需要处理以下可能的目标值转变

  1. 目标是nil在初始化时,变为非nil later
  2. 目标设定为非nil,变成nil later
  3. 目标设定为非nil,然后更改为另一个非nil value
  4. 目标是nil(不在 init 上),变成非nil later

...在情况 #1 中我们立即遇到了问题。如果 KVO 观察者只观察到的话,我们可能就没事了objectValue(因为它永远是你的代理),但是假设观察者观察到了一个通过你的代理/真实对象的 keyPath,比如说objectValue.status。这意味着 KVO 机器将调用valueForKey: objectValue在观察的目标上并取回你的代理,然后它会调用valueForKey: status在你的代理上并且将会得到nil后退。当目标变为非nil,KVO 将认为该值已从其下方更改(即不符合 KVO 要求),并且您将收到引用的错误消息。如果你有办法暂时迫使目标返回nil for status,你可以打开该行为,调用-[target willChangeValueForKey: status],关闭该行为,然后调用-[target didChangeValueForKey: status]。无论如何,我们可以在案例 #1 处停止,因为它们有相同的陷阱:

  1. nil如果你打电话,不会做任何事willChangeValueForKey:其上(即 KVO 机器永远不会知道在转换到或从nil)
  2. 迫使任何目标物体具有一种暂时躺下并返回的机制nil来自 valueForKey: 对于所有键来说,当所声明的愿望是“透明代理”时,这似乎是一个相当繁重的要求。
  3. 在带有 a 的代理上调用 setValue:forKey: 是什么意思?nil目标?我们是否保留这些价值观?等待真正的目标?我们扔吗?巨大的开放问题。

对此方法的一种可能的修改是当真实目标是时使用替代目标nil,也许是一个空的NSMutableDictionary,并将 KVC/KVO 调用转发给代理。这将解决无法有意义地调用的问题willChangeValueForKey: on nil。话虽如此,假设您保留了观察列表,我并不乐观地认为 KVO 会容忍以下在情况#1 中设置目标所涉及的序列:

  1. 外部观察员电话-[proxy addObserver:...],代理转发到字典代理
  2. 代理调用-[surrogate willChangeValueForKey:] 因为目标正在设定
  3. 代理调用-[surrogate removeObserver:...] 关于代理
  4. 代理调用-[newTarget addObserver:...]朝着新的目标
  5. 代理调用-[newTarget didChangeValueForKey:] 平衡调用#2

我不清楚这是否也会导致同样的错误。整个方法真的会变得一团糟,不是吗?

我确实有几个替代想法,但#1 相当微不足道,而#2 和#3 不够简单,也不够鼓舞人心,不足以让我想花时间来编写它们。但是,对于后代来说,怎么样:

1. Use NSObjectController为您的代理

当然,它会用一个额外的密钥来连接你的 keyPaths 来通过控制器,但这有点像NSObjectController's存在的全部理由,对吗?它可以有nil内容,并将处理所有观察设置和拆除。它没有实现透明的调用转发代理的目标,但例如,如果目标是为某些异步生成的对象提供一个替代对象,那么让异步生成操作传递最终的对象可能会相当简单向控制器发出对象。这可能是最省力的方法,但并没有真正满足“透明”的要求。

2. 使用NSObject您的代理的子类

NSProxy's主要特征不是它has它有一些魔力——主要特点是它没有(一切NSObject其中的实施。如果你愿意付出努力去推翻一切NSObject你的行为don't想要的,并将它们分流回您的转发机制,您最终可以获得与NSProxy但保留了 KVO 支持机制。从那里开始,您的代理监视目标上观察到的所有相同关键路径,然后重新广播willChange... and didChange...来自目标的通知,以便外部观察者将其视为来自您的代理。

...现在是一些非常疯狂的事情:

3. (Ab)使用运行时来带NSObjectKVC/KVO 行为融入您的NSProxy子类

您可以使用运行时来获取与KVC和KVO相关的方法实现NSObject (i.e. class_getMethodImplementation([NSObject class], @selector(addObserver:...))),然后您可以添加这些方法(即class_addMethod([MyProxy class], @selector(addObserver:...), imp, types)) 到你的代理子类。

这可能会导致猜测和检查过程,找出所有私有/内部方法NSObject公共 KVO 方法调用,然后将它们添加到您批发的方法列表中。假设维护 KVO 遵守的内部数据结构不会在 ivars 中维护,这似乎是合乎逻辑的NSObject (NSObject.h表示没有 ivars——现在这并不意味着什么),因为这意味着每个NSObject实例将支付空间价格。另外,我在 KVO 通知的堆栈跟踪中看到了很多 C 函数。我认为您可能已经为 NSProxy 引入了足够的功能,成为 KVO 的一流参与者。从那时起,这个解决方案看起来就像NSObject基于解决方案;您观察目标并重新广播通知,就好像它们来自您一样,此外还围绕目标的任何更改伪造 willChange/didChange 通知。你might甚至可以在您的调用转发机制中自动执行其中的一些操作,方法是在您输入任何 KVO 公共 API 调用时设置一个标志,然后尝试调用您调用的所有方法,直到您在公共 API 调用返回时清除该标志为止- 那里的问题是试图保证引入这些方法不会破坏代理的透明度。

我怀疑这会失败的地方在于 KVO 在运行时创建类的动态子类的机制。该机制的细节是不透明的,并且可能会导致另一长串找出私有/内部方法以从NSObject。最后,这种方法也是完全脆弱的,以免任何内部实现细节发生变化。

...综上所述

抽象地说,问题归结为这样一个事实:KVO 期望在其密钥空间上有一个连贯的、可知的、持续更新的(通过通知)状态。 (如果您想支持,请将“可变”添加到该列表中-setValue:forKey:或可编辑的绑定。)除非有肮脏的伎俩,成为一流的参与者意味着NSObjects。如果链中的这些步骤之一通过调用其他内部状态来实现其功能,这是它的特权,但它将负责履行 KVO 合规性的所有义务。

出于这个原因,我认为如果这些解决方案中的任何一个值得付出努力,我会把钱花在“使用NSObject作为代理而不是NSProxy” 因此,为了了解您问题的确切性质,may成为一种方式NSProxy符合 KVO 的子类,但似乎不值得。

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

NSProxy 和键值观察 的相关文章

  • UITextField 文本更改事件

    如何检测文本字段中的任何文本更改 委托方法shouldChangeCharactersInRange适用于某些东西 但它并不能完全满足我的需求 因为在它返回 YES 之前 textField 文本不可用于其他观察者方法 例如在我的代码中ca
  • iOS:调用 Objective-C 方法的处理开销是多少?

    我正在编写一些实时音频处理代码 该代码将在音频单元的渲染回调中执行 该线程处于系统识别的最高优先级 Apple 指示最大限度地减少此调用中进行的处理量 他们的建议之一是避免 Objective C 方法调用 But why 调用 Objec
  • 如何在iPhone应用程序中的类结构中实现主键和外键表数据[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 如何连接sqlite数据库中的两个表数据 if sqlite3 open dbPath UTF8String database SQL
  • UISegmentedControl 中的自定义字体禁用调整FontSizeToFitWidth

    我已经为我的 UISegmentedControl 设置了自定义字体 但它似乎禁用了默认字体自动调整字体大小以适合宽度范围 Before After 这是我用来设置自定义字体的代码 UISegmentedControl segmentedC
  • 最近打开的应用程序[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 有什么方法可以获取最近打开的应用程序 例如 4 个 的列表吗 如果是这样 怎么办 可可麦克 看看LaunchServices LSSh
  • UITableview 中的水平和垂直滚动[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 I want to make a lineup for a festival You can see what I want to a
  • 是否有针对不同屏幕尺寸的单独故事板?

    基本上我已经完成了一个应用程序 我唯一的问题是 ATM 机应用程序在设计时只考虑了 4 英寸显示屏 当在 3 5 英寸模拟器上运行时 应用程序会丢失 0 5 英寸 显然 那么我的问题是 如何在 Xcode 5 中为不同的屏幕尺寸设置不同的故
  • iPhone 应用程序中的异步、同步、线程

    我正处于一个应用程序的设计阶段 该应用程序将利用 REST Web 服务 并且在使用异步 同步和线程方面遇到了困境 这是场景 假设您有三个选项可供深入研究 每个选项都有自己的基于 REST 的资源 我可以使用同步请求延迟加载每个请求 但这会
  • 在横向中自动调整 UITableCells 内容的大小

    在 UITableView 中 我通过 UILabels 将内容添加到单元格中 定义最佳尺寸 与单元格宽度允许的一样大 我注意到只有tableView contentSize width是可靠的 因为cell contentView bou
  • 如何知道我的应用程序使用了多少 iCloud 空间?

    有没有办法查看我的应用程序正在备份到 iCloud 的内容以及它消耗了多少内存 Settings gt iCloud gt Storage Backup gt Manage Storage将显示正在备份的总计内容 iOS 会备份位于应用程序
  • 如何在 iOS 9 上可靠地检测是否连接了外部键盘?

    在 iOS 9 之前 确定是否连接外部键盘的最可靠方法是监听UIKeyboardWillShowNotification并使文本字段成为第一响应者 如中所述这个问题 https stackoverflow com questions 289
  • 在 Objective C 的类方法中引用类本身

    我希望我没有跳过 ObjC 手册中的这一部分 但是是否可以从类的一个类方法中引用该类 就像在 PHP 中一样 您将使用 this 来引用当前实例 而 self 引用实例的类 this 的 ObjC 等价物将是 self 那么 PHP 的 s
  • insertNewObjectForEntityForName:

    我使用 Xcode xcdatamodel 文件编辑器设置了一个实体 我创建了一个名为 Person 的实体 添加了一些属性 然后生成了一个 m 文件来表示它 一切都很好 现在 当我去编写一行代码时 例如 Person person Per
  • 水平 UICollectionView 单行布局

    我正在尝试使用以下命令设置简单的水平布局UICollectionView 兜圈子却没有达到预期的结果 所以任何指针或例子将不胜感激 我粘贴经常更改的代码但没有成功可能没什么意义 该图像显示两行 第一行是单个项目 尺寸正确并且在中心正确对齐
  • Objective-C 中是否有相当于 C++ 动态转换的功能?

    如果我有两个类 子类和超类 SuperClass super new SuperClass SubClass sub new SubClass SubClass sub pointer The nice one line cast belo
  • iOS 7 tabBar 横线,如何去掉?

    Apple 在 iOS 7 中的 tabBar 上添加了一条细线 该线应该在 tabBar 和 UI 之间起到阴影或淡入淡出的作用 由于我使用的是定制的 tabBar 这条线非常令人恼火 你如何删除它 请告诉我这是可能的 否则我需要重新设计
  • 未知异常和崩溃

    当我尝试快速滚动表格视图或从远程重新加载数据时 我的应用程序崩溃了 当我先进行远程获取然后滚动表格视图时 一切似乎都工作正常 我不知道下面的崩溃日志意味着什么 它只是有时工作正常 有时崩溃 Incident Identifier 710A1
  • 在 Objective-C 中的 Swift 类上调用 NSStringFromClass 返回模块损坏的名称

    我知道这个问题 https stackoverflow com questions 24107658 get a user readable version of the class name in swift in objc nsstri
  • 从 NSImage 获取像素和颜色

    我创建了一个 NSImage 对象 理想情况下想确定它包含多少个像素颜色 这可能吗 此代码呈现NSImage into a CGBitmapContext void updateImageData if image return Dimen
  • 核心数据 iCloud 同步中的关系完整性和验证

    考虑以下简单的实体模型 实体 A 与实体 B 具有一对一关系 称为b 实体 B 具有逆对一关系 称为a 这两种关系都不是可选的 A B b lt gt a 假设我们有两个设备 1 和 2 开始完全同步 每个对象都有一个 A 类对象和一个 B

随机推荐

  • Pattern.matches() 针对 char 数组,无需在 java 中转换为 String

    Scenario 我需要根据字符数组检查正则表达式模式 char 出于安全考虑 我不允许将字符数组转换为字符串 Java 的 Pattern matches 方法旨在获取模式和字符串 另外 正则表达式模式是从另一个来源传递给我的 并且会发生
  • AWS ELB 中的双栈前缀是什么意思?

    当我在 AWS Route 53 中添加 ELB 作为别名目标时 它会自动添加dualstack我的 ELB DNS 的前缀 这代表什么 当我尝试时dig 两者都返回相同的端点 注意 这是一个内部负载平衡器 The dualstackDNS
  • 可以让 WinDBG 在符号存储中找到 mscordacwks.dll 吗?

    问题 有很多手动方法可以让 WinDBG 在没有符号存储的情况下找到 mscordacwks dll 将文件放在某个路径中 将其放在与 Windbg exe 相同的文件夹中 将其放在我的 Framework v 文件夹中 在使用WinDBG
  • 图书馆的数据库架构

    我正在为我的大学的一个部门设计一个图书馆管理系统 我想吸引您关注我提出的架构 这篇文章主要涉及我们如何存储每本书的多个副本 我设计的一些东西让我感到不舒服 我希望你们都能指出更好的方法来解决问题 为了处理用户借书的情况 我设计了三个表 bo
  • 带有客户端 haml 的 angularjs

    我刚刚开始在 Rails 应用程序中使用 AngularJS 并且由于我习惯在 Rails 中使用 haml 模板 所以我想在客户端对 AngularJS 执行相同的操作 问题是我不知道在 haml 文件中读取哪里 我有一个供投资者使用的模
  • CoreMotion 姿态参考系

    有什么区别startDeviceMotionUpdatesUsingReferenceFrameCM态度参考框架 X任意Z垂直 X任意校正Z垂直 X磁北Z垂直 X真北Z垂直 Here is 苹果文档 https developer appl
  • C#从MYSQL读取Mediumblob数据类型

    我在 MYSQL Server 中有一个数据库 有一个表存储图像及其信息 该图像的数据类型是 Mediumblob 我需要读取它并存储在 byte 中 但我不知道该怎么做 有人对这种情况有解决方案吗 非常感谢 Regards 查看来自的示例
  • 在 JPanel 内绘制 JComponent

    我正在尝试在 JPanel 内显示 JComponent 我使用空布局 因为组件的位置可以在运行时更改 并且我必须控制它们 但下面的代码不起作用 如果我显式调用 paintComponent 方法 JComponent 仅在显示时变得可见
  • 如何快速从列表中删除项目

    我正在寻找一种快速从 C 中删除项目的方法List
  • 如何在本地查看git中项目的Github网络视图?

    我觉得有点荒谬 我必须将分支推送到 Github 才能查看我可以使用的内容 有没有办法在 git 本地获得用户友好的视图 The git log branches remotes tags graph oneline decorate并不真
  • Tibco EMS 协议

    我正在尝试使用 Node js 与 Tibco EMS 服务器进行交互 并且很好奇是否可以仅在 Node js 中使用完全开源的解决方案 我不想使用 Tibco 的 Web Messaging 解决方案 那么这让我们想到 Tibco EMS
  • 为什么 C# 中的类没有循环布局问题?

    public struct Unit Unit u Causes Unit 类型的结构成员 Unit u 导致结构中发生循环 布局 But public class Unit Unit u 编译 我明白我想的问题 引用a时会形成死循环Uni
  • 完整功能中如何获取jQuery ajax数据?

    我知道这是众所周知的主题 解决方案之一是将调用更改为同步 我仍然不清楚是否有其他方法可以异步执行并获取完整函数中的数据 示例函数在 success 函数中创建一个新的资产对象 我想在完整函数中获取对它的引用 function getPres
  • javax.el.PropretyNotWritableException:类 Article 没有可写属性“id”

    我有一篇文章 DTO Article java 代码摘录 public class Article private int id public Article this id 0 public Integer getId return id
  • Keycloak 授权:CRUD 授权策略、通过 API 的权限

    在 Keycloak 中 我看到有一个 CRUD API 来创建资源 和范围 http 主机 端口 auth realms realm name authz protection resource set http 24 7Bhost 7D
  • 如何使用 DBI 从数据库中获取单个计数值?

    对于获取单个计数值 以下代码似乎太多了 是否有更好的推荐方法来使用普通 DBI 获取单个 COUNT 值 sub get count my sth dbh gt prepare SELECT COUNT FROM table WHERE s
  • 具有 HTML5 验证功能的 JQuery 对话框表单

    我正在创建一个 HTML5 示例应用程序 但我坚持做一些简单的事情 这是我想做的 我有一个链接 可以打开 JQuery 模式对话框 在该对话框中 有一个表单 有 2 个字段 当我单击 Envoyer 按钮 这是一个 JQuery 按钮 而不
  • 通过Rest WebService上传图像文件

    我写了下面的代码来做到这一点 POST Path UploadProfileImage Consumes MediaType MULTIPART FORM DATA Produces MediaType APPLICATION JSON p
  • Xamarin.IOS.dll 使用广告标识符 (IDFA)

    我们想提交我们的Xamarin申请复核Apple Appstore在提交过程中会提出以下问题 此应用程序是否使用广告标识符 IDFA 这 广告标识符 IDFA 是每个 iOS 设备的唯一 ID 是提供有针对性的广告的唯一方法 用户可以选择限
  • NSProxy 和键值观察

    NSProxy对于那些尚不存在的对象来说 它似乎可以很好地作为替代对象 例如 NSMethodSignature methodSignatureForSelector SEL sel return self target methodSig