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

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

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

问题出现顺序如下:

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

仅供参考,我在写入这些属性时没有问题。但是当我尝试删除这 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 我认为您应该在下面查看此答案。我知道你在这方面非常熟练,但这是一件很容易被忽视的事情。也许你会再次遇到这种情况。谢谢你的帮助顺便说一句!!!

标签: ios swift core-data


【解决方案1】:

哇,谁能想到……

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

来自苹果documentation

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-09
    • 2023-03-14
    • 2018-09-02
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多