更新:
现在只使用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.
}
}
编辑:
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 :(得分:3)
您的内存管理问题。不是斯威夫特的。这是你出错的地方......
在viewDidLoad
方法中,您已经实例化了包含200多张图片的imageGroup
数组。假设这些图像不是非常小,那么你已经从get go中为一个不必要的数组分配了一个巨大的内存块。您应该在loadImage
方法中根据需要获取这些图片。
例如,您可以替换此行:
var newcontainerView = UIImageView(image: imageGroup[imageCounter])
带有以下内容:
let newImage = UIImage(named: "bg_\(imageCounter + 1)")
var newcontainerView = UIImageView(image: newImage)
因此您可以根据需要从捆绑中获取图像。
注意:您需要找出适合您的情况的适当的文件名获取算法... named: "bg_\(imageCounter + 1)"
只是一个例子。
至于您在整个代码中使用imageGroup.count
,因为您的viewDidLoad
显示您的图片已知数量,我建议您更换imageGroup.count
的所有实例等效常数。
编辑:
要解决代码中的另一个问题,在loadVisibleImages
中调用scrollViewDidScroll
也会导致内存问题。
当滚动视图滚动时,UIScrollView
委托方法scrollViewDidScroll
会被连续调用,因此,正如您的代码所示,loadVisibleImages
也将被调用。因此,特别是当用户快速滚动并且您的应用同时运行loadVisibleImages
的多次迭代时(方法的一次传递在下一次开始之前尚未完成),这可能会导致此特定情况下的崩溃。
所以这里有一个建议,现在就在我的脑海中(我可以很好地提出一个更好的一个,我相信更好的存在)。在您的scrollViewDidScroll
方法中,如果您的应用尚未通过,则可能只调用loadVisibleImages
。然后在滚动视图完成减速后再次将其作为安全措施,以确保您拥有可见图像。例如:
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()
}
答案 1 :(得分:1)
使用可重复使用的滚动视图第三方框架。它加载和显示图像的方式与表格视图类似。它在每个滚动条上使用可重用的视图。您可以显示小尺寸的占位符,并在焦点上重新加载图像的实际大小。非常容易使用: https://github.com/sumofighter666/ReusableScrollView