当我尝试在后台线程中读取数据库时出现问题。有几个崩溃消息,例如" EXC_BAD_INSTRUCTION",引用FMDatabase.m
文件中的不同代码行,但数据库错误消息只有一个:
2018-04-04 09:16:17.166 MyAppName [821:12717] FMDatabase目前正在使用中。
当我在不同的ViewControllers中对我的项目进行编码时,这个消息错误一直伴随着我,直到今天我还以为我的数据库实例/选择函数已经出现了,但我发现问题是由后台线程发生的。这是我的代码的一部分。
我的数据库实例:
class func getInstance() -> DBHelper {
let documentsFolder = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
databasePath = (documentsFolder + "/myAppName.db") as NSString
let filemgr = FileManager.default
if !filemgr.fileExists(atPath: databasePath as String) {
let contactDB = FMDatabase(path: databasePath as String)
if (contactDB.open()) {
/*** my instructions to create an database ***/
contactDB.close()
}
} else {
//database exist, check version and update schema
//version number numerated from 0 (default is 0)
let version = sharedInstance.checkVersion()
print("version: \(version)")
// switch version {
//
// case 0:
//
// print("case 0")
//
// sharedInstance.setVersion(version: Int32(dbVersion))
// break
//
// default:
//
// break
//
// }
}
if(sharedInstance.database == nil) {
let documentsFolder = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
databasePath = (documentsFolder + "/myAppName.db") as NSString
sharedInstance.database = FMDatabase(path: databasePath as String)
}
return sharedInstance
}
我的选择功能,通常会导致问题:
func selectAllWhere(tableName:String, whereColumns:String) -> FMResultSet {
if sharedInstance.database!.open() {
do {
let querySQL = "SELECT * FROM \(tableName) WHERE \(whereColumns)"
let result = try self.database?.executeQuery(querySQL, values: [])
return result!
} catch {
print("error = \(error.localizedDescription)")
print("error = code: \(database?.lastErrorCode()) message: \(database?.lastErrorMessage())")
return FMResultSet()
}
} else {
return FMResultSet()
}
}
使用示例(自定义日历,应显示月,月中每天的多个事件,并使用UIPageViewController
切换):
class MonthlyCalendar: UICollectionViewController, UICollectionViewDelegateFlowLayout {
/*** collection functions and more ***/
let newInstance:DBHelper = DBHelper.getInstance()
func setCalendarItems(month:Int) {
DispatchQueue.global(qos: .background).async {
//DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async {
//DispatchQueue.global().async(execute: {
let calendar = Calendar.current
let date = calendar.date(byAdding: .month, value: page, to: start!)
let dayRange = calendar.range(of: .day, in: .month, for: date!)
for currentMonthDay in 0..<dayRange!.count {
var numEvents:Int = 0
let eventForDate = calendar.date(byAdding: .day, value: currentMonthDay, to: date!)
let day = calendar.component(.weekday, from: eventForDate!)
let whereStatement = " \(db.columnEventDateStart) LIKE '%\(dateFormatter.string(from: eventForDate!))%'"
let eventQuery = self.newInstance.selectAllWhere(tableName: db.tableEvents, whereColumns: whereStatement)
while eventQuery.next() {
numEvents = numEvents + 1
}
/*** instructions, when I’m adding rows to array ***/
}
DispatchQueue.main.sync {
self.collectionView?.reloadData()
}
}
这是一个问题:
DispatchQueue.global(qos:.background).async
我的选择查询工作正常,当我删除此行时,应用程序不会崩溃(以及负责主线程更新的代码,下面几行),但是我的代码在主线程中工作,并且当我的表中的部分数据很大时,可能会锁定/冻结它,这是不好的解决方案。问题听起来像后台操作尝试在多个线程中工作,并且当第一个线程将使用我的数据库实例时,第二个线程在数据库查询上返回异常,因为第一个线程已经忙了。如果不同,请纠正我。但是,我尝试使用不同的DispatchQueues
,但是一直出现此问题。有趣的是,第一次,当我启动ViewController时,所有必需的数据都被正确读取(页面默认加载 - 3个可见页面),当我尝试左/右切换页面时,新内容导致崩溃。我无法找到解决问题的方法。以上从FMDatabase读取数据的方法以更快捷的方式呈现,我读过这些内容。请帮忙。