核心数据 - 某些属性崩溃:objc_release

Posted

技术标签:

【中文标题】核心数据 - 某些属性崩溃:objc_release【英文标题】:Core Data -Crash on certain Properties: objc_release 【发布时间】:2021-12-26 15:18:36 【问题描述】:

我的 CoreData 实体文件中有几个名为 UnsavedModel 的属性,这里是其中的一些。

我使用 CollectionView 创建了自己的文件,当我实例化 newBodyTextnewHttpsStr 属性时,它崩溃了。正确的值被输入到这两个属性中,它们只是字符串,但它只会在这些属性上崩溃,而不会在其他属性上崩溃。 如果我不给这些属性赋值,一切都会正常。这里有什么问题?

问题出现顺序如下:

    HomeVC > buttonPress 立即按下 UnsavedVC UnsavedVC(正确加载单元格)> backButtonPressed 立即弹回 HomeVC HomeVC > buttonPress 立即按下 UnsavedVC 崩溃

仅供参考,我在写入这些属性时没有问题。但是当我尝试删除这 2 个属性时,它会崩溃,但删除任何其他属性都没有问题。

我在Thread 1 Queue : com.apple.main-thread (serial) 上也遇到了同样的问题。

代码:

class UnsavedController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout 

    var datasource = [CopyCoreDataModel]()

    override func viewDidLoad() 
        super.viewDidLoad()

        fetchData()
    

    func fetchData() 

        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else  return 
        let context = appDelegate.persistentContainer.viewContext

        // I also tried context.performAndWait  ... run the do-try-catch fetchRequest in here... 

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

        do 
            let results = try context.fetch(fetchRequest)
            
            for result in results 
                
                guard let id = result.value(forKey: "id") as? String else  continue 
                
                let isContained = tableData.contains(where:  $0.id ?? "" == id )
                
                if !isContained 
                    let copy = CopyCoreDataModel(id: id, unsavedModel: result)
                    datasource.append(copy)
                
            
            
            collectionView.reloadData()

         catch 
            print(error)
        
    


// CopyCoreDataModel is necessary because I run some functions based on certain properties
class CopyCoreDataModel 

    var fileUrl: URL?

    var id: String?
    var unsavedModel: UnsavedModel?

    var postDate: Double?
    // otherProperties of type String, Double, and Boolean

    var micUrl: String?
    var newBodyText: String?
    var newHttpsStr: String?

    init(id: String, unsavedModel: UnsavedModel) 

        self.id = id
        self.unsavedModel = unsavedModel

        // self otherProperties = unsavedModel.otherProperties // run some function on some of the other properties. These all work perfectly fine

        if let micUrl = unsavedModel.micUrl  // works perfectly fine
            self.micUrl = micUrl
            // function to get micURL from FileManager that eventually sets self.fileUrl
        

        if let newBodyText = unsavedModel.newBodyText  // crash occurs here only if it has a value
            self.newBodyText = newBodyText
        

        if let newHttpsStr = unsavedModel.newHttpsStr  // crash occurs here only if it has a value
            self.newHttpsStr = newHttspStr
        
    


func writeData(micURL: URL) 

    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else  return 
    let context: NSManagedObjectContext = appDelegate.persistentContainer.viewContext
    let entity: NSEntityDescription = NSEntityDescription.entity(forEntityName: "UnsavedModel", in: context)!

    let object: NSManagedObject = NSManagedObject(entity: entity, insertInto: context)

    object.setValue(UUID().uuidString, forKey: "id")
    object.setValue(micURL.path, forKey: "micUrl")
    object.setValue("abc", forKey: "newBodyText")
    object.setValue("https...", forKey: "newHttpsStr")
    // set other properties

    do 
        try context.save()
        
     catch let error as NSError 
        print("could not save . \(error), \(error.userInfo)")
    

我还设置了一个类似 this 的 sharedInstance 并通过 let context = CoreDataManager.sharedManager.persistentContainer.viewContext 访问了上下文,但出现了同样的问题

更新

我还更改了 CopyCoreDataModel 的初始化程序以使用来自 unsavedModel 的 k/v 字典,但崩溃仍然发生

class CopyCoreDataModel 

    // same exact properties

    init(id: String, dict: [String: Any]) 

        // set the properties using the values from the dict

    


func fetchData() 

    let context = // ...        
    let fetchRequest = // ...

    do 
        let results = try context.fetch(fetchRequest)

        for result in results 
            
            guard let id = result.value(forKey: "id") as? String else  continue 
            
            let isContained = datasource.contains(where:  $0.id ?? "" == id )
            
            if !isContained 
                
                let dict = createDictFromUnsavedModel(unsavedModel: result)
                let copy = CopyCoreDataModel(id: id, dict: dict)
                datasource.append(copy)
            
        
        
        collectionView.reloadData()

     catch  
    


func createDictFromUnsavedModel(unsavedModel: UnsavedModel) -> [String:Any] 

    var dict = [String: Any]()

    // set dict using k/v from unsavedModel

    return dict

【问题讨论】:

可能不相关,但不应该是self.newHttspStr = newHttspStr 而不是self.newBodyText = newHttspStr 哦,是的,这是一个错字,我的实际代码中没有(它是正确的)。让我修复它。谢谢!我想我刚刚发现了这个问题。我正在测试它并即将发布。我认为修复它的修复并没有修复它 @vadian 我认为您应该在下面查看此答案。我知道你在这方面非常熟练,但这是一件很容易被忽视的事情。也许你会再次遇到这种情况。谢谢你的帮助顺便说一句!!! 【参考方案1】:

哇,谁能想到……

问题在于两个名称都以 new 开头,如 newBodyTextnewHttpsStr。这在 Obj-C 中是不允许的,CoreData 基于 Obj-C。我找到了@Silfverstrom 的答案here

来自苹果documentation:

为了允许与手动保留释放代码的互操作,ARC 强加了一个 对方法命名的约束:

不能为访问者指定以 new 开头的名称。这反过来 意味着您不能,例如,声明一个 nameproperty 以 new 开头,除非您指定不同的 getter

一旦我将它们从 newBodyTextnewHttpsStr 更改为 updatedBodyTextupdatedHttpsStr,崩溃就消失了。 p>

【讨论】:

以上是关于核心数据 - 某些属性崩溃:objc_release的主要内容,如果未能解决你的问题,请参考以下文章

核心数据 - 向 xcddatamodel 文件添加额外属性后应用程序崩溃

核心数据:访问 NSManagedObject 属性时应用程序崩溃

应用程序因核心数据的一个属性而崩溃

在新版本中添加现有实体的新属性时核心数据崩溃

当我们保存在 NSUserDefaults 中时,从核心数据和应用程序中获取“<NULL>”数据会崩溃?

试图设置核心数据关系导致崩溃