我有以下代码,它在 UITableView 中显示了测验列表。
问题是为了显示图像,我调用了我的方法 prepareImages
并且我得到了一个索引在 tableView
函数中填充单元格时出现超出范围异常,因为 quizzesImages
数组似乎为空 (print(self.quizzesImages.count)
显示 0
),我知道这与我如何让线程工作有关,但我看不出哪里出错了。
import UIKit
// Estructura del JSON que devuelve la URL
struct ResponseObject : Codable {
let quizzes : [Quiz]?
let pageno : Int?
let nextUrl : String?
}
class QuizzesTableViewController: UITableViewController {
// Aquí se guardan los quizzes cargados de la URL
var totalQuizzes = [Quiz]()
var quizzesImages = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.rowHeight = 90.0
navigationController?.navigationBar.prefersLargeTitles = true
downloadQuizzes()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func prepareImages(){
for i in 0...self.totalQuizzes.count-1{
let imageUrlString = self.totalQuizzes[i].attachment?.url
let imageUrl:URL = URL(string: imageUrlString!)!
print(imageUrl)
// Start background thread so that image loading does not make app unresponsive
DispatchQueue.global(qos: .userInitiated).async {
let imageData:NSData = NSData(contentsOf: imageUrl)!
// When from background thread, UI needs to be updated on main_queue
DispatchQueue.main.async {
let image = UIImage(data: imageData as Data)
print("hola")
self.quizzesImages.append(image!)
}
}
}
}
func downloadQuizzes(){
let QUIZZES_URL = "https://quiz2019.herokuapp.com/api/quizzes?token=945d3bf7d4c709d69940"
if let url = URL(string: QUIZZES_URL){
let queue = DispatchQueue(label: "download quizzes queue")
queue.async {
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
defer{
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
let data = try? Data(contentsOf: url, options: .alwaysMapped)
let decoder = JSONDecoder()
do{
let response = try decoder.decode(ResponseObject.self, from: data!)
DispatchQueue.main.async {
if (response.quizzes!.count != 0){
self.totalQuizzes.append(contentsOf: response.quizzes!)
self.prepareImages()
print(self.totalQuizzes.count)
print(self.quizzesImages.count)
self.tableView.reloadData()
}
}
}
catch {
print(error)
}
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return totalQuizzes.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Quiz", for: indexPath) as! QuizTableViewCell
let quiz = totalQuizzes[indexPath.row]
let images = quizzesImages[indexPath.row]
cell.authorLabel?.text = quiz.author?.username
cell.quizLabel?.text = quiz.question
cell.quizImage?.image = images
return cell
}}
在此先感谢您的帮助!
最佳答案
See this screen shot form my playground
我尝试在 playground 中运行您的代码并设法让它工作并进行一些更改,请参阅以下内容。
Note
为了让它在 Playground 上运行,我必须做出一些假设,只需用我的核心逻辑替换您的核心逻辑即可。
编码愉快😀
import UIKit
// Estructura del JSON que devuelve la URL
struct ResponseObject: Codable {
let quizzes: [Quiz]?
let pageno: Int?
let nextURL: String?
enum CodingKeys: String, CodingKey {
case quizzes, pageno
case nextURL = "nextUrl"
}
}
struct Quiz: Codable {
let id: Int?
let question: String?
let author: Author?
let attachment: Attachment?
let favourite: Bool?
let tips: [String]?
}
struct Attachment: Codable {
let filename: String?
let mime: MIME?
let url: String?
}
enum MIME: String, Codable {
case imageJPEG = "image/jpeg"
}
struct Author: Codable {
let id: Int?
let isAdmin: Bool?
let username: String?
}
class QuizzesTableViewController: UITableViewController {
// Aquí se guardan los quizzes cargados de la URL
var totalQuizzes = [Quiz]()
var quizzesImages = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.rowHeight = 90.0
navigationController?.navigationBar.prefersLargeTitles = true
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Quiz")
self.tableView.dataSource = self
self.tableView.delegate = self
downloadQuizzes()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func prepareImages(){
print("in prepare images")
// Start background thread so that image loading does not make app unresponsive
DispatchQueue.global(qos: .userInitiated).async {
for i in 0...self.totalQuizzes.count-1 {
let imageUrlString = self.totalQuizzes[i].attachment?.url
let imageUrl:URL = URL(string: imageUrlString!)!
print(imageUrl)
let imageData:NSData = NSData(contentsOf: imageUrl)!
let image = UIImage(data: imageData as Data)
print("hola \(i)")
self.quizzesImages.append(image!)
print(self.quizzesImages.count)
// When from background thread, UI needs to be updated on main_queue
}
DispatchQueue.main.async {
print(self.quizzesImages.count)
self.tableView.reloadData()
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
}
func downloadQuizzes(){
let QUIZZES_URL = "https://quiz2019.herokuapp.com/api/quizzes?token=945d3bf7d4c709d69940"
if let url = URL(string: QUIZZES_URL){
let queue = DispatchQueue(label: "download quizzes queue")
queue.async {
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
let data = try? Data(contentsOf: url, options: .alwaysMapped)
let decoder = JSONDecoder()
do{
let response = try decoder.decode(ResponseObject.self, from: data!)
DispatchQueue.main.async {
if (response.quizzes!.count != 0){
self.totalQuizzes.append(contentsOf: response.quizzes!)
self.prepareImages()
print(self.totalQuizzes.count)
}
}
}
catch {
print(error)
}
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
print("num of rows \(totalQuizzes.count)")
return totalQuizzes.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("in cellForRowAt \(indexPath.row)")
let cell = tableView.dequeueReusableCell(withIdentifier: "Quiz")!
let quiz = totalQuizzes[indexPath.row]
let images = quizzesImages[indexPath.row]
cell.textLabel?.text = "\(quiz.author?.username) \(quiz.question)"
cell.imageView?.image = images
return cell
}}
关于ios - 使用 DispatchQueue 索引超出范围异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53450085/