用swift写了一个程序,添加了一个学生成绩管理的sqlite数据库。用的是XCODE7.3.1。
但是总会在labelId.text = "(arrStu[n].id)"处报错“fatal error: Index out of range”。
请大神们帮忙看看代码
import UIKit class ViewController: UIViewController { //数据库结构:主索引 姓名 语文成绩 数学成绩 struct stu { var id:Int32 var name:String var chinese:Int32 var math:Int32 init(id:Int32,name:String,chinese:Int32,math:Int32) { self.id = id self.name = name self.chinese = chinese self.math = math } } /*定义变量*/ var arrStu:Array= []//存储数据库的数组 var db:COpaquePointer = nil var statement:COpaquePointer = nil var sql:NSString = ""//SQL指令 var currentStu = 0//当前数据 @IBOutlet var labelId: UILabel!//显示数据编号 @IBOutlet var textName: UITextField!//输入姓名 @IBOutlet var textChinese: UITextField!//输入语文成绩 @IBOutlet var textMath: UITextField!//输入数学成绩 @IBOutlet var tableViewSqlite: UITableView! @IBOutlet var buttonInsert: UIButton! @IBOutlet var buttonWrite: UIButton! /*表格的设置*/ func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ return arrStu.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{ let cell : UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell",forIndexPath: indexPath) as UITableViewCell cell.textLabel?.text = " 姓名:\(arrStu[indexPath.row].name)" cell.detailTextLabel?.text = " 编号:\(arrStu[indexPath.row].id) 语文:\(arrStu[indexPath.row].chinese) 数学:\(arrStu[indexPath.row].math)" return cell } func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){ buttonToggle(true, writeAble: false) currentStu = indexPath.row showSingle(currentStu) } /*定义对话框*/ func alertView(alertView:UIAlertView,clickedButtonAtIndex buttonIndex:Int) { if alertView.title == " 更新 " { switch (buttonIndex) { case 0://单击“确定”按钮的处理 //确定更新数据,更新数据库 let sqltem1:String = "UPDATE class101 SET s_name ='" + textName.text! + "',s_math=" + textChinese.text! let sqltem2:String = ",s_math=" + textMath.text! + "WHERE s_id=" + labelId.text! sql = sqltem1 + sqltem2 statement = nil sqlite3_prepare_v2(db, sql.UTF8String, -1, &statement, nil) if sqlite3_step(statement) == SQLITE_DONE { alertMsg(" 成功 ", msgStr: " 数据库更新成功! ") } else { alertMsg(" 失败 ", msgStr: " 数据库更新失败! ") } //更新数组 arrStu[currentStu].name = textName.text! arrStu[currentStu].chinese = Int32(Int(textChinese.text!)!) arrStu[currentStu].math = Int32(Int(textMath.text!)!) tableViewSqlite.reloadData() default: break } } else if alertView.title == " 删除 " { switch (buttonIndex) { case 0://单击“确定”按钮的处理 //确定删除数据,更新数据库 sql = "DELETE FROM class101 WHERE s_id=" + labelId.text! statement = nil sqlite3_prepare_v2(db, sql.UTF8String, -1, &statement, nil) if sqlite3_step(statement) == SQLITE_DONE { alertMsg(" 成功 ", msgStr: " 数据库删除成功! ") } else { alertMsg(" 失败 ", msgStr: " 数据库删除失败! ") } arrStu.removeAtIndex(currentStu) tableViewSqlite.reloadData() //数据删除后,显示下一笔 if currentStu == arrStu.count { currentStu -= 1 } showSingle(currentStu) default: break } } } /*创建自定义函数*/ func showSingle(n:Int) {//显示单笔数据 labelId.text = "\(arrStu[n].id)" textName.text = arrStu[n].name textChinese.text = "\(arrStu[n].chinese)" textMath.text = "\(arrStu[n].math)" } func buttonToggle(insertAble:Bool,writeAble:Bool) -> Void { buttonInsert.enabled = insertAble buttonWrite.enabled = writeAble } func alertMsg(titleStr:String,msgStr:String) -> Void { let alertView:UIAlertView = UIAlertView(title:titleStr,message: msgStr,delegate: self,cancelButtonTitle: " 确定 ") alertView.show() } /*页面载入时*/ override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. buttonToggle(true, writeAble: false) //第一次执行时将数据库复制到Documents文件夹 let fm:NSFileManager = NSFileManager() db = nil let src:String = NSBundle.mainBundle().pathForResource("student", ofType: "sqlite")! let dst:String = NSHomeDirectory() + "/Documents/student.sqlite" if !fm.fileExistsAtPath(dst) { try! fm.copyItemAtPath(src, toPath: dst) } //连接及打开数据库 if sqlite3_open(dst, &db) != SQLITE_OK { alertMsg(" 失败 ", msgStr: " 无法打开数据库! ") } //逐笔读取数据行 while sqlite3_step(statement) == SQLITE_ROW { let id = sqlite3_column_int(statement, 0) let temName = sqlite3_column_text(statement, 1) let name = String.fromCString(UnsafePointer (temName)) let chinese = sqlite3_column_int(statement, 2) let math = sqlite3_column_int(statement, 3) let student:stu = stu(id: id, name: name!, chinese: chinese, math: math) arrStu.append(student)//将数据行存入数组 } sqlite3_finalize(statement) tableViewSqlite.reloadData() showSingle(0)//开始时显示第一笔数据 } /*按键的触发事件*/ @IBAction func modifyClick(sender: UIButton) {//修改 let alertModify:UIAlertView = UIAlertView() alertModify.title = " 更新 " alertModify.message = " 确定要更新数据吗? " alertModify.delegate = self alertModify.addButtonWithTitle(" 确定 ") alertModify.addButtonWithTitle(" 取消 ") alertModify.show() }//更新数据 @IBAction func deleteClick(sender: UIButton) {//删除 if arrStu.count > 1 {//数据大于1笔才允许删除 let alertDelete:UIAlertView = UIAlertView() alertDelete.title = " 删除 " alertDelete.message = " 确定要删除数据吗? " alertDelete.delegate = self alertDelete.addButtonWithTitle(" 确定 ") alertDelete.addButtonWithTitle(" 取消 ") alertDelete.show() } else { self.alertMsg(" 失败 ", msgStr: " 只有一笔数据时不可删除! ") } } @IBAction func insertClick(sender: UIButton) {//新增 buttonToggle(false, writeAble: true) labelId.text = "" textName.text = "" textChinese.text = "" textMath.text = "" } @IBAction func writeClick(sender: UIButton) {//写入 buttonToggle(true, writeAble: false) sql = "INSERT INTO class101 (s_name, s_chinese, s_math) VALUES ('" + textName.text! + "'," + textChinese.text! + "," + textMath.text! + ");" statement = nil sqlite3_prepare_v2(db, sql.UTF8String, -1, &statement, nil) if sqlite3_step(statement) == SQLITE_DONE { alertMsg(" 成功 ",msgStr:" 数据库新增成功! ") } else { alertMsg(" 失败 ",msgStr:" 数据库新增失败! ") } let id = Int32(sqlite3_last_insert_rowid(db)) let name = textName.text let chinese = Int32(Int(textChinese.text!)!) let math = Int32(Int(textMath.text!)!) let student:stu = stu(id:id, name:name!, chinese:chinese, math:math) arrStu.append(student)//将数据行存入数组 tableViewSqlite.reloadData() showSingle(arrStu.count - 1) currentStu = arrStu.count - 1 } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
从提示来看,出错的地方应该是访问 arrStu 时下标越界了, 你检查一下 arrStu 的长度, 有第 n 个元素吗? 另外,如果没有,为什么会导致需要访问一个数组中不存在的元素的情况?
解决啦!!!
我尝试了在页面载入时加入一段代码,让tableview在载入时就显示数据库中已有的数据库,就不会报错了。极有可能是原来代码表格载入时是不显示数据的,这样表格中没有数据,所以后面的函数才会报“fatal error: Index out of range”这个错误。
/*页面载入时*/ override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. buttonToggle(true, writeAble: false) //第一次执行时将数据库复制到Documents文件夹 let fm:NSFileManager = NSFileManager() db = nil let src:String = NSBundle.mainBundle().pathForResource("student", ofType: "sqlite")! let dst:String = NSHomeDirectory() + "/Documents/student.sqlite" if !fm.fileExistsAtPath(dst) { try! fm.copyItemAtPath(src, toPath: dst) } //连接及打开数据库 if sqlite3_open(dst, &db) != SQLITE_OK { alertMsg(" 失败 ", msgStr: " 无法打开数据库! ") } let sql:NSString = "SELECT * FROM class101" if sqlite3_prepare_v2(db,sql.UTF8String,-1,&statement,nil) != SQLITE_OK { let alertView:UIAlertView = UIAlertView(title:" 读取失败 ",message: " 读取数据库失败! ",delegate: self,cancelButtonTitle: " 确定 ") alertView.show() exit(1) } arrStu.removeAll(keepCapacity: true) //逐笔读取数据行 while sqlite3_step(statement) == SQLITE_ROW { let id = sqlite3_column_int(statement, 0) let temName = sqlite3_column_text(statement, 1) let name = String.fromCString(UnsafePointer<CChar>(temName)) let chinese = sqlite3_column_int(statement, 2) let math = sqlite3_column_int(statement, 3) let student:stu = stu(id: id, name: name!, chinese: chinese, math: math) arrStu.append(student)//将数据行存入数组 } sqlite3_finalize(statement) tableViewSqlite.reloadData() showSingle(0)//开始时显示第一笔数据 }
有兴趣的大神可以帮我看看还有哪里需要改进的地方,整个代码运行时,点击修改点是会弹出不成功的那个对话框!