2014-11-23 3 views
-2

Обновление:Предупреждения памяти при попытке загрузить 200+ изображений

Теперь просто используйте CollectionView. Я должен был сделать это с самого начала, но я был очень знаком с iOS. CollectionViews управляет всем получением и выпуском изображений для вас. Так что проблем с памятью вообще нет. Достаточно учебников по ним в Интернете. Просто быстрая заметка. Дайте изображениям имя с номером и не добавляйте ноль перед номером. Затем вы можете получить их с помощью indexPath.

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("AnimationCell", forIndexPath: indexPath) as! AnimationCell 


     cell.imageView?.image = UIImage(named: "bg_\(indexPath.row)") 


    return cell 
} 

Я строй просмотр фотографий приложения для графического романа. Один гигантский прокрутка, содержащий более 200 изображений.

Я попытался построить некоторое управление памятью на основе кода примера, но это, похоже, не работает. Я думаю, это не работает, потому что у меня есть только управление памятью на изображениях, а не на представлениях, которые их удерживают.

Это что-то, где мне нужно использовать более «слабые» переменные и как я могу заставить их работать?

Когда я положил слабую переменную, она говорит мне, что ей нужен класс.

import UIKit 

class ViewController: UIViewController, UIScrollViewDelegate { 

    @IBOutlet var scrollView: UIScrollView! 


    var imageGroup : [UIImage?] = [] 
    var containerViews : [UIImageView?] = [] 
    var containerView :UIImageView? 
    var imgWidthMult : CGFloat = 2.121875 
    let imageGroupCount : CGFloat? 
    let containerHeight : CGFloat? 
    let containerWidth : CGFloat? 
    var imageCounter : Int = 0 



    override func viewDidLoad() { 
     super.viewDidLoad() 
     // 1 
     imageGroup = [ 
      UIImage(named: "bg_001")!, 
      UIImage(named: "bg_002")!, 
      UIImage(named: "bg_003")!, 
      UIImage(named: "bg_004")!, 
      //200+ images to follow here 
     ] 

     let imageGroupCount = CGFloat(imageGroup.count) 
     println(imageGroupCount) 


     // 3 
     for i in 0..<imageGroup.count { 
      containerViews.append(nil) 
     } 

     // 4 

     let imagesScrollViewSize = UIScreen.mainScreen().applicationFrame; 
     scrollView.contentSize = CGSizeMake(imagesScrollViewSize.height * imgWidthMult * CGFloat(imageGroup.count), imagesScrollViewSize.height) 

     // 5 
     let containerframe = UIScreen.mainScreen().applicationFrame; 
     let containerHeight : CGFloat = containerframe.height 
     let containerWidth : CGFloat = (imgWidthMult * containerHeight) 

     loadVisibleImages() 

     println("containerWidth") 
     println(containerWidth) 
     println(containerframe.size) 
     println(scrollView.contentSize) 




     return 
    } 

    // this loads images and should be adjusted and taken out of local scope 


    func loadImage (imageCounter:Int) { 
     let containerframe = UIScreen.mainScreen().applicationFrame; 
     let containerHeight : CGFloat = containerframe.height 
     let containerWidth : CGFloat = (imgWidthMult * containerHeight) 

     if imageCounter < 0 || imageCounter >= imageGroup.count { 
      // If it's outside the range of what you have to display, then do nothing 
      return 
     } 

     // 1 
     if let containerView = containerViews[imageCounter] { 
      // Do nothing. The view is already loaded. 
     } else { 
      // 2 
      var frame = UIScreen.mainScreen().applicationFrame; 
      frame.origin.x = frame.size.height * CGFloat(imageCounter) * 2.121875 
      frame.origin.y = 0.0 
      frame.size = CGSize(width: containerWidth, height: containerHeight) 

      // 3 
      var newcontainerView = UIImageView(image: imageGroup[imageCounter]) 
      newcontainerView.contentMode = .ScaleAspectFit 
      newcontainerView.frame = frame 
      scrollView.addSubview(newcontainerView) 


      containerViews[imageCounter] = newcontainerView 
     } 

    } 

    func purgeImage(imageCounter:Int) { 

     if imageCounter < 0 || imageCounter >= imageGroup.count { 
      // If it's outside the range of what you have to display, then do nothing 
      return 
     } 

     // Remove a page from the scroll view and reset the container array 
     if let containerView = containerViews[imageCounter] { 
      containerView.removeFromSuperview() 
      containerViews[imageCounter] = nil 
      println("removed page") 
     } 

    } 


    func loadVisibleImages() { 


     // First, determine which page is currently visible 
     let containerframe = UIScreen.mainScreen().applicationFrame; 
     let containerHeight : CGFloat = containerframe.height 
     let containerWidth : CGFloat = (imgWidthMult * containerHeight) 
     let pagesWidth = (containerWidth) 
     let imageCounter = Int(floor((scrollView.contentOffset.x * 2.0 + pagesWidth)/(pagesWidth * 2.0))) 


     println(Int(floor((scrollView.contentOffset.x * 2.0 + pagesWidth)/(pagesWidth * 2.0)))) 
     println(pagesWidth) 
     println(containerHeight) 


     println(imageCounter) 

     // Update the page control 

     // Work out which pages you want to load 
     let firstPage = imageCounter - 1 
     let lastPage = imageCounter + 1 


     // Purge anything before the first page 
     for var index = 0; index < firstPage; ++index { 
      purgeImage(index) 
     } 

     // Load pages in our range 
     for var index = firstPage; index <= lastPage; ++index { 
      loadImage(index) 
     } 

     // Purge anything after the last page 
     for var index = lastPage+1; index < imageGroup.count; ++index { 
      purgeImage(index) 
     } 
     println("loadVisibleImages") 
    } 





    func scrollViewDidScroll(scrollView: UIScrollView) { 
     // Load the pages that are now on screen 
     println("did scroll") 
     loadVisibleImages() 
     println("did scroll") 

    } 




    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

} 

Edit:

import UIKit 

class ViewController: UIViewController, UIScrollViewDelegate { 

    @IBOutlet var scrollView: UIScrollView! 


    var containerViews : [UIImageView?] = [] 
    var containerView : UIImageView? 
    var imgWidthMult : CGFloat = 2.121875 
    let imageGroupCount : Int = 149 
    let containerHeight : CGFloat? 
    let containerWidth : CGFloat? 
    var imageCounter : Int = 000 
    var loadingVisibleImages : Bool? 


    override func viewDidLoad() { 
     super.viewDidLoad() 
     // 1 


     loadingVisibleImages = false 

     // 3 
     for i in 0..<imageGroupCount { 
      containerViews.append(nil) 
     } 

     // 4 

     let imagesScrollViewSize = UIScreen.mainScreen().applicationFrame; 
     scrollView.contentSize = CGSizeMake(imagesScrollViewSize.height * imgWidthMult * CGFloat(imageGroupCount), imagesScrollViewSize.height) 

     // 5 

     let containerframe = UIScreen.mainScreen().applicationFrame; 
     let containerHeight : CGFloat = containerframe.height 
     let containerWidth : CGFloat = (imgWidthMult * containerHeight) 

     loadVisibleImages() 


     return 
    } 

    // this loads images and should be adjusted and taken out of local scope 


    func loadImage (imageCounter:Int) { 
     let containerframe = UIScreen.mainScreen().applicationFrame; 
     let containerHeight : CGFloat = containerframe.height 
     let containerWidth : CGFloat = (imgWidthMult * containerHeight) 

     if imageCounter < 0 || imageCounter >= imageGroupCount { 
      // If it's outside the range of what you have to display, then do nothing 
      return 
     } 

     // 1 
     if let containerView = containerViews[imageCounter] { 
      // Do nothing. The view is already loaded. 
     } else { 
      // 2 
      var frame = UIScreen.mainScreen().applicationFrame; 
      frame.origin.x = ((frame.size.height * CGFloat(imageCounter) * 2.121875) + containerframe.width) 
      frame.origin.y = 0.0 
      frame.size = CGSize(width: containerWidth, height: containerHeight) 

      // 3 
      let newImage = UIImage(named: "bg_\(imageCounter + 1)") 
      var newcontainerView = UIImageView(image: newImage) 
      newcontainerView.contentMode = .ScaleAspectFit 
      newcontainerView.frame = frame 
      scrollView.addSubview(newcontainerView) 


      containerViews[imageCounter] = newcontainerView 
     } 

    } 

    func purgeImage(imageCounter:Int) { 

     if imageCounter < 0 || imageCounter >= imageGroupCount { 
      // If it's outside the range of what you have to display, then do nothing 
      return 
     } 

     // Remove a page from the scroll view and reset the container array 
     if let containerView = containerViews[imageCounter] { 
      containerView.removeFromSuperview() 
      containerViews[imageCounter] = nil 
      println("removed page") 
     } 

    } 


    func loadVisibleImages() { 

     loadingVisibleImages = true 

     // First, determine which page is currently visible 
     let containerframe = UIScreen.mainScreen().applicationFrame; 
     let containerHeight : CGFloat = containerframe.height 
     let containerWidth : CGFloat = (imgWidthMult * containerHeight) 
     let pagesWidth = (containerWidth) 
     let imageCounter = Int(floor(((scrollView.contentOffset.x * 2.0 + pagesWidth)/(pagesWidth * 2.0))) 


     println(pagesWidth) 
     println(containerHeight) 


     println(imageCounter) 

     // Update the page control 

     // Work out which pages you want to load 
     let firstPage = imageCounter - 1 
     let lastPage = imageCounter + 1 


     // Purge anything before the first page 
     for var index = 0; index < firstPage; ++index { 
      purgeImage(index) 
     } 

     // Load pages in our range 
     for var index = firstPage; index <= lastPage; ++index { 
      loadImage(index) 
     } 

     // Purge anything after the last page 
     for var index = lastPage+1; index < imageGroupCount; ++index { 
      purgeImage(index) 
     } 

     loadingVisibleImages = false 
     println("loadVisibleImages") 
    } 





    func scrollViewDidScroll(scrollView: UIScrollView) { 
     // Load the pages that are now on screen 
     println("did scroll") 
     if loadingVisibleImages == false { 
     loadVisibleImages() 
     } 


    } 

    func scrollViewDidEndDecelerating(scrollView: UIScrollView) { 
     if loadingVisibleImages == false { 
      loadVisibleImages() 
     } 
    } 




    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

} 
+0

Что вы имеете в виду "управление памятью" не работает? Я предполагаю, что проблема заключается в том, что у вас заканчивается память, правильно? Что именно вы имеете в виду, «не работает»? – nhgrif

+1

Кажется, вы не управляете какой-либо памятью – John

+0

Но он называет 'super.didReceiveMemoryWarning()', что считается, правильно? – nhgrif

ответ

3

Ваше управление памятью проблема. Не Свифт. Вот где вы поступили не так ...

В вашем методе viewDidLoad вы создали экземпляр своего массива imageGroup с более чем 200 изображениями. Предполагая, что эти изображения не супер-крошечные, вы уже выделили огромный кусок памяти для ненужного массива из get go. Вы должны использовать эти изображения по мере необходимости во время вашего метода loadImage.

Например, вы можете заменить эту строку:

var newcontainerView = UIImageView(image: imageGroup[imageCounter]) 

с чем-то вдоль линий:

let newImage = UIImage(named: "bg_\(imageCounter + 1)") 
var newcontainerView = UIImageView(image: newImage) 

так что вы вместо того, чтобы получить изображение из комплекта по мере необходимости.

NB: Вам нужно найти подходящий алгоритм получения имен файлов в соответствии с вашим случаем ... named: "bg_\(imageCounter + 1)" - всего лишь пример.

Как для использования imageGroup.count на протяжении всего кода, так как это очевидно, в вашем viewDidLoad, что ваши изображения имеют известное количество, я бы предложил заменить все экземпляры imageGroup.count с эквивалентной постоянной.


Edit:

Для решения еще один вопрос с вашим кодом, вызывая loadVisibleImages в scrollViewDidScroll также может вызвать проблемы с памятью.

Метод UIScrollView делегат scrollViewDidScroll называется непрерывно как Scrollview свитков, и, таким образом, как и ваш код стоит, loadVisibleImages будет называться почти постоянно, а также. Поэтому, особенно когда прокрутка пользователя выполняется быстро, и ваше приложение одновременно запускает несколько итераций loadVisibleImages (когда один проход метода не завершился до начала следующего), это может привести к сбою в этом конкретном случае.

Итак, вот предложение сейчас прямо с моей головы (я бы очень хорошо подошел к лучшему позже, и я уверен, что лучшие существуют). В вашем методе scrollViewDidScroll, возможно, звоните только loadVisibleImages, если ваше приложение еще не проходит через него. Затем вызовите его снова как гарантию, как только ваш scrollview завершит замедление только для того, чтобы убедиться, что у вас есть видимые изображения. Например:

var loadingVisibleImages 

override func viewDidLoad() { 
    super.viewDidLoad() 

    loadingVisibleImages = false 
    ... 
} 

func loadVisibleImages() { 
    loadingVisibleImages = true 
    ... 
    loadingVisibleImages = fasle 
} 

func scrollViewDidScroll(scrollView: UIScrollView) { 
    // Load the pages that are now on screen 
    println("did scroll") 
    if loadingVisibleImages == false 
     loadVisibleImages() 
} 

func scrollViewDidEndDecelerating(scrollView: UIScrollView) { 
    if loadingVisibleImages == false 
     loadVisibleImages() 
} 
+0

Я думал, что это будет что-то в этом роде! –

+0

Тогда я также позвоню позже? : 'for i in 0 ..

+0

@RMenke Это создавало бы ошибки времени сборки, компилирует ошибки времени или просто ничего не делает ... – nhgrif

1

Не загружать изображения с помощью [UIImage imageNamed:] для изображения нагрузки в ImageView, это причина выпуска памяти, когда No.of изображения более,

использовать это, в Objective-C

NSString *imgpath= [[NSBundle mainBundle] pathForResource:@"imageName" ofType:@"jpg"]; 
imageView.image=[UIImage imageWithContentsOfFile: imgpath]; 

и Swift 3.0

let imgath = Bundle.main.path(forResource: "imageName", ofType: "jpg") 
imageView.image = UIImage(contentsOfFile: imgath!)