首页 > swift管理SQLite数据库,请大神帮忙看看为何总报错“fatal error: Index out of range”。

swift管理SQLite数据库,请大神帮忙看看为何总报错“fatal error: Index out of range”。

用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<stu> = []//存储数据库的数组
    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<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)//开始时显示第一笔数据
    }

    /*按键的触发事件*/
    @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.
    }
}


解决啦!!!
我尝试了在页面载入时加入一段代码,让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)//开始时显示第一笔数据
    }

有兴趣的大神可以帮我看看还有哪里需要改进的地方,整个代码运行时,点击修改点是会弹出不成功的那个对话框!


从提示来看,出错的地方应该是访问 arrStu 时下标越界了, 你检查一下 arrStu 的长度, 有第 n 个元素吗? 另外,如果没有,为什么会导致需要访问一个数组中不存在的元素的情况?

【热门文章】
【热门文章】