我有以下功能:
func attachToComment(_ data: Data, url: URL?, type: MediaType) {
self.dismiss(animated: true, completion: nil)
let image = UIImage(data: data)!
model.attachmentData = data
model.attachmentVideoURL = url
model.attachmentType = type
toolbar.attachImage(image, withType: type)
}
这是传递给模态呈现的视图控制器的引用:
containerNavViewController.attachToComment = attachToComment
ContainerNavViewController
是一个UINavigationController
,里面有一个容器视图控制器。这将显示相机,一旦拍摄完图像,将attachToComment
功能传递给下一个视图控制器 - EditImageViewController
。在ContainerNavViewController中,我有以下代码:
var attachToComment: ((_ data: Data, _ url: URL?, _ type: MediaType) -> ())?
var model = CameraModel()
....
editImageViewController.attachToComment = self.attachToComment
editImageViewController.model = model
self.navigationController?.pushViewController(editImageViewController, animated: false)
在EditImageViewController中,我有以下代码调用闭包:
attachToComment(model.imageData, model.videoURL, model.mediaType)
然后调用原始函数并解除模态视图控制器。然而,deinit并未在这些视图中被调用,并且它们在后台非常“活跃”。我的记忆泄漏在哪里,我该如何预防呢?
答案 0 :(得分:2)
正如Dare和Sealos所暗示的那样,问题很可能是一个强大的参考周期。但是问题中提供的代码单独就不足以导致这样的循环(因为当你解雇editImageViewController
时,如果没有更强的引用,则关闭被释放并且强引用周期被打破)。
但有一些观察结果:
我无法仅使用提供的代码重现您的强引用周期。
但是如果呈现editImageViewController
的视图控制器保持对它的强引用,阻止它被释放,我可以引发强引用周期。 editImageViewController
是局部变量,还是属性?如果是属性,请将其更改为本地变量,这可能会解决问题。或许还有其他东西可以强烈引用editImageViewController
(例如重复计时器或类似的东西)。
您可以使用“调试记忆图”工具确定保留对editImageViewController
的强引用的内容(参见下面的第3点)。
如果您确实希望确保attachToComment
的{{1}}没有对呈现视图控制器的强引用,我会替换:
EditImageViewController
使用:
editImageViewController.attachToComment = attachToComment
这是确保editImageViewController.attachToComment = { [weak self] data, url, type in
self?.attachToComment(data, url: url, type: type)
}
中的attachToComment
闭包不能保持对呈现视图控制器的强引用的最简单方法。
您可能希望使用Xcode 8中的“调试内存图”工具来识别editImageViewController
的所有权。例如,我做了两个例子:
错误地将EditImageViewController
存储为呈现视图控制器的属性,而不是将其保存为局部变量(第1点);和
未在封闭中使用editImageViewController
模式(第2点)。
当我这样做时,我得到了一个类似的记忆图:
从该图表中,我不必猜测问题的根源是什么。我不仅可以看到强引用周期存在,而且具体是导致问题的原因。但是,如果我修复上述两个问题中的任何一个(或两者),这个循环就会消失。
答案 1 :(得分:1)
问题是当你分配attachToComment时,它会捕获视图控制器的自指针,并阻止释放。
有两种方法可以解决这个问题:
编辑由于Rob的更正,而不是捕获一个实例,请使用弱自指针返回一个闭包:
在attachToComment变量中使用弱自指针。像这样:
typealias ReturnType = (Data, URL?, MediaType) -> ()
func attachToComment() -> ReturnType {
return { [weak self] in
self?.dismiss(animated: true, completion: nil)
let image = UIImage(data: data)!
self?.model.attachmentData = data
self?.model.attachmentVideoURL = url
self?.model.attachmentType = type
self?.toolbar.attachImage(image, withType: type)
}
}
editImageViewController.attachToComment = containerNavController.attachToComment()
问题是,这通常是使用弱协议完成的。一个例子是:
protocol EditImageProtocol: class {
func attachToComment(_ data: Data, url: URL?, type: MediaType)
}
class ContainerNavController: EditImageProtocol {
func attachToComment(_ data: Data, url: URL?, type: MediaType) {
self.dismiss(animated: true, completion: nil)
let image = UIImage(data: data)!
model.attachmentData = data
model.attachmentVideoURL = url
model.attachmentType = type
toolbar.attachImage(image, withType: type)
}
}
class EditImageViewController {
weak var delegate: EditImageProtocol?
func someFunction() {
delegate?.attachToComment(...)
}
}