I'm using CropViewController for swift and has just installed yesterday so my pod is up to date. I really like it, good job man but i think there is possible memory leak occurred.
I just create new UIViewController and present it via modally. I have UIImageView on this controller and it has tap recognizer. I use UIImagePickerController and present CropViewController object when media picking finish like;
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
let cropVC = CropViewController(croppingStyle: .circular, image: selectedImage)
cropVC.delegate = self
picker.present(cropVC, animated: false, completion: nil)
}
}
After finished cropping and dismissing this UIViewController, deinit
never called. If i'm changing imagePickerController
delegate method like this;
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
self.imageView.image = selectedImage
}
}
then if i'm dismiss, deinit
calls. I don't set any speciald items, only UIViewController, UIImageView and UIImagePickerController here. Do i set up anything wrong or is this a memory leak?
When i call deinit
in your CropViewController.swift
class, neither it's not called.
Hi @kcankaynak!
Uh-oh. You're right. That certainly smells like a memory leak. I'll have to try it out in the sample app when I get a chance. Thanks for letting me know!
I have the same issue, there is a retain cycle causing my UIViewController (the one that presents your crop VC) to not be released, it doesnt call the deinit method as @kcankaynak mentioned. I thought it was your croppingVC delegate not being WEAK, because you had your delegate property as
public var delegate: CropViewControllerDelegate? {
didSet { self.setUpDelegateHandlers() }
}
so I thought.. maybe
public weak var delegate: CropViewControllerDelegate? {
didSet { self.setUpDelegateHandlers() }
}
will fix it... but it didnt :(
okay.. I fixed it with the following
1- I made the delegate weak, because delegates should always be weak
2- I made the self calls inside the handlers to be [weak self]
In your CropViewController.swift see the onDid... callbacks.
fileprivate func setUpDelegateHandlers() {
guard let delegate = self.delegate else {
onDidCropToRect = nil
onDidCropImageToRect = nil
onDidCropToCircleImage = nil
onDidFinishCancelled = nil
return
}
if delegate.responds(to: #selector(CropViewControllerDelegate.cropViewController(_:didCropImageToRect:angle:))) {
self.onDidCropImageToRect = {[weak self] rect, angle in
delegate.cropViewController!((self)!, didCropImageToRect: rect, angle: angle)
}
}
if delegate.responds(to: #selector(CropViewControllerDelegate.cropViewController(_:didCropToImage:withRect:angle:))) {
self.onDidCropToRect = {[weak self] image, rect, angle in
delegate.cropViewController!((self)!, didCropToImage: image, withRect: rect, angle: angle)
}
}
if delegate.responds(to: #selector(CropViewControllerDelegate.cropViewController(_:didCropToCircularImage:withRect:angle:))) {
self.onDidCropToCircleImage = {[weak self] image, rect, angle in
delegate.cropViewController!((self)!, didCropToCircularImage: image, withRect: rect, angle: angle)
}
}
if delegate.responds(to: #selector(CropViewControllerDelegate.cropViewController(_:didFinishCancelled:))) {
self.onDidFinishCancelled = { [weak self] finished in
delegate.cropViewController!((self)!, didFinishCancelled: finished)
}
}
}
This was merged in another PR. Thanks for that!
Most helpful comment
okay.. I fixed it with the following
1- I made the delegate weak, because delegates should always be weak
2- I made the self calls inside the handlers to be [weak self]
In your CropViewController.swift see the onDid... callbacks.