Tôi mới sử dụng lập trình nhanh và iOS, nhưng tôi đã có thể xây dựng giao diện khởi động chủ yếu ổn định cho ứng dụng của mình trong Xcode. CollectionView lấy một hình ảnh và văn bản từ một loạt các từ điển được tạo từ một tệp csv trên máy chủ mạng gia đình của tôi. Các tập tin cvs chứa dữ liệu theo định dạng sau (lưu ý, url đã được thay đổi để bảo vệ hình ảnh được cấp phép):swift iOS - Hình ảnh UICollectionView được trộn lẫn sau khi cuộn nhanh
tập tin csv
csv file is @ url https://myserver.com/csv.txt and contains the following
Title";"SeriesImageURL
Title1";"https://licensedimage.com/url1
Title2";"https://licensedimage.com/url2
...
Title1000";"https://licensedimage.com/url1000
Vấn đề là khi di chuyển một cách nhanh chóng thông qua các CollectionView, tế bào sẽ lấy hình ảnh không đúng. Đáng chú ý, nếu bạn làm một cuộn chậm hoặc trung bình, một hình ảnh khác sẽ hiển thị trước khi hình ảnh chính xác được đưa vào ô chính xác (văn bản nhãn cho các ô luôn chính xác, chỉ hình ảnh bị tắt). Sau khi sự không phù hợp của hình ảnh vào ô phù hợp với nhãn xảy ra, tất cả các ô khác trong CollectionView cũng sẽ hiển thị hình ảnh không chính xác.
Ví dụ: Ô 1-9 sẽ hiển thị Title1-9 với đúng Image1-9 Khi cuộn chậm, Ô 19-27 sẽ hiển thị Tiêu đề 19-27, sẽ hiển thị nhanh Hình ảnh 10-18 và sau đó hiển thị Hình 19-27 chính xác. Khi di chuyển nhanh chóng một số lượng lớn các ô (ví dụ: từ ô 1-9 đến ô 90-99), các ô 90-99 sẽ hiển thị Tiêu đề 90-99, sẽ hiển thị Hình ảnh 10-50, và sau đó sẽ không chính xác ở lại Hình 41- 50 (hoặc ở xa). Khi di chuyển xa hơn, Ô 100+ sẽ hiển thị Tiêu đề chính xác nhưng sẽ chỉ hiển thị hình ảnh từ phạm vi Hình 41-50.
Tôi nghĩ lỗi này là do việc tái sử dụng ô không được xử lý đúng cách, bộ nhớ đệm của hình ảnh không được xử lý đúng cách hoặc cả hai. Nó cũng có thể là một cái gì đó tôi không nhìn thấy như là một lập trình viên mới bắt đầu iOS/swift. Tôi đã cố gắng để thực hiện một yêu cầu với một bổ trợ hoàn thành nhưng dường như không thể làm cho nó hoạt động đúng với cách mã của tôi được thiết lập. Tôi sẽ đánh giá cao bất kỳ sự giúp đỡ nào với điều này cũng như giải thích cho lý do tại sao sửa chữa hoạt động theo cách của nó. Cảm ơn!
Mã có liên quan bên dưới.
SeriesCollectionViewController.swift
class SeriesCollectionViewController: UICollectionViewController, UISearchBarDelegate {
let reuseIdentifier:String = "SeriesCell"
// Set Data Source Models & Variables
struct seriesModel {
let title: AnyObject
let seriesimageurl: AnyObject
}
var seriesDict = [String:AnyObject]()
var seriesArray = [seriesModel]()
// Image Cache
var imageCache = NSCache()
override func viewDidLoad() {
super.viewDidLoad()
// Grab Data from Source
do {
let url = NSURL(string: "https://myserver.com/csv.txt")
let fullText = try NSString(contentsOfURL: url!, encoding: NSUTF8StringEncoding)
let readings = fullText.componentsSeparatedByString("\n") as [String]
var seriesDictCount = readings.count
seriesDictCount -= 1
for i in 1..<seriesDictCount {
let seriesData = readings[i].componentsSeparatedByString("\";\"")
seriesDict["Title"] = "\(seriesData[0])"
seriesDict["SeriesImageURL"] = "\(seriesData[1])"
seriesArray.append(seriesModel(
title: seriesDict["Title"]!,
seriesimageurl: seriesDict["SeriesImageURL"]!,
))
}
} catch let error as NSError {
print("Error: \(error)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
imageCache.removeAllObjects()
// Dispose of any resources that can be recreated.
}
//...
//...skipping over some stuff that isn't relevant
//...
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> SeriesCollectionViewCell {
let cell: SeriesCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! SeriesCollectionViewCell
if (self.searchBarActive) {
let series = seriesArrayForSearchResult[indexPath.row]
do {
// set image
if let imageURL = NSURL(string: "\(series.seriesimageurl)") {
if let image = imageCache.objectForKey(imageURL) as? UIImage {
cell.seriesImage.image = image
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
if let tvimageData = NSData(contentsOfURL: imageURL) {
let image = UIImage(data: tvimageData)
self.imageCache.setObject(image!, forKey: imageURL)
dispatch_async(dispatch_get_main_queue(), {() -> Void in
cell.seriesImage.image = nil
cell.seriesImage.image = image
})
}
})
}
}
cell.seriesLabel.text = "\(series.title)"
}
} else {
let series = seriesArray[indexPath.row]
do {
// set image
if let imageURL = NSURL(string: "\(series.seriesimageurl)") {
if let image = imageCache.objectForKey(imageURL) as? UIImage {
cell.seriesImage.image = image
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
if let tvimageData = NSData(contentsOfURL: imageURL) {
let image = UIImage(data: tvimageData)
self.imageCache.setObject(image!, forKey: imageURL)
dispatch_async(dispatch_get_main_queue(), {() -> Void in
cell.seriesImage.image = nil
cell.seriesImage.image = image
})
}
})
}
}
cell.seriesLabel.text = "\(series.title)"
}
}
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.mainScreen().scale
cell.prepareForReuse()
return cell
}
SeriesCollectionViewCell
class SeriesCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var seriesImage: UIImageView!
@IBOutlet weak var seriesLabel: UILabel!
}
Các ô được sử dụng lại và bạn đang gửi đi tìm nạp hình ảnh không đồng bộ, vì vậy khi bạn sử dụng ô và tìm nạp hình ảnh mới không đồng bộ thì tìm nạp cũ vẫn đang chạy. Bạn cần phải xử lý này. Có lẽ cách dễ nhất là sử dụng một cái gì đó SDWebImage trong đó có một phần mở rộng trên UIImageView mà sẽ xử lý này cho bạn – Paulw11
@ Paulw11: Yea, tôi đã tìm thấy nó đã làm với các yêu cầu không được hủy bỏ đúng hoặc một cái gì đó. Tôi đã hy vọng để viết mã chỉ sử dụng UIKit kể từ khi tôi đang sử dụng ứng dụng này như là một kinh nghiệm học tập và tôi cảm thấy như dựa vào một khuôn khổ bên ngoài đánh bại mục đích vì nó là một phím tắt. Tôi đã thực sự nhìn vào Alamofire/AlamofireImage và SDWebImage, mặc dù, nhưng đối với một số lý do sau khi các pod được cài đặt, tôi không thể nhập khẩu trong các mô-đun (đây là một vấn đề riêng biệt tôi đã không hoàn toàn tìm ra). Tôi sẽ sử dụng nó nếu tôi cần mặc dù, chỉ muốn thử xử lý nó với UIKit trước. – shadowofjazz
Cách tiếp cận khác là lưu trữ URL hình ảnh làm thuộc tính của ô của bạn, sau đó trong quá trình đóng hoàn thành, hãy kiểm tra giá trị thuộc tính đối với URL bạn vừa tìm nạp. Nếu nó không khớp thì không đặt hình ảnh vì ô đã được sử dụng lại. – Paulw11