我有一个我创建的数据结构,它使用Dictionary和Queue的组合来缓存项目。想法是将项目添加到"缓存"一旦达到极限,缓存中最旧的项目将被删除:
struct Cache<A: Hashable, B> {
fileprivate var theCache = [A:B]()
fileprivate var keyQueue = Queue<A>()
fileprivate var maxItems: Int!
init(maxItems: Int) {
self.maxItems = maxItems
}
subscript(key : A?) -> B? {
get {
if key != nil {
return theCache[key!]
}
return nil
}
set(newValue) {
// If value being added to cache, check that the max no. of items isn't exceeded.
// If it is then remove the first item of the cache queue and add value to queue.
if key != nil {
if (theCache.count + 1 > maxItems) {
removeFirstItem()
}
addValue(key!, value: newValue)
}
}
}
/**
Tells us how many items there are in the cache
- returns: The count of the cache
*/
var count: Int {
return theCache.count
}
mutating func clear() {
theCache.removeAll()
for _ in 0..<keyQueue.count {
_ = keyQueue.dequeue()
}
}
fileprivate mutating func addValue(_ key: A, value: B?) {
theCache[key] = value // Memory leak 2
keyQueue.enqueue(key)
}
fileprivate mutating func removeFirstItem() {
let firstItemKey = keyQueue.dequeue()
if firstItemKey != nil {
theCache.removeValue(forKey: firstItemKey!)
}
}
}
我使用此功能在UIImages
中缓存UICollectionView
,并从我的model
类中强烈引用此缓存。
在我的cellForItemAt
方法中,我有以下代码来检查缓存的图像。如果有缓存图像,则会将其添加到UICollectionCell
,否则会将其下载,将其添加到缓存中,然后将其添加到UICollectionCell
:
if let cellImage = model.imageCache[urlString] {
cell.imageView.image = cellImage
}
else {
model.downloadImage(
urlString,
completion: { [weak self] (error, image) -> () in
if let strongSelf = self {
if error == nil {
// Store the image in to our cache
strongSelf.model.imageCache[urlString] = image
// Update the cell with our image
if let cellToUpdate = collectionView.cellForItem(at: indexPath) as? MyCollectionCell {
cellToUpdate.imageView.image = image
}
}
else {
print("Error downloading image: \(error!.localizedDescription)")
}
}
}
)
}
然而,根据Xcode 8,整个过程导致UIImages的内存泄漏。任何人都可以帮我解决内存泄漏的问题以及如何防止内存泄漏吗?
修改
这是我的downloadImage
功能。我还添加了内存泄漏1&#34;和&#34;内存泄漏2&#34;作为我的代码旁边的注释,显示内存泄漏的回溯xcode告诉我:
Alamofire.request(urlString, method: .get)
.authenticate(usingCredential: credentials!)
.validate()
.downloadProgress { bytesRead, totalBytesRead, totalBytesExpectedToBeRead in
DispatchQueue.main.async {
progress?(Float(totalBytesRead)/Float(totalBytesExpectedToBeRead))
}
}
.responseData { response in
// Convert the downloaded data in to a UIImage object
var image: UIImage?
if response.result.error == nil {
image = UIImage(data: response.data!) // Memory leak 1
}
completion(response.result.error, image)
}