我正在尝试让这个表格视图算法适用于这个学校的艺术应用程序项目。我的大部分代码都在工作。但是,由于某种原因,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
和 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
无法正常工作。
我 90% 确定检索和存储数据库的代码是正确的。但是,在表格视图单元格中,艺术名称:、艺术家:、日期:、位置:单元格中的图像和 numberOfRowsInSection 不会像预期的那样更新。每次我测试应用程序时,单元格都不会更新。
我已经尝试了多种方法,例如添加新变量、将“Art Date”Int 数组转换为 String 数组,但没有任何效果。我认为可以在
override func viewDidLoad()
、func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
、func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
或其他地方找到潜在的修复方法。
当前视图控制器:
应用程序打开时当前显示的内容:
下面是 artSearchViewController 中的当前代码。
import UIKit
import SQLite3
class artSearchViewController: UIViewController,UITableViewDelegate, UITableViewDataSource{
@IBOutlet weak var txtArtNameField: UITextField!
@IBOutlet weak var txtArtistNameField: UITextField!
@IBOutlet weak var txtLocationField: UITextField!
@IBOutlet weak var txtYearField: UITextField!
// Location of the database on the computer.
var dbPath = "/Users/williamfletcher/Documents/School Files/DIS/Assignment Work/Year 12 Term 2/Database File/art_finder_app.db"
// Variable that points to the location of a database, nor created until first used.
lazy var db = openDatabase()
// Variable to hold an SQL query.
var queryStatementString = ""
// Arrays that will store the data collected from a search using SQL.
var artName:[String] = [""]
var artist:[String] = [""]
var artLocation:[String] = [""]
var artYear:[Int] = [0]
var artYearString:[String] = [""]
// Art Info Var
var artInfo: [artworkDetails] = []
// Currently not working 100% correctly.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Remove 'return' if code does not work.
return artInfo.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Display cell items on outlets that exist in the class.
let cell = tableView.dequeueReusableCell(withIdentifier: "artInfoCell", for: indexPath) as! searchArtDescriptionTableViewCell
// For each cell update with the correct image, name and information. Check outlet names are correct.
// Interestingly, only the text "Artist:, "Date:", and "Location appears.
cell.lblArtName.text = self.artInfo[indexPath .row].artName
cell.lblArtistName.text = "Artist: " + self.artInfo[indexPath .row].artistName
cell.lblArtDate.text = "Date: " + self.artInfo[indexPath .row].artDate
cell.lblArtLocation.text = "Location: " + self.artInfo[indexPath .row].artLocation
cell.imgArtPhoto.image = UIImage (named: artInfo[indexPath .row].artImage)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 132
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let destinationVC = self.storyboard?.instantiateViewController(withIdentifier: "artInfoView") as! artInfoViewController
savedArtName = artName[indexPath.row]
self.present(destinationVC, animated: true, completion: nil)
}
// This fuctionion will open up the database if it can find it, and return a pointer to the database location. Otherwise an error message is printed. (ONLY USEFUL FOR ADDING INFORMATION TO THE DATABASE)
func openDatabase() -> OpaquePointer? {
var db: OpaquePointer? = nil
if sqlite3_open(dbPath, &db) == SQLITE_OK {
print("Successfully opened connection to database as \(dbPath)")
return db
} else {
print("Unable to locate database")
return nil
}
}
// Process SQL Quaries
func queryArtInfomationList() {
// Pointer that keeps track of where we are up to - records
var queryStatement: OpaquePointer?
// If the query can be run in the database; proceed.
if sqlite3_prepare_v2(db, queryStatementString, -1, &queryStatement, nil) == SQLITE_OK {
// Results will be collected one row/record at a time.
// The order of results depends on order in the selected statement.
while sqlite3_step(queryStatement) == SQLITE_ROW {
// HANDLES SQL TEXT
// Return data from records: art name[0]
guard let qrArtName = sqlite3_column_text(queryStatement, 0)
else {
print("Query result: art name is nil")
return
}
// Return data from record: artist[1]
guard let qrArtist = sqlite3_column_text(queryStatement, 1)
else {
print("Query result: artist name is nil")
return
}
// Return data from record: location[2]
guard let qrArtLocation = sqlite3_column_text(queryStatement, 2)
else {
print("Query result: art location is nil")
return
}
// Return data from record: artYear[4]
let qrArtYear = sqlite3_column_int(queryStatement, 4)
// CONVERT int32 to Int (Swift)
let artYearResult = Int("\(qrArtYear)")
// Convert data collected from the database that are stored as C values to Swift.
// CONVERT cString to String (Swift)
let artNameResult = String(cString: qrArtName)
let artistResult = String(cString: qrArtist)
let artLocationResult = String(cString: qrArtLocation)
// Integers append
artYear.append(artYearResult!)
// STORE Swift version of results in the arrays.
// Strings - if arrays are empty initialise with a value first
if artName != nil {
artName.append(artNameResult)
} else {
artName = [artNameResult]
}
if artist != nil {
artist.append(artistResult)
} else {
artist = [artistResult]
}
if artLocation != nil {
artLocation.append(artLocationResult)
} else {
artLocation = [artLocationResult]
}
// trace for debugging purposes
print("Query Result:")
print("\(artName) \(artYear) \(artist) \(artLocation)")
}
} else {
print("Error with SQL query/command")
}
sqlite3_finalize(queryStatement)
}
@IBOutlet weak var tblSearchArtList: UITableView!
@IBAction func btnArtSearch(_ sender: Any) {
var typedArtName:String = String(txtArtNameField.text!)
var typedArtist:String = String(txtArtistNameField.text!)
var typedLocaiton:String = String(txtLocationField.text!)
var typedYear:String = String(txtYearField.text!)
artName.removeAll()
artist.removeAll()
artLocation.removeAll()
artYear.removeAll()
// SQL query used with this search term that is stored in the variable queryStatementString
queryStatementString = "SELECT * FROM art_data WHERE art_name LIKE '%\(typedArtName)%' AND artist LIKE '%\(typedArtist)%' AND location LIKE '%\(typedLocaiton)%' AND installation_year LIKE '%\(typedYear)%' ORDER BY art_name ASC;"
print("\(queryStatementString)")
// Function that processes the query and stores the results
queryArtInfomationList()
print ("\(artName.count)")
}
@IBAction func btnHome(_ sender: Any) {
let destinationVC = self.storyboard?.instantiateViewController(withIdentifier: "homeView") as! homeViewController
self.present(destinationVC, animated:true, completion: nil)
}
@IBAction func btnSavedArt(_ sender: Any) {
let destinationVC = self.storyboard?.instantiateViewController(withIdentifier: "savedArtView") as! savedArtViewController
self.present(destinationVC, animated:true, completion: nil)
}
@IBAction func btnMap(_ sender: Any) {
let destinationVC = self.storyboard?.instantiateViewController(withIdentifier: "artMapView") as! artMapViewController
self.present(destinationVC, animated:true, completion: nil)
}
override func viewDidLoad() {
// CODE NEEDED
artYearString = artYear.map { String($0) }
for i in 0 ... artName.count - 1 {
artInfo.append(artworkDetails(artName: artName[i], artistName: artist[i], artLocation: artLocation[i], artDate: artYearString[i], artImage: artName[i]))
}
super.viewDidLoad()
// CODE NEEDED
}
我尝试过但没有奏效的事情包括添加 artWork 支柱。
import Foundation
struct artworkDetails {
let artName: String
let artistName: String
let artLocation: String
let artDate: String
let artImage: String
}
以及
tblSearchArtList.reloadData()
在覆盖功能中。
您使用结构来保存有关艺术品的所有信息的想法很好。维护多个数组很脆弱。如果您最终在任何数组中得到不同数量的元素,您的代码可能会因“数组索引超出范围”错误而崩溃。
但这不是你问题的原因。问题是您的代码在表格视图显示之前不会加载数据。
一旦你确定你的SQL加载完成,你应该在主线程上调用你的表视图的
reloadData()
方法。这将导致表视图重新向数据源询问部分的数量,以及数量每个部分的行数,然后要求显示单元格。
我没怎么用过SQLite,也很久没用过了。我认为我 ever 使用过 SQLite3 Swift 库。需要进行一些研究才能弄清楚它如何处理查询并告诉您如何判断它何时完成加载行。我认为你会在你打电话给
tableView.reloadData()
之后添加一个电话给queryArtInfomationList()
。