简体   繁体   中英

UIImage memory issue in Swift

I got a problem with UIImage . Each time I call the function below, the memory increases by 5 MB.

I have 200 images, I'm scared it will crash on my iPad 2 (512 MB) so I did added pagination to my app - each page contains 20 images.

And it is still crashing. How can I reduce the amount memory on each page?

func loadImage(index:Int){
    if self.imgPaths.count == 0 {
        println("Has not data")
        actInd.stopAnimating()
        return
    }
    var imgURL: NSURL = NSURL(string: self.imgPaths[index].stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()))!
    let width:CGFloat = self.view.bounds.width
    let height:CGFloat = self.view.bounds.height
    var view:UIView = UIView(frame: CGRectMake(0, 0, width, height));

    if let imgObj = self.dicData[index] {

    }
    else
    {
    println("imgURL \(imgURL)")
    let request: NSURLRequest = NSURLRequest(URL: imgURL)
    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in
        if error == nil {
            let imgItem = UIImage(data: data)!

            var te :Float = self.imgPaths.count > 0 ? Float(index  + 1) / Float(self.imgPaths.count) : 1
            self.progressView.setProgress(te, animated: true)

            if let imgObj = self.dicData[index] {

                if index < self.imgPaths.count - 1
                {
                    var nextIndex:Int = index + 1
                    self.loadImage(nextIndex)
                }
                if(index == self.imgPaths.count - 1)
                {
                    if self.currentImageIndex > 0
                    {
                        self.isAddedFirstImg = true
                    }
                    if !self.isAddedFirstImg
                    {
                        self.scrollViews[0].zoomScale = self.zoomScales[0]
                        self.view.insertSubview(self.scrollViews[0], belowSubview: self.tabBar.viewWithTag(77)!)
                        self.isAddedFirstImg = true
                    }

                    self.actInd.stopAnimating()
                    println("loaded image")
                }
            }
            else
            {
                self.dicData[index] = UIImageView(image: imgItem)

                self.dicData[index]?.frame = CGRect(origin: CGPointMake(0.0, 0.0), size:imgItem.size)

                // 2
                self.scrollViews[index].addSubview(self.dicData[index]!)
                self.scrollViews[index].contentSize = imgItem.size

                // 3
                var doubleTapRecognizer = UITapGestureRecognizer(target: self, action: "scrollViewDoubleTapped:")
                doubleTapRecognizer.numberOfTapsRequired = 2
                doubleTapRecognizer.numberOfTouchesRequired = 1
                self.scrollViews[index].addGestureRecognizer(doubleTapRecognizer)

                var singleTapRecognizer = UITapGestureRecognizer(target: self, action: "scrollViewSingleTapped:")
                singleTapRecognizer.numberOfTapsRequired = 1
                singleTapRecognizer.numberOfTouchesRequired = 1
                self.scrollViews[index].addGestureRecognizer(singleTapRecognizer)

                var swipeRight = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
                swipeRight.direction = UISwipeGestureRecognizerDirection.Right
                self.scrollViews[index].addGestureRecognizer(swipeRight)

                var swipeLeft = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:")
                swipeLeft.direction = UISwipeGestureRecognizerDirection.Left
                self.scrollViews[index].addGestureRecognizer(swipeLeft)

                // 4
                var scrollViewFrame = self.scrollViews[index].frame
                var scaleWidth = scrollViewFrame.size.width / self.scrollViews[index].contentSize.width
                var scaleHeight = scrollViewFrame.size.height / self.scrollViews[index].contentSize.height
                var minScale = min(scaleWidth, scaleHeight)
                self.zoomScales[index] = minScale
                self.scrollViews[index].minimumZoomScale = minScale

                // 5
                self.scrollViews[index].maximumZoomScale = 1.0
                self.scrollViews[index].delegate = self

                // 6
                self.centerScrollViewContents(index)

                dispatch_async(dispatch_get_main_queue(), {
                    println("downloaded image index: \(index) CH.\(self.chapterID)")
                    if(index == 0)
                    {
                        self.scrollViews[0].zoomScale = self.zoomScales[0]
                        self.view.insertSubview(self.scrollViews[0], belowSubview: self.tabBar.viewWithTag(77)!)
                        self.actInd.stopAnimating()
                    }

                    if index < self.imgPaths.count - 1 && !self.stopDownload
                    {
                        var nextIndex:Int = index + 1
                        self.loadImage(nextIndex)
                    }
                    if(index == self.imgPaths.count - 1)
                    {
                        if self.currentImageIndex > 0
                        {
                            self.isAddedFirstImg = true
                        }
                        if !self.isAddedFirstImg
                        {
                            self.scrollViews[0].zoomScale = self.zoomScales[0]
                            self.view.insertSubview(self.scrollViews[0], belowSubview: self.tabBar.viewWithTag(77)!)
                            self.isAddedFirstImg = true
                        }

                        self.actInd.stopAnimating()
                        println("loaded image")
                    }
                })
            }
        }
        else {
            println("Error: \(error.localizedDescription)")
        }
    })
    }
}

Your intuition here (not trying to load 200 high resolution images at the same time) is right.

There are two issues here:

  1. If the image dimensions greatly exceed the dimensions of the image views in which you're showing them (or more accurately, the dimensions of the image view times the device's scale ), then you should resize the image to the size appropriate for the current image view. Loading a large image into a small image view still requires a great deal of memory. So, resize the image if necessary.

  2. You should only hold in memory those images that are visible at any given time. Those that scroll out of view should be removed from memory. The images not currently visible should be cached to some persistent storage so that you can free up memory while being able to re-retrieve the image quickly without having to go back to the web service for the image.

    It would appear that you're manually adding image view objects to a scroll view. To do this properly with a scroll view involves complicated UIScrollViewDelegate logic that determines which image views are visible and removes the ones that outside the visible portion of the scroll view. It's much easier to use UITableView or UICollectionView or UIPageViewController , which give you mechanisms to manager/reuse image views as they scroll in and out of view. Deciding which of these is appropriate depends a little upon the desired UI. But hopefully this illustrates the idea: Don't try to load all images in the scroll view at the same time. And rather than manually paging yourself, consider using one of the iOS built-in controls which greatly simplifies this process.

As an aside, you might also consider using a image framework like the UIImageView category provided by SDWebImage or AFNetworking . These allow a very simple mechanism for asynchronously retrieving images from web service. You'll still want to use one of the above mechanisms for managing the image views, but either of these two frameworks will simplify your networking code (lazy loading, asynchronous image retrieval, caching of images, concurrent image retrieval which will greatly improve performances, etc.).

You need to use Haneke instead NSdata . The problem is your app download synchronously , not asynchronously .

Haneke

imageView.hnk_setImageFromURL(url)

Reference:

http://blog.revivalx.com/2015/02/23/uitableview-tutorial-in-swift-using-alamofire-haneke-and-swiftyjson/

https://github.com/Haneke/HanekeSwift

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM