You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS16下调用Language.name触发NSInvalidArgumentException崩溃求助

iOS 16下Core Data实体调用name方法崩溃问题

问题描述

调试控制台报错:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Language name]: unrecognized selector sent to instance 0x11c6f8920'
该崩溃仅在iOS 16版本出现,iOS 15.7及之前版本可正常运行,崩溃触发代码行:Button(language.name ?? "", action: {

相关代码:

import SwiftUI
import Foundation
import CoreData

struct CategoriesRevisionView: View {

@State private var selectedLanguage: String = ""
@State private var selectedLanguageSection: String = ""
@State var languagesWithSectionThingHomework: [Language] = []
    
@FetchRequest(entity: Language.entity(), sortDescriptors: []) var languages: FetchedResults<Language>
@FetchRequest(entity: LanguageSection.entity(), sortDescriptors: []) var languageSections: FetchedResults<LanguageSection>
@FetchRequest(entity: SectionThing.entity(), sortDescriptors: [NSSortDescriptor(key: "native", ascending: true)]) var sectionThings: FetchedResults<SectionThing>
@FetchRequest(entity: CommonWordThing.entity(), sortDescriptors: []) var commonWords: FetchedResults<CommonWordThing>

let tintColour = TintColour()

var revisionThings: [SectionThing] {
    if self.selectedLanguageSection == "" {
        return sectionThings.filter{ $0.setAsRevision == true && $0.languageSection?.language?.name == selectedLanguage }
    } else {
        return sectionThings.filter{ $0.setAsRevision == true && $0.languageSection?.name == selectedLanguageSection && $0.languageSection?.language?.name == selectedLanguage}
    }
}

var languagesToAddHomework: [Language] {
    var languagesWithoutHomework: [Language] = []

    for languageSection in languageSections {
        if languageSection.setAsRevision == false {
            if !languagesWithoutHomework.contains(languageSection.language ?? Language()) {
                languagesWithoutHomework.append(languageSection.language ?? Language())
            }
        }
    }
    return languagesWithoutHomework
}

var languagesToRemoveHomework: [Language] {
    var languagesWithHomework: [Language] = []

    for languageSection in languageSections {
        if languageSection.setAsRevision == true {
            if !languagesWithHomework.contains(languageSection.language ?? Language()) {
                languagesWithHomework.append(languageSection.language ?? Language())
            }
        }
    }
    return languagesWithHomework
}

var languageSectionsToAddHomework: [LanguageSection] {
    var languageSectionsWithoutHomework: [LanguageSection] = []
    
    for languageSection in languageSections {
        if languageSection.setAsRevision == false {
            if !languageSectionsWithoutHomework.contains(languageSection) {
                languageSectionsWithoutHomework.append(languageSection)
            }
        }
    }
    
    return languageSectionsWithoutHomework
}

var languageSectionsToRemoveHomework: [LanguageSection] {
    var languageSectionsWithHomework: [LanguageSection] = []
    
    for languageSection in languageSections {
        if languageSection.setAsRevision == true {
            if !languageSectionsWithHomework.contains(languageSection) {
                languageSectionsWithHomework.append(languageSection)
            }
        }
    }
    
    return languageSectionsWithHomework
}

var languageCategories: [LanguageSection] {
    return languageSections.filter { $0.setAsRevision == true }
}

var body: some View {
    List {
        ForEach(revisionThings ?? [], id: \.self) { revisionThing in
            ThingRowView(thing: revisionThing, commonWords: Array(commonWords), resizedImage: UIImage())
            .swipeActions(edge: .trailing, allowsFullSwipe: false) {
                Button {
                    setRevision.unsetFilteredHomeworkThingRevision(sectionThings: [revisionThing], languageSections: Array(languageSections), commonWordThings: Array(commonWords))
                    computeLanguagesWithSectionHomework()
                    selectLanguageAndSection()
                    
                    PersistenceController.shared.saveDB()
                    dataSetIsEmpty()
                } label: {
                    Image("removeHomework")
                }
                .tint(tintColour.SetRevisionSectionThing(sectionThing: revisionThing))
            }
        }
    }
    .listStyle(InsetGroupedListStyle())
    .background(Color.init(.systemGroupedBackground))
    .navigationBarTitle("Revision", displayMode: .inline).opacity(0.8)
    .toolbar {
        ToolbarItemGroup(placement: .navigationBarLeading) {
            Menu {
                ForEach(languagesWithSectionThingHomework, id: \.self) { language in
                    Button("\(language.name ?? "")", action: {
                        self.selectedLanguage = language.name ?? ""
                        self.selectedLanguageSection = ""
                   })
                    Menu("Categories") {
                        ForEach(languageCategories, id: \.self) { languageSection in
                            if languageSection.language == language {
                                Button("\(languageSection.name ?? "")", action: {
                                    self.selectedLanguage = language.name ?? ""
                                    self.selectedLanguageSection = languageSection.name ?? ""
                                })
                            }
                        }
                    }
                    Divider()
                }
            } label: {
                if languageSections.filter{ $0.setAsRevision == true }.count <= 1 {
                    Label("Choose Homework Language", image: "menu")
                } else {
                    Label("Choose Homework Language", image: "menu").foregroundColor(Color.systemBlue)
                }
            }
            .disabled(languageSections.filter{ $0.setAsRevision == true }.count <= 1)
            
            Menu {
                ForEach(languagesToAddHomework, id: \.self) { language in
                    Button(language.name ?? "", action: {
                        setRevision.setSectionThingRevision(sectionThings: sectionThings.filter { $0.languageSection?.language == language }, commonWordThings: Array(commonWords), languageSections: Array(languageSections))
                        computeLanguagesWithSectionHomework()
                        self.selectedLanguage = language.name ?? ""
                        self.selectedLanguageSection = ""
                    })
                    Menu("Categories") {
                        ForEach(languageSectionsToAddHomework.filter { $0.language == language }, id: \.self) { languageSection in
                            Button(languageSection.name ?? "", action: {
                                setRevision.setSectionThingRevision(sectionThings: sectionThings.filter { $0.languageSection?.language == language && $0.languageSection == languageSection }, commonWordThings: Array(commonWords), languageSections: Array(languageSections))
                                computeLanguagesWithSectionHomework()
                                self.selectedLanguage = language.name ?? ""
                                self.selectedLanguageSection = languageSection.name ?? ""
                            })
                        }
                    }
                    Divider()
                }
            } label: {
                if sectionThings.filter{ $0.setAsRevision == true }.count == sectionThings.count {
                    Image("revisionAdd")
                } else {
                    Image("revisionAdd").foregroundColor(.green)
                }
            }
            .disabled(sectionThings.filter{ $0.setAsRevision == true }.count == sectionThings.count)
            
            Menu {
                ForEach(languagesToRemoveHomework, id: \.self) { language in
                    Button(language.name ?? "", action: {
                        setRevision.unsetFilteredHomeworkThingRevision(sectionThings: sectionThings.filter { $0.languageSection?.language == language }, languageSections: Array(languageSections), commonWordThings: Array(commonWords))
                        
                        computeLanguagesWithSectionHomework()
                        selectLanguageAndSection()
                        dataSetIsEmpty()
                    })
                    Menu("Categories") {
                        ForEach(languageSectionsToRemoveHomework.filter { $0.language == language }, id: \.self) { languageSection in
                            Button(languageSection.name ?? "", action: {
                                setRevision.unsetFilteredHomeworkThingRevision(sectionThings: languageSection.sectionThing?.allObjects as? [SectionThing] ?? [], languageSections: Array(languageSections), commonWordThings: Array(commonWords))
                                
                                computeLanguagesWithSectionHomework()
                                selectLanguageAndSection()
                                dataSetIsEmpty()
                            })
                        }
                    }
                    Divider()
                }
            } label: {
                if sectionThings.filter{ $0.setAsRevision == true }.count == 0 {
                    Image("revisionRemove")
                } else {
                    Image("revisionRemove").foregroundColor(.yellow)
                }
            }
            .disabled(sectionThings.filter{ $0.setAsRevision == true }.count == 0)
        }
    }
    .onAppear(perform: initialize)
}

func initialize() {
outerloop: for language in languages {
        if let languageSections = language.languageSection?.allObjects as? [LanguageSection] {
            for languageSection in languageSections {
                if let languageSectionThings = languageSection.sectionThing?.allObjects as? [SectionThing] {
                    if languageSectionThings.filter({ $0.setAsRevision == true }).count > 0 {
                        self.selectedLanguage = language.name ?? ""
                        self.selectedLanguageSection = languageSection.name ?? ""
                        break outerloop
                    }
                }
            }
        }
    }
    
    dataSetIsEmpty()
    
    computeLanguagesWithSectionHomework()
}

func computeLanguagesWithSectionHomework() {
    var sectionThingLanguages: [Language] = []
    
    for language in languages {
        if languageSections.filter({ $0.language == language && $0.setAsRevision == true }).count > 0 {
            if !sectionThingLanguages.contains(language) {
                sectionThingLanguages.append(language)
            }
        }
    }
    
    self.languagesWithSectionThingHomework = sectionThingLanguages
}

func selectLanguageAndSection() {
    if revisionThings?.count == 0 {
        if languageSections.filter({ $0.sectionThing?.allObjects.count ?? 0 > 0 && $0.setAsRevision == true }).count > 0 {
            selectedLanguageSection = languageSections.filter{ $0.sectionThing?.allObjects.count ?? 0 > 0 && $0.setAsRevision == true }[0].name ?? ""
            selectedLanguage = languageSections.filter{ $0.sectionThing?.allObjects.count ?? 0 > 0 && $0.setAsRevision == true }[0].language?.name ?? ""
        }
    }
}

问题分析与解决方案

核心原因

崩溃本质是代码中创建了未关联Core Data上下文的空Language实例,这类实例没有动态生成的name属性访问方法。iOS 16对Core Data实例的合法性校验更严格,直接暴露了这个问题,而iOS 15.7的校验逻辑更宽松,所以未触发崩溃。

具体修复步骤

1. 移除非法的默认初始化器调用

找到所有languageSection.language ?? Language()的代码,替换为跳过nil值的逻辑,避免创建无效实例:

// 修改languagesToAddHomework
var languagesToAddHomework: [Language] {
    var languagesWithoutHomework: [Language] = []

    for languageSection in languageSections {
        guard let language = languageSection.language else { continue } // 跳过nil的language
        if languageSection.setAsRevision == false {
            if !languagesWithoutHomework.contains(where: { $0.objectID == language.objectID }) {
                languagesWithoutHomework.append(language)
            }
        }
    }
    return languagesWithoutHomework
}

// 同理修改languagesToRemoveHomework
var languagesToRemoveHomework: [Language] {
    var languagesWithHomework: [Language] = []

    for languageSection in languageSections {
        guard let language = languageSection.language else { continue }
        if languageSection.setAsRevision == true {
            if !languagesWithHomework.contains(where: { $0.objectID == language.objectID }) {
                languagesWithHomework.append(language)
            }
        }
    }
    return languagesWithHomework
}

2. 校验Core Data实体配置

  • 打开Core Data模型文件,确认Language实体存在name属性,且属性类型、配置正确。
  • 确保Language类是Xcode自动生成的,若手动编写类,需确保正确实现name的get/set方法。

3. 过滤无效实例

在生成languagesWithSectionThingHomework时,添加实例有效性校验:

func computeLanguagesWithSectionHomework() {
    var sectionThingLanguages: [Language] = []
    
    for language in languages {
        guard language.managedObjectContext != nil else { continue } // 仅保留关联上下文的有效实例
        if languageSections.filter({ $0.language == language && $0.setAsRevision == true }).count > 0 {
            if !sectionThingLanguages.contains(where: { $0.objectID == language.objectID }) {
                sectionThingLanguages.append(language)
            }
        }
    }
    
    self.languagesWithSectionThingHomework = sectionThingLanguages
}

内容的提问来源于stack exchange,提问作者Tycho Systems

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 13:45:38