Swift 4中的UIImagePickerController内存泄漏Xcode 9 [英] UIImagePickerController Memory Leak Xcode 9 in Swift 4

查看:138
本文介绍了Swift 4中的UIImagePickerController内存泄漏Xcode 9的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,当我使用UIImagePickerController时发现内存泄漏,我以为是我的应用程序,但是在寻找解决方案时,我找到了Apple的示例,并且我还发现该示例具有相同的内存泄漏. /p>

您可以在以下URL中找到示例.

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

根据UIImagePickerController文档:

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

在第5点中,您说您必须使用委托对象关闭图像选择器,在Apple的示例中,UIImagePickerDelegate正在关闭.

问题是选择图像并使用它时,内存泄漏浪费了大约21 MB的内存.

已使用的内存,没有内存泄漏

已使用内存且有内存泄漏

内存泄漏

这是显示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.
    })
}

这是委托中用来关闭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()
        }
    })
}

我仍在寻找解决方案,任何帮助将不胜感激.

解决方案

我遇到了同样的问题.大量其他人也是如此.追溯到2008年.非常疯狂.

不幸的是,我能找到的最佳答案是使用一个令人讨厌的单例. [IE.有意保留UIImagePickerController的一个实例,以便您每次要选择图像时都可以访问它.]这是其他人的建议.

此外,我只花了一个小时就用使用单例的代码编写此答案,但我却无法避免内存泄漏[尽管我以为我有一秒钟的时间].也许我只是做错了-随时尝试.但是我不会发布功能异常的代码作为答案.

最好的答案(这就是我解决问题的方式)是使用第三方pod/库.我使用了ImagePicker,它快速,快速,免费,美观,并且没有内存泄漏! [MIT许可证]

在此处查看: https://github.com/hyperoslo/ImagePicker

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.

解决方案

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

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

这篇关于Swift 4中的UIImagePickerController内存泄漏Xcode 9的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆