UIImagePickerController Memory Leak Xcode 9 in Swift 4

放肆的年华 提交于 2019-12-04 04:21:05

问题


In my application I found a memory leak when I used the UIImagePickerController, I thought it was my application, but searching for a solution I found an Apple's sample and I also found that this sample has the same memory leak.

You can find the example in the following URL.

https://developer.apple.com/library/content/samplecode/PhotoPicker/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010196

According to the UIImagePickerController documentation:

https://developer.apple.com/documentation/uikit/uiimagepickercontroller

In point 5, thy said that you have to dismiss the image picker using your delegate object, in the Apple's sample the UIImagePickerDelegate is doing the dismiss.

The issue is that the memory leak is wasting approximately 21 MB of memory when you select an image and work with it.

Used Memory without Memory Leak

Used Memory with Memory Leak

Memory Leak

This is the code to present the UIImagePickerController:

@IBAction func showImagePickerForPhotoPicker(_ sender: UIBarButtonItem) {
    showImagePicker(sourceType: UIImagePickerControllerSourceType.photoLibrary, button: sender)
}

fileprivate func showImagePicker(sourceType: UIImagePickerControllerSourceType, button: UIBarButtonItem) {
    // If the image contains multiple frames, stop animating.
    if (imageView?.isAnimating)! {
        imageView?.stopAnimating()
    }
    if capturedImages.count > 0 {
        capturedImages.removeAll()
    }

    imagePickerController.sourceType = sourceType
    imagePickerController.modalPresentationStyle =
        (sourceType == UIImagePickerControllerSourceType.camera) ?
            UIModalPresentationStyle.fullScreen : UIModalPresentationStyle.popover

    let presentationController = imagePickerController.popoverPresentationController
    presentationController?.barButtonItem = button   // Display popover from the UIBarButtonItem as an anchor.
    presentationController?.permittedArrowDirections = UIPopoverArrowDirection.any

    if sourceType == UIImagePickerControllerSourceType.camera {
        // The user wants to use the camera interface. Set up our custom overlay view for the camera.
        imagePickerController.showsCameraControls = false

        // Apply our overlay view containing the toolar to take pictures in various ways.
        overlayView?.frame = (imagePickerController.cameraOverlayView?.frame)!
        imagePickerController.cameraOverlayView = overlayView
    }

    present(imagePickerController, animated: true, completion: {
        // Done presenting.
    })
}

And this is the code in the delegate to dismiss the UIImagePickerController:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    let image = info[UIImagePickerControllerOriginalImage]
    capturedImages.append(image as! UIImage)

    if !cameraTimer.isValid {
        // Timer is done firing so Finish up until the user stops the timer from taking photos.
        finishAndUpdate()
    } else {
        dismiss(animated: true, completion: nil)
    }
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    dismiss(animated: true, completion: {
        // Done cancel dismiss of image picker.
    })
}

fileprivate func finishAndUpdate() {
    dismiss(animated: true, completion: { [weak self] in
        guard let `self` = self else {
            return
        }

        if `self`.capturedImages.count > 0 {
            if self.capturedImages.count == 1 {
                // Camera took a single picture.
                `self`.imageView?.image = `self`.capturedImages[0]
            } else {
                // Camera took multiple pictures; use the list of images for animation.
                `self`.imageView?.animationImages = `self`.capturedImages
                `self`.imageView?.animationDuration = 5    // Show each captured photo for 5 seconds.
                `self`.imageView?.animationRepeatCount = 0   // Animate forever (show all photos).
                `self`.imageView?.startAnimating()
            }

            // To be ready to start again, clear the captured images array.
            `self`.capturedImages.removeAll()
        }
    })
}

I'm still looking for a solution, any help will be appreciated.


回答1:


I had the same issue. So did a ton of other people. Dating back to 2008. Pretty crazy.

  • http://iphonedevsdk.com/forum/iphone-sdk-development/3816-uiimagepickercontroller-memory-issues.html
  • UIImagePickerController leaking memory after launch and during taking a picture. Makes app crash after taking more than a 100 pictures
  • UIImagePickerController Memory Leak

Unfortunately, the best answer I could find was to use a singleton, which sucks. [i.e. Intentionally retain an instance of UIImagePickerController so you just access that every single time you want to select an image.] This is what others have suggested.

Further, I just spent an hour writing this answer with code that uses a singleton, and I just could not avoid a memory leak [although I thought I had for a second]. Maybe I'm just doing it incorrectly - feel free to try. But I won't post my dysfunctional code as an answer.

The best answer [which is how I solved my problem] is to use a third party pod/library. I used ImagePicker, and it is quick, fast, FREE, beautiful, and NO memory leaks! [MIT License]

Check it out here: https://github.com/hyperoslo/ImagePicker



来源:https://stackoverflow.com/questions/48734044/uiimagepickercontroller-memory-leak-xcode-9-in-swift-4

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!