核心数据 - 某些属性崩溃:objc_release
Posted
技术标签:
【中文标题】核心数据 - 某些属性崩溃:objc_release【英文标题】:Core Data -Crash on certain Properties: objc_release 【发布时间】:2021-12-26 15:18:36 【问题描述】:我的 CoreData 实体文件中有几个名为 UnsavedModel 的属性,这里是其中的一些。
我使用 CollectionView 创建了自己的文件,当我实例化 newBodyText
和 newHttpsStr
属性时,它崩溃了。正确的值被输入到这两个属性中,它们只是字符串,但它只会在这些属性上崩溃,而不会在其他属性上崩溃。 如果我不给这些属性赋值,一切都会正常。这里有什么问题?
问题出现顺序如下:
-
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
开头,如 newBodyText 和 newHttpsStr。这在 Obj-C 中是不允许的,CoreData 基于 Obj-C。我找到了@Silfverstrom 的答案here
来自苹果documentation:
为了允许与手动保留释放代码的互操作,ARC 强加了一个 对方法命名的约束:
您不能为访问者指定以 new 开头的名称。这反过来 意味着您不能,例如,声明一个 name 的 property 以 new 开头,除非您指定不同的 getter
一旦我将它们从 newBodyText 和 newHttpsStr 更改为 updatedBodyText 和 updatedHttpsStr,崩溃就消失了。 p>
【讨论】:
以上是关于核心数据 - 某些属性崩溃:objc_release的主要内容,如果未能解决你的问题,请参考以下文章
核心数据 - 向 xcddatamodel 文件添加额外属性后应用程序崩溃
核心数据:访问 NSManagedObject 属性时应用程序崩溃