搜尋

首頁  >  問答  >  主體

ios - 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.
    }
}

PHPzPHPz2772 天前715

全部回覆(2)我來回復

  • ringa_lee

    ringa_lee2017-04-18 09:06:25

    解決啦! ! !
    我嘗試了在頁面載入時加入一段程式碼,讓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)//开始时显示第一笔数据
        }

    有興趣的大神可以幫我看看還有哪裡需要改進的地方,整個程式碼運行時,點擊修改點是會彈出不成功的那個對話框!

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-18 09:06:25

    從提示來看,出錯的地方應該是訪問 arrStu 時下標越界了, 你檢查一下 arrStu 的長度, 有第 n 個元素嗎? 另外,如果沒有,為什麼會導致需要存取數組中不存在的元素的情況?

    回覆
    0
  • 取消回覆