[NSDecimalNumber 保留]:消息发送到已释放实例 0x174222220,但为啥呢?

Posted

技术标签:

【中文标题】[NSDecimalNumber 保留]:消息发送到已释放实例 0x174222220,但为啥呢?【英文标题】:[NSDecimalNumber retain]: message sent to deallocated instance 0x174222220, but why?[NSDecimalNumber 保留]:消息发送到已释放实例 0x174222220,但为什么呢? 【发布时间】:2017-01-03 15:37:40 【问题描述】:

我似乎遇到了这个错误。

*** -[NSDecimalNumber retain]: message sent to deallocated instance 0x174222220

我第一次运行应用程序时,代码执行良好,但如果我回到那个 VC,应用程序会崩溃并显示上面的消息。我做了一些研究,我认为这意味着一些 NSDecimal 是如何发布的。这很奇怪,因为我还有 3 个其他小数的设置方式完全相同。

小数点存储在 Core Data 中,然后在我的 VC 中的 cellForIndexAt 方法中设置为标签。

print("\(historyEntry.newAmount) new amount")

我第一次取回正确的金额。但是第二次或者如果我尝试移动表格视图,应用程序会因上面的消息而崩溃。什么会导致小数释放自己?

编辑

我有一个 CoreDataStack swift 文件,并且 managedContext 是这样创建的:

    lazy var managedContext: NSManagedObjectContext = 
    return self.storeContainer.viewContext
()

我正在获取这样的对象:

  // load the data
    let fetchRequest: NSFetchRequest<Statement> = Statement.fetchRequest()
    fetchRequest.predicate = NSPredicate(format:"person.name == %@ AND amountOwed >= 0", personName)

    let sort = NSSortDescriptor(key: #keyPath(Statement.amountOwed), ascending: true)
    fetchRequest.sortDescriptors = [sort]
    positiveFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.managedContext, sectionNameKeyPath: nil, cacheName: nil)

    do
        try positiveFetchedResultsController.performFetch()
    catch let error as NSError
        print("Fetching error: \(error), \(error.userInfo)")
    
    positiveFetchedResultsController.delegate = self

我认为将我正在使用的获取的对象传递给另一个 ViewController 并像这样访问它的属性:

print("\(historyEntry.changeAmount) change amount") // gives me back the correct amount that was saved evrytime.

这个属性在第一次之后崩溃

print("\(historyEntry.newAmount) new amount") // first time correct, after that error message from above.

编辑

这里是 CoreDataStack 类

    import Foundation
import CoreData

class CoreDataStack 

    private let modelName: String

    init(modelName: String) 
        self.modelName = modelName
    

    lazy var managedContext: NSManagedObjectContext = 
        return self.storeContainer.viewContext
    ()

    private lazy var storeContainer: NSPersistentContainer = 

        let container = NSPersistentContainer(name: self.modelName)
        container.loadPersistentStores  (storeDescription, error) in
            if let error = error as NSError? 
                print("Unresolved error \(error), \(error.userInfo)")
            
        
        return container
    ()

    func saveContext () 
        guard managedContext.hasChanges else  return 

        do 
            try managedContext.save()
         catch 
            let nserror = error as NSError
            print("Unresolved error \(nserror), \(nserror.userInfo)")
        
    

【问题讨论】:

可以设置异常断点看看 我不确定我是否知道如何创建异常断点 您向已释放实例发送消息。这就是你的应用崩溃的原因 为什么会被释放? 你有一个正在被释放的对象的引用。这被称为“僵尸”。自从 Apple 引入 ARC(这是 Swift 的唯一选择)以来,这些就不太常见了。你有没有声明为不安全而不是弱的变量?通常 Swift 负责清零弱引用,所以你得到一个 nil 而不是僵尸。发布有关您的 NSDecimalNumbers 声明及其创建/发布方式的信息。 【参考方案1】:

您的 NSDecimalNumber 属性的名称是什么?如果任何属性名称以“new”开头,则会混淆 ARC 并导致此类问题。

引用Apple's Introduction to ARC,

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

【讨论】:

【参考方案2】:

我会尝试确保在您重新进入 VC 时托管对象上下文没有被解除分配和重新分配。这可以解释为什么您的 MOC 会被释放。

除此之外,我会在 Product/Scheme/Edit Scheme/Run/Diagnostics 下启用“Zombie Objects”,看看是否提供了更多提示。

【讨论】:

如何检查托管对象上下文是否正在被释放?我确实启用了 Zombie Objects,没有太大帮助,只是告诉我 NSDecimal 对象已被释放。 它不会告诉您NSDecimalNumber 被释放的位置吗?任何有用的堆栈跟踪?关于被释放的 MOC,您应该检查您的代码以了解 - 也许您正在创建第二个 MOC 并将其分配给相同的引用 - 另外,请尝试记录其地址以查看它是否更改...

以上是关于[NSDecimalNumber 保留]:消息发送到已释放实例 0x174222220,但为啥呢?的主要内容,如果未能解决你的问题,请参考以下文章

[UIImageAsset 保留]:发送到已释放实例的消息

为啥在 ARC 中发送消息会导致保留周期警告,但属性集不会?

ARC 禁止发送“保留”问题的显式消息

[UINavigationController 保留]:发送到已释放实例的消息

Service Broker,消息到达目标服务器但它保留在发送方队列中

ZeroMQ(0MQ)服务器保留客户端发送消息的状态信息的时间为多长时间?