11

在我当前的项目中,几个视图控制器(如vc)生成在静态 NSOperationQueue 上执行的 NSOperation 对象(如operation)。当操作等待或运行时,它将通过委托(operation.delegate = vc,分配不保留)向视图控制器报告。

但是这些操作可能需要一段时间,同时应用程序可以释放视图控制器(通过将它们从导航控制器的堆栈中弹出)。

到目前为止,一切都是故意的。包含静态 NSOperationQueue 的类有办法返回操作,因此视图控制器不会保留它们。它们只是分配/初始化/自动释放并放入队列中。

现在这也导致了问题。在视图控制器解除分配后,对 NSOperation 的精神委托的任何调用都将导致错误的访问冲突。据我了解,无法检查指针处的对象是否已被释放,如本问题所述

我能想到的一种解决方法是保留操作并将 operation.delegate 设置为 nil on dealloc。但这将是我最不受欢迎的修复,因为它会引入很多额外的 ivars/属性来跟踪。

因此,我的问题是,有没有其他方法可以解决这个问题,如果有,你能在这里画一个吗?

干杯,
EP。

解决方案:最适合我的方法是与 Guiliano 的回答略有不同:

  • 在队列管理器中实现每个委托协议是不可行的(20 多种不同的协议和 50 多种方法),所以我保留了直接委托分配。我所做的更改是进行分配调用的班级。这曾经是创建请求的类(和委托),但现在它被卸载到队列管理器。

  • 队列管理器除了将委托分配给操作之外,还拥有一个辅助可变字典来跟踪委托/操作对。

  • 每个委托实例在释放时调用一个[QueueManager invalidateDelegate:self]方法,然后查找属于该委托的请求并将其归零。然后还删除字典操作/委托对以允许正确解除分配操作。

  • 最后,通过 KVO 观察isFinished每个操作的属性,可变 dict 保持干净,以确保所有操作保留计数在完成后实际释放。

感谢 Guiliano 提供使用 KVO 破解此问题的提示!

4

3 回答 3

7

我建议检查您的体系结构并将委托移动到管理队列的类(假设 QueueManager),而不是在每个操作中都有一个委托:

  • 创建一个 QueueManagerDelegate 来实现您需要通知 viewControllers 的方法

  • 在 QueueManager 中为每个 NSOperation 的 isFinished 属性添加一个 KVO 观察者(在将操作添加到队列之前执行此操作;))

  • 在 KVO 的回调中调用委托方法,仅当委托为 != nil 时才需要

  • 向 QueueManager 添加一个 invalidate 方法,并在 UIViewController(s) 的 dealloc 方法中调用此方法

    -(void)invalidate { self->delegate = nil; }

如果您需要更新 KVO:Kvo 编程指南

于 2011-05-06T16:40:23.063 回答
0

这里最好的建议是审查应用程序的架构以避免这种情况。但是,如果当前代码无法更改,您可以使用NSNotificationCenter。每次释放视图控制器时,您都可以发布通知,此通知必须由NSOperationQueue持有者捕获,通知处理程序中的简单 foreach 循环将取消分配的视图控制器的委托。应该做的伎俩。

于 2011-05-06T16:06:06.383 回答
0

您还应该检查以确保任何代表(如果非零)也能够响应操作完成的消息。您可以使用respondsToSelector所有 NSObject 子类所拥有的函数来执行此操作。

在我的项目中,我已将此检查抽象为 NSObject 上的一个类别,让我可以安全地调用具有任意数量对象参数的委托:

- (void) dispatchSelector:(SEL)selector target:(id)target objects:(NSArray*)objects onMainThread:(BOOL)onMainThread {

if(target && [target respondsToSelector:selector]) { // Do your delegate calls here as you please } }

您可以在此处查看完整示例:https ://github.com/chaione/ChaiOneUtils/blob/master/Categories/NSObject-Dispatch.m

于 2011-05-06T16:40:01.120 回答