首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >搜索CoreData后台线程将导致EXC_BAD_ACCESS

搜索CoreData后台线程将导致EXC_BAD_ACCESS
EN

Stack Overflow用户
提问于 2018-01-02 19:41:12
回答 1查看 153关注 0票数 0

我用Swift 4,iOS 11

我显然是在尝试做一些超出我知识水平的事情,但我希望有人能帮上忙。

我正在实现一个从CoreData获取结果的表视图搜索。搜索变得太慢了,所以我现在尝试异步运行它,以避免UI延迟。

在我的主要VC (表视图)上,运行在textDidChange上的逻辑如下:

代码语言:javascript
运行
复制
DispatchQueue.global(qos: .background).async {

    DataManager.searchAllTables(searchText: searchText){  (returnResults) -> () in

        DispatchQueue.main.async {

            // LOGIC TO GIVE RETURNED RESULTS TO TABLE

            self.resultsTable.reloadData()
        }
    }
}

在函数DataManager中的searchAllTables中,在每个CoreData关系上运行以下逻辑:

代码语言:javascript
运行
复制
// Get Disease
if let disease = bug.related_disease?.allObjects {
    if !disease.isEmpty {
        if disease.contains(where: { (($0 as AnyObject).name?.lowercased().contains(searchTerm.lowercased()))! || (($0 as AnyObject).name?.lowercased().contains(self.convertAcronyms(searchTerm: searchTerm)))! }){
            // LOGIC TO DETERMINE POINTS
        }
    }
}

在尝试实现异步之前,它工作得很好,但现在它给了我错误。

线程5: EXC_BAD_ACCESS (code=1,address=0x1a1b40cc771)

用于代码行

代码语言:javascript
运行
复制
if let disease = bug.related_disease?.allObjects {

如果用户输入速度慢,则不会出现此错误。这让我认为后台线程正在交叉,并且我试图从CoreData获取的对象发生了一些事情。

我知道EXC_BAD_ACCESS意味着“向已经发布的对象发送消息”。有人能帮我理解如何解决这个问题吗?

更新:在下面添加了searchAllTables

代码语言:javascript
运行
复制
static func searchAllTables(searchText:String, completion: @escaping ((_ returnResults:[BugElement])->())) {

    var bugElements:[BugElement] = []
    var bugElementShell:[BugElement] = []

    var returnValueRank:Int = 0
    var categoryRestriction:String = "all" // Search all categories by default
    var numSearchTerms:Int = searchText.components(separatedBy: " ").count
    let searchTerm:String = self.getSearchPhrases(searchTerms: searchText.components(separatedBy: " ")).1
    numSearchTerms = self.getSearchPhrases(searchTerms: searchText.components(separatedBy: " ")).0

    // Set category restriciton if needed
    if self.bugFilter.category_restricted[searchTerm.lowercased()] != nil{
        categoryRestriction = self.bugFilter.category_restricted[searchTerm.lowercased()]!
    }

    let fetchRequest: NSFetchRequest<Bugs> = Bugs.fetchRequest()

    // DOES THIS HELP SPEED?
    if searchTerm.count <= 3{
        let predicate = NSPredicate(format:"name beginswith[c] %@ OR ANY related_disease.name contains[c] %@ OR ANY related_general.name beginswith[c] %@ OR ANY related_gramstain.name beginswith[c] %@ OR ANY related_keypoints.name beginswith[c] %@ OR ANY related_laboratory.name beginswith[c] %@ OR ANY related_morphology.name beginswith[c] %@ OR ANY related_prevention.name beginswith[c] %@ OR ANY related_signs.name beginswith[c] %@ OR ANY related_treatments.name beginswith[c] %@ OR ANY related_type.name beginswith[c] %@", argumentArray: [searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased()])
        fetchRequest.predicate = predicate
    } else{
        let predicate = NSPredicate(format:"name contains[c] %@ OR related_disease.name contains[c] %@ OR related_general.name contains[c] %@ OR related_gramstain.name contains[c] %@ OR related_keypoints.name contains[c] %@ OR related_laboratory.name contains[c] %@ OR related_morphology.name contains[c] %@ OR related_prevention.name contains[c] %@ OR related_signs.name contains[c] %@ OR related_treatments.name contains[c] %@ OR related_type.name contains[c] %@", argumentArray: [searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased(),searchTerm.lowercased()])
        fetchRequest.predicate = predicate
    }

    do {
        let diseases = try DataManager.context.fetch(fetchRequest)

        for bug in diseases{

            // Points system (all matches past array are worth 1)
            var matchValue_name:[Int] = [10, 8, 4]
            var matchValue_disease:[Int] = [8, 4, 3]
            var matchValue_general:[Int] = [5, 3, 2]
            var matchValue_gramstain:[Int] = [5, 3, 2]
            var matchValue_keypoints:[Int] = [5, 3, 2]
            var matchValue_laboratory:[Int] = [2]
            var matchValue_morphology:[Int] = [5, 3, 2]
            var matchValue_prevention:[Int] = [2]
            var matchValue_signs:[Int] = [1]
            var matchValue_treatment:[Int] = [5, 3, 2]
            var matchValue_type:[Int] = [1]

            // Break down by word
            var matchedNameTerms:Int = 0
            var matchedDiseaseTerms:Int = 0
            var matchedGeneralTerms:Int = 0
            var matchedGramStainTerms:Int = 0
            var matchedKeyPointsTerms:Int = 0
            var matchedLaboratoryTerms:Int = 0
            var matchedMorphologyTerms:Int = 0
            var matchedPreventionTerms:Int = 0
            var matchedSignsTerms:Int = 0
            var matchedTreatmentTerms:Int = 0
            var matchedTypeTerms:Int = 0


            // BEGIN: By term

            var matchBasis = Set<String>()

            if categoryRestriction == "all" || categoryRestriction == "name"{
                // FAULT

                if bug.name.lowercased().contains(searchTerm.lowercased()){
                    matchedNameTerms += 1

                    // Matched based on disease name
                    if matchedNameTerms > (matchValue_name.count-1){
                        // Match beyond point assignment
                        returnValueRank += 1
                    } else {
                        // Matched within point assignment, add those points
                        returnValueRank += matchValue_name[(matchedNameTerms-1)]
                    }

                    // Append name if first match
                    if matchedNameTerms == 1{
                        matchBasis.insert("Name")
                    }

                }
            }

            // Get Disease
            if categoryRestriction == "all" || categoryRestriction == "disease"{
                // FAULT

                if let disease = bug.related_disease?.allObjects {
                    if !disease.isEmpty {
                        if disease.contains(where: { (($0 as AnyObject).name?.lowercased().contains(searchTerm.lowercased()))! || (($0 as AnyObject).name?.lowercased().contains(self.convertAcronyms(searchTerm: searchTerm)))! }){
                            matchedDiseaseTerms += 1

                            // Matched based on Disease
                            if matchedDiseaseTerms > (matchValue_disease.count-1){
                                // Match beyond point assignment
                                returnValueRank += 1
                            } else {
                                // Matched within point assignment, add those points
                                returnValueRank += matchValue_disease[(matchedDiseaseTerms-1)]
                            }

                            // Append Disease if first match
                            if matchedDiseaseTerms == 1{
                                matchBasis.insert("Disease")
                            }
                        }
                    }
                }
            }

            // ADDITIONAL MATCHES JUST LIKE ABOVE DISEASE BLOCK

            // END: By term

            if (matchedNameTerms + matchedDiseaseTerms + matchedGeneralTerms + matchedGramStainTerms + matchedKeyPointsTerms + matchedLaboratoryTerms + matchedMorphologyTerms + matchedPreventionTerms + matchedSignsTerms + matchedTreatmentTerms + matchedTypeTerms) > 0{

                // Create Element
                let bugElement = BugElement(rank: returnValueRank, name: bug.name, match: matchBasis) // Initialize struct
                bugElementShell.append(bugElement)


            }

            returnValueRank = 0

        }

    } catch {
        if DataManager.debug{ print("Could not get Bugs!") }
    }


    // Handle stored search
    if numSearchTerms == 0{
        // No stored search
        //print("None")
        self.storedBugElements.append(bugElementShell)
    } else if numSearchTerms > self.storedBugElements.count{
        // New search term
        //print("New")
        self.storedBugElements.append(bugElementShell)
    } else if numSearchTerms < self.storedBugElements.count{
        // Deleted search term
        //print("Delete")
        self.storedBugElements.removeLast()
    } else if numSearchTerms == self.storedBugElements.count{
        // Still typing search term
        //print("Still...")
        self.storedBugElements.removeLast()
        self.storedBugElements.append(bugElementShell)
    }

    // Handle stored search
    if self.storedBugElements.count > 0 {
        let namedElements = self.storedBugElements.joined().map { ($0.name, $0) }
        // Now combine them as you describe. Add the ranks, and merge the items
        let uniqueElements =
            Dictionary<String, BugElement>(namedElements,
                                           uniquingKeysWith: { (lhs, rhs) -> BugElement in
                                                let sum = lhs.rank + rhs.rank
                                                return BugElement(rank: sum,
                                                           name: lhs.name,
                                                           match: lhs.match.union(rhs.match))
            })

        // The result is the values of the dictionary
        let result = uniqueElements.values
        bugElements = result.sorted { $0.rank > $1.rank }

    } else{
        bugElements = bugElementShell.sorted { $0.rank > $1.rank }
    }



    completion(bugElements)

}
EN

回答 1

Stack Overflow用户

发布于 2018-01-03 09:53:31

ManagedObjectContextsmanagedObjects不是线程安全的。既不是为了读书也不是为了写作。我不需要看你在searchAllTables中做了什么,就知道你做错了。有两种类型的上下文--主队列上下文(必须始终从主线程访问)和只能通过performBlock评估的私有队列上下文。在全局后台线程上运行的上下文是不正确的。

在我看来,您的问题是将所有对象加载到内存中,并测试每个对象,而不是在获取请求时使用NSPredicate。我建议在主线程上运行搜索并修复它,这样就不会花那么长时间。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48066852

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档