菜鸟教程小白 发表于 2022-12-11 19:57:09

ios - 核心数据变更处理错误


                                            <p><p>我正在开发一个硬币收集应用程序,我最近开始将核心数据集成到我的应用程序中。我有一个存储自定义 CoinCategory 对象的核心数据数据库,每个 CoinCategory 对象都有一个 Coin 对象数组。这样,我的应用程序就可以按类别存储所有内容。</p>

<p>当我整合核心数据时,我可以添加我的第一个类别没有任何错误,删除它也没有任何问题,但是当我添加第二个硬币类别时,我遇到以下错误:</p>

<p><code>2017-06-26 09:55:37.218 CoinCollection -:无法识别的选择器发送到实例 0x608000236cc0
2017-06-26 09:55:37.219215-0400 CoinCollection [错误] 错误:严重的应用程序错误。在核心数据更改处理期间捕获到异常。这通常是 NSManagedObjectContextObjectsDidChangeNotification 观察者中的一个错误。 -:无法识别的选择器使用 userInfo (null) 发送到实例 0x608000236cc0
CoreData:错误:严重的应用程序错误。在核心数据更改处理期间捕获到异常。这通常是 NSManagedObjectContextObjectsDidChangeNotification 观察者中的一个错误。 -:无法识别的选择器发送到实例 0x608000236cc0 和 userInfo (null)</code></p>

<p>谁能告诉我如何解决这个问题?非常感谢!</p>

<p>我在下面为我的 ViewController 和运行核心数据的应用程序委托(delegate)附加了我的代码。 </p>

<pre><code>    AppDelegate.swift
    //We customize the app, system-wide
    import UIKit
    import CoreData


    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {



var window: UIWindow?



//MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: &#34;CoinCollection&#34;)
    container.loadPersistentStores(completionHandler: { (storeDescription,
      error) in
      if let error = error as NSError? {
            fatalError(&#34;Unresolved error \(error), \(error.userInfo)&#34;)
      }
    })
    return container
}()
// MARK: - Core Data Saving support
func saveContext ()
{
    let context = persistentContainer.viewContext

    if context.hasChanges
    {
      do
      {
            try context.save()
      }
      catch
      {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate.
            //You should not use this function in a shipping application, although it may be useful during development.
            let nserror = error as NSError
            fatalError(&#34;Unresolved error \(nserror), \(nserror.userInfo)&#34;)
      }
    }
}
    }
</code></pre>

<p>然后是我的 ViewController 。请注意,我从调用此方法的 subviewController 中获取 Coin 对象,并且我们决定 Coin 对象是否适合现有类别。如果没有,那么我们添加新币。</p>

<pre><code>    //Controls the table view controller showing the general coins (one per each category)
    import UIKit
    import CoreData

    class CoinTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {


//this is an array of all the coins in the collection
//each row of this two-dimensional array represents a new category
var coinsByCategory: = []
var fetchResultController: NSFetchedResultsController&lt;CoinCategoryMO&gt;!


//other attributes....





////////////////////////////////////////////////////////////////////////
override func viewDidLoad()
{
    super.viewDidLoad()
    //////////////////////////////////////////////////////////////////////////////////

    //we now fetch the data
    let fetchRequest : NSFetchRequest&lt;CoinCategoryMO&gt; = CoinCategoryMO.fetchRequest()

    if let appDelegate = (UIApplication.shared.delegate as? AppDelegate)
    {
      let context = appDelegate.persistentContainer.viewContext

      let sortDescriptor = NSSortDescriptor(key: &#34;coinCategory&#34;, ascending: true)
      fetchRequest.sortDescriptors =

      fetchResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
      fetchResultController.delegate = self

      do
      {
            try fetchResultController.performFetch()
            if let fetchedObjects = fetchResultController.fetchedObjects
            {
                self.coinsByCategory = fetchedObjects
            }
      }
      catch
      {
            print(error)
      }
    }

    //configure even more....      
}



// MARK: - Table view data soure

func deleteCoinCategory(rowPath: IndexPath)
{
    if 0 &lt;= rowPath.row &amp;&amp; rowPath.row &lt; self.coinsByCategory.count
    {
      //we have just tested that the rowPath index is valid
      if let appDelegate = (UIApplication.shared.delegate as? AppDelegate)
      {
            let context = appDelegate.persistentContainer.viewContext
            let coinCategoryToDelete = self.fetchResultController.object(at: rowPath)
            context.delete(coinCategoryToDelete)

            appDelegate.saveContext()
      }
    }
}

func deleteCoin(c: Coin, indexOfSelectedCategory: IndexPath) -&gt; Bool
{
    //we have a coin that we want to delete from this viewcontroller
    //and the data contained in it.
    //
    //the parameter indexOfSelectedCategory refers to the IndexPath of the
    //row in the TableView contained in THIS viewcontroller whose category
    //of coins we are modifying in this method
    //
    //Return value: a boolean that indicates whether a single coin has
    //been deleted - meaning that the user should return to the parentviewcontroller
    if 0 &lt; indexOfSelectedCategory.row &amp;&amp; indexOfSelectedCategory.row &lt; self.coinsByCategory.count &amp;&amp; self.coinsByCategory.coinCategory?.hasCoin(c: c) == true
    {
      //the index is valid as it refers to a category in the coinsByCategory array
      //and the examined category has the coin in question
      if self.coinsByCategory.coinCategory?.count == 1
      {
            //the coin &#34;c&#34; that we are going to delete is the only coin in the entire category
            self.deleteCoinCategory(rowPath: indexOfSelectedCategory)

            return true
      }
      else
      {
            //more than one coin in the category
            self.coinsByCategory.coinCategory?.removeCoin(c: c)

            //we save the changes in the database...
            if let appDelegate = (UIApplication.shared.delegate as? AppDelegate)
            {
                appDelegate.saveContext()
            }

            return false
      }
    }

    return false
}

func addCoin(coinToAdd: Coin)
{
    //we check over each category to see if the coin can be added
    for category in self.coinsByCategory
    {
      if category.coinCategory?.coinFitsCategory(aCoin: coinToAdd) == true
      {
            //we can add the coin to the category
            category.coinCategory?.addCoin(newCoin: coinToAdd)

            if let appDelegate = (UIApplication.shared.delegate as? AppDelegate)
            {
                //we save changes to the database
                appDelegate.saveContext()

                //we are DONE with this function
                return
            }
      }
    }

    //since the coinToAdd does not fall in the existing categories, we create a new one
    if let appDelegate = (UIApplication.shared.delegate as? AppDelegate)
    {
      let newCategory = CoinCategoryMO(context: appDelegate.persistentContainer.viewContext)


      newCategory.coinCategory = CoinCategory(coins: , categoryType: CoinCategory.CategoryTypes.COUNTRY_VALUE_AND_CURRENCY)


      print(&#34;Saving data to context ...&#34;)
      appDelegate.saveContext()
    }
}



//delegate methods control the core data database
func controllerWillChangeContent(_ controller: NSFetchedResultsController&lt;NSFetchRequestResult&gt;)
{
    tableView.beginUpdates()
}

func controller(_ controller: NSFetchedResultsController&lt;NSFetchRequestResult&gt;, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?)
{
    switch type
    {
    case .insert :
      if let newIndexPath = newIndexPath
      {
            tableView.insertRows(at: , with: .fade)
      }

    case .delete:
      if let indexPath = indexPath
      {
            tableView.deleteRows(at: , with: .fade)
      }

    case .update:
      if let indexPath = indexPath
      {
            tableView.reloadRows(at: , with: .fade)
      }

    default:
      tableView.reloadData()
    }

    if let fetchedObjects = controller.fetchedObjects
    {
      self.coinsByCategory = fetchedObjects as!
    }
}

func controllerDidChangeContent(_ controller: NSFetchedResultsController&lt;NSFetchRequestResult&gt;)
{
    tableView.endUpdates()
    }
</code></pre>

<p>我期待听到您的想法,并提前感谢您的帮助!</p>

<p>编辑:</p>

<p>我的 CoinCategory 类代码:</p>

<pre><code>    //This class is supposed to represent a category of coin objects in CoreData

import Foundation
import CoreData

    public class CoinCategory: NSObject, NSCoding
    {
      //These are the various types of categories that a user can create out of their coin collection
      enum CategoryTypes : NSString
      {
            case COUNTRY_VALUE_AND_CURRENCY = //...
            case COUNTRY = //...
            case YEAR = //...
            case CURRENCY = //...
            case NO_CATEGORY = //...
      }

//this struct is used to encode data in Key-Value pairs per the NSCoding protocol
struct Keys
{
    static let Current_Category_Type = &#34;current_category_type&#34;
    static let Coins_In_Category = &#34;coins_in_category&#34;
}

//this is the collection of the coins in the category
var coinsInCategory: = []//initially we have no coins in the collection
var currentCategoryType : CategoryTypes.RawValue = &#34;&#34;

public var count : NSNumber
{
    get
    {
      //..number of coins in category
    }
}

public var array :
{
    get
    {
      //read-only copy of the Coins array..
    }
}

public required init?(coder aDecoder: NSCoder)
{
    //we decode this object&#39;s information
    if let categoryTypeObject = aDecoder.decodeObject(forKey: Keys.Current_Category_Type) as? CategoryTypes.RawValue
    {
      self.currentCategoryType = categoryTypeObject
    }

    if let coinsInCategoryArrayObject = aDecoder.decodeObject(forKey: Keys.Coins_In_Category) as?
    {
      self.coinsInCategory = coinsInCategoryArrayObject
    }
}

public func encode(with aCoder: NSCoder)
{
    //we encode this object&#39;s information
    aCoder.encode(currentCategoryType, forKey: Keys.Current_Category_Type)
    aCoder.encode(self.coinsInCategory, forKey: Keys.Coins_In_Category)
}

override init()
{
    super.init()
    self.currentCategoryType = CategoryTypes.COUNTRY_VALUE_AND_CURRENCY.rawValue
    self.coinsInCategory = []
}

convenience init(coins: , categoryType: CategoryTypes.RawValue)
{
    self.init()
    self.coinsInCategory = coins

    if isACategoryType(categoryType: categoryType) == true
    {
      self.currentCategoryType = categoryType
    }
    else
    {
       self.currentCategoryType = CategoryTypes.NO_CATEGORY.rawValue
    }
}

func isACategoryType(categoryType: NSString) -&gt; Bool
{
    switch categoryType
    {
    case CategoryTypes.COUNTRY_VALUE_AND_CURRENCY.rawValue:
      return true
    case CategoryTypes.COUNTRY.rawValue:
      return true
    case CategoryTypes.YEAR.rawValue:
      return true
    case CategoryTypes.CURRENCY.rawValue:
      return true
    default:
      return false
    }
}

func addCoin(newCoin: Coin)
{
    //we are adding a new Coin object to this category
    //if it falls into the category&#39;s type
    if self.coinFitsCategory(aCoin: newCoin) == true
    {
      self.coinsInCategory.append(newCoin)
    }
}

func coinFitsCategory(aCoin: Coin) -&gt; Bool
{
    //this function tests if aCoin fits into the category type
    //but that all varies depending on which category the coin is
    if self.coinsInCategory.count == 0
    {
      //this category is currently empty, so any addition goes!
      return true
    }

    //otherwise, this category is not empty... so we are now going to
    //examine the situation more critically
    let testCoin = self.coinsInCategory


    switch self.currentCategoryType
    {
      case CategoryTypes.COUNTRY_VALUE_AND_CURRENCY.rawValue:
            return (testCoin.getCountry().lowercased == aCoin.getCountry().lowercased) &amp;&amp; (testCoin.getValue() == aCoin.getValue()) &amp;&amp; (testCoin.getDenomination().lowercased == aCoin.getDenomination().lowercased)

    case CategoryTypes.COUNTRY.rawValue:
      return testCoin.getCountry().lowercased == aCoin.getCountry().lowercased

    case CategoryTypes.CURRENCY.rawValue:
      return testCoin.getDenomination().lowercased == aCoin.getDenomination().lowercased

    case CategoryTypes.YEAR.rawValue:
      return testCoin.getYear() == aCoin.getYear()

    default:
      return false
    }
}

func getIndexOfCoinInCollection(coin: Coin) -&gt; Int
{
    //we are going to return -1 if the coin does not exist in the collection
    //and are going to return the index otherwise if yes
    for i in 0..&lt;self.coinsInCategory.count
    {
      if coinsInCategory == coin
      {
            return i
      }
    }

    //have not found anything
    return -1
}

func removeCoin(at: Int)
{
    //we remove the coin at the index if it is in a valid range of the coinInCategory array
    if isValidArrayIndex(index: at)
    {
      self.coinsInCategory.remove(at: at)
    }
}

func getCoin(at: Int) -&gt; Coin?
{
    //we return nil if there is an issue in accessing the coin
    if isValidArrayIndex(index: at)
    {
      return self.coinsInCategory
    }
    else
    {
      return nil
    }
}

func assignCoin(at: Int,c: Coin)
{
    if isValidArrayIndex(index: at)
    {
      self.coinsInCategory.assign(right: c)
    }
}

func deleteAllCoins()
{
    //we delete all the coin in this category
    self.coinsInCategory.removeAll()
}

func removeCoin(c: Coin)
{
    //we delete a coin from the category
    for i in 0..&lt;self.coinsInCategory.count
    {
      if self.coinsInCategory == c
      {
            //the coin at index &#34;i&#34; is equal to the coin &#34;c&#34; that we want to delete from the category
            self.coinsInCategory.remove(at: i)
            return
      }
    }
}

func hasCoin(c: Coin) -&gt; Bool
{
    return getIndexOfCoinInCollection(coin: c) != -1
}

func swapValuesWithAnotherCategory(other: CoinCategory)
{
    swap(&amp;self.currentCategoryType, &amp;other.currentCategoryType)
    swap(&amp;self.coinsInCategory,&amp;other.coinsInCategory)
}

func swapCoins(indexOne: Int, indexTwo: Int)
{
    if isValidArrayIndex(index: indexOne) &amp;&amp; isValidArrayIndex(index: indexTwo)
    {
      swap(&amp;self.coinsInCategory,&amp;self.coinsInCategory)
    }
}

private func isValidArrayIndex(index: Int) -&gt; Bool
{
    return (0 &lt;= index &amp;&amp; index &lt; coinsInCategory.count)
}   
    }
</code></pre>

<p>然后是硬币类别类:
               //这为项目提供了 Class Coin 的类定义</p>

<pre><code>    import UIKit
    import CoreData

    enum TimePeriods: String
    {
      //this enumeration represents the different time periods that a
      //coin was minted in, for the sake of this programn
      case BCE = &#34;BCE&#34;
      case CE = &#34;CE&#34;
    }

    public class Coin : NSObject, NSCoding
    {
      //this struct represents all the keys used in encoding and decoding this object
      struct Keys
      {
            static let Country = &#34;country&#34;
            static let Mint = &#34;mint&#34;
            static let Year = &#34;year&#34;
            static let Currency = &#34;currency&#34;
            static let Value = &#34;value&#34;
            static let Grade = &#34;grade&#34;
            static let Comments = &#34;comments&#34;
            static let NumInstances = &#34;numberInstances&#34;
            static let Description = &#34;description&#34;
            static let Obverse = &#34;obverse&#34;
            static let Reverse = &#34;reverse&#34;
      }
//this represents a coin in the table view
static let GRADING_LOWER_LIMIT: NSNumber = 1
static let GRADING_UPPER_LIMIT: NSNumber = 70

//this represents the default strings returned if a field does not have the needed information
static let DEFAULT_DESCRIPTIVE_NAME: NSString = &#34;(Description?)&#34;
static let DEFAULT_COMMENTS: NSString = &#34;(Comments?)&#34;
static let DEFAULT_DENOMINATION: NSString = &#34;(Denomination?)&#34;
static let DEFAULT_MINT: NSString = &#34;(Mint?)&#34;
static let DEFAULT_COUNTRY: NSString = &#34;(Country?)&#34;
static let DEFAULT_YEAR: NSString = &#34;(Year?)&#34;
static let DEFAULT_GRADE: NSString = &#34;(Grade?)&#34;
static let DEFAULT_VALUE_AND_DENOMINATION: NSString = &#34;(Value?) (Currency?)&#34;

static let OBVERSE_IMAGE_STRING : NSString = &#34;Obverse&#34;
static let REVERSE_IMAGE_STRING : NSString = &#34;Reverse&#34;

static private let BULLET = &#34;➣ &#34;         //represents the kind of bullet to be used to build a complete summary of the coin

//declare members with setters and getters
private var country: NSString = &#34;&#34;      //what country/empire/etc. used in?
private var mint: NSString = &#34;&#34;            //where minted? EX: US Mint, St. Petersburg
private var year: NSNumber? = nil            //what year minted? per gregorian calendar
                                    //the year can be negative to represent the BCE period
                                    //positive to represent the CE periods
private var typeCurrency: NSString = &#34;&#34;   //what is the unit of value? EX: Cents, dollars, centavos, etc
private var theValue: NSNumber = 0         //how many? EX: how many dollars, cents, centavos, etc.?


//additional information about the coin
private var grade: NSNumber?            //on the american grading scale for coins. 1-70
private var comments: NSString = &#34;&#34;      //extra comments stored by the user for himself


private var numberOfInstances: NSNumber = 0 //number of coins exactly like this. EX: 1,2,3,4...etc? For each instance, it must be &gt;= 1.

//This describes the type of the coin
//EX: Walking Liberty Quarter, Barber Quarter, Standing Liberty Quarter... etc
private var descriptiveName: NSString = &#34;&#34;

private var obverseImage: UIImage? = nil
private var reverseImage: UIImage? = nil


public var valueAndDenomination: NSString
{
    get
    {
      //need to check four cases
      //case 1: we have the right values for value and denomination
      //case 2: we do not have a value but do have denomination
      //case 3: we have a value but do not have denomination
      //case 4: we do not have both
      //
      //the reason why we consider 0 to be an empty value is because a coin that was worth
      //nothing would not have been minted in the first place!!!
      if (self.theValue != 0 &amp;&amp; self.typeCurrency != &#34;&#34;)
      {
            //have value and denomination
            return &#34;\(self.theValue) \(self.typeCurrency)&#34; as NSString //like &#34;20 Cents&#34;
      }

      else if (self.theValue == 0 &amp;&amp; self.typeCurrency != &#34;&#34; )
      {
            //do not have value, but have denomination
            return &#34;(Value?) \(self.typeCurrency)&#34; as NSString
      }

      else if (self.theValue != 0 &amp;&amp; self.typeCurrency == &#34;&#34;)
      {
            //we have value, but do not have denomination
            return &#34;\(self.theValue) (Currency?)&#34; as NSString
      }

      else
      {
            //we do not have both
            return Coin.DEFAULT_VALUE_AND_DENOMINATION as NSString
      }

    }
}

public required init?(coder aDecoder: NSCoder)
{
    //we decode this object&#39;s information
    if let countryObject = aDecoder.decodeObject(forKey: Keys.Country) as? NSString
    {
      self.country = countryObject
    }

    if let mintObject = aDecoder.decodeObject(forKey: Keys.Country) as? NSString
    {
      self.mint = mintObject
    }

    if let yearObject = aDecoder.decodeObject(forKey: Keys.Year) as? NSNumber
    {
      self.year = yearObject
    }

    if let currencyObject = aDecoder.decodeObject(forKey: Keys.Currency) as? NSString
    {
      self.typeCurrency = currencyObject
    }

    if let valueObject = aDecoder.decodeObject(forKey: Keys.Value) as? NSNumber
    {
      self.theValue = valueObject
    }

    if let gradeObject = aDecoder.decodeObject(forKey: Keys.Grade) as? NSNumber
    {
      self.grade = gradeObject
    }

    if let commentObject = aDecoder.decodeObject(forKey: Keys.Comments) as? NSString
    {
      self.comments = commentObject
    }

    if let numInstancesObject = aDecoder.decodeObject(forKey: Keys.NumInstances) as? NSNumber
    {
      self.numberOfInstances = numInstancesObject
    }

    if let descriptiveNameObject = aDecoder.decodeObject(forKey: Keys.Description) as? NSString
    {
      self.descriptiveName = descriptiveNameObject
    }

    if let obverseImageObject = aDecoder.decodeObject(forKey: Keys.Obverse) as? UIImage
    {
      self.obverseImage = obverseImageObject
    }

    if let reverseImageObject = aDecoder.decodeObject(forKey: Keys.Reverse) as? UIImage
    {
      self.reverseImage = reverseImageObject
    }
}
override init()
{
    //default initializer
    super.init()

    self.country = &#34;&#34;
    self.mint = &#34;&#34;
    self.year = nil
    self.typeCurrency = &#34;&#34;
    self.theValue = 0
    self.comments = &#34;&#34;
    self.numberOfInstances = 1
    self.descriptiveName = &#34;&#34;
    self.obverseImage = nil
    self.reverseImage = nil
}

init(country: NSString,year: Int?,typeCurrency: NSString, theValue: NSNumber,mint: NSString,grade: Int?,numInstances: NSNumber = 1,description: NSString, comments: NSString)
{
    super.init()
    self.country = country
    self.mint = mint
    self.year = year! as NSNumber
    self.typeCurrency = typeCurrency
    self.theValue = theValue
    self.comments = comments
    self.numberOfInstances = numInstances
    self.descriptiveName = description

    self.obverseImage = nil
    self.reverseImage = nil
}

init(country: NSString,year: NSNumber?,typeCurrency: NSString, theValue: NSNumber,mint: NSString,grade: NSNumber?,numInstances: NSNumber = 1,description: NSString, comments: NSString,obverseImage: UIImage, reverseImage: UIImage)
{
    super.init()
    self.country = country
    self.mint = mint
    self.year = year
    self.typeCurrency = typeCurrency
    self.theValue = theValue
    self.comments = comments
    self.numberOfInstances = numInstances
    self.descriptiveName = description
}

public func encode(with aCoder: NSCoder)
{
    //we encode the coin&#39;s information
    aCoder.encode(self.country, forKey: Keys.Country)
    aCoder.encode(self.mint, forKey: Keys.Mint)
    aCoder.encode(self.year, forKey: Keys.Year)
    aCoder.encode(self.typeCurrency, forKey: Keys.Currency)
    aCoder.encode(self.theValue, forKey: Keys.Value)
    aCoder.encode(self.grade, forKey: Keys.Grade)
    aCoder.encode(self.comments, forKey: Keys.Comments)
    aCoder.encode(self.numberOfInstances, forKey: Keys.NumInstances)
    aCoder.encode(self.descriptiveName, forKey: Keys.Description)
    aCoder.encode(self.obverseImage, forKey: Keys.Obverse)
    aCoder.encode(self.reverseImage, forKey: Keys.Reverse)
}



//setter and getter functions for class members...


func getCompleteSummary() -&gt; NSString
{
    //returns a bulleted list that represents the coin
    //and it describes every single detail...
}

func getIncompleteSummary() -&gt; String
{
      //returns a bulleted list string that represents the coin
      //and it describes every single detail...   
}

/////////////////////////////////////////////////////////////////////////////////

func ofSameType(rhs: Coin) -&gt; Bool
{
    return (self.getCountry().lowercased == rhs.getCountry().lowercased) &amp;&amp; (self.getValue() == rhs.getValue()) &amp;&amp; (self.getDenomination().lowercased == rhs.getDenomination().lowercased)
}

public static func==(lhs: Coin, rhs: Coin) -&gt; Bool
{
    //we compare two coin objects for equality in ALL Categories
    returnlhs.country.lowercased == rhs.country.lowercased &amp;&amp;
            lhs.theValue == rhs.theValue &amp;&amp;
            lhs.typeCurrency.lowercased == rhs.typeCurrency.lowercased &amp;&amp;
            lhs.mint.lowercased == rhs.mint.lowercased &amp;&amp;
            lhs.year == rhs.year &amp;&amp;
            lhs.grade == rhs.grade &amp;&amp;
            lhs.comments == rhs.comments &amp;&amp;
            lhs.numberOfInstances == rhs.numberOfInstances &amp;&amp;
            lhs.descriptiveName == rhs.descriptiveName &amp;&amp;
            lhs.obverseImage == rhs.obverseImage &amp;&amp;
            lhs.reverseImage == rhs.reverseImage
}

func assign(right: Coin)
{
    //we implement this instead of overloading the assignment &#34;=&#34; operator
    //as it is not possible to overload the &#34;=&#34; operator
    //we assign the right-hand-coin&#39;s field values
    //to the left-hand coin&#39;s side
    self.country = right.country
    self.theValue = right.theValue
    self.typeCurrency = right.typeCurrency
    self.mint = right.mint
    self.year = right.year
    self.grade = right.grade
    self.comments = right.comments
    self.numberOfInstances = right.numberOfInstances
    self.descriptiveName = right.descriptiveName
    self.obverseImage = right.obverseImage
    self.reverseImage = right.reverseImage
}

    }
</code></pre></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>看起来问题是您的 <code>CoinCategory</code> 类没有实现 <code>compare:</code> 方法:</p>

<blockquote>
<p>: unrecognized selector sent to instance 0x608000236cc0</p>
</blockquote>

<p>我的猜测是 FRC 试图将第二个 <code>CoinCategoryMO</code> 的 <code>coinCategory</code> 属性与第一个 <code> 的 <code>coinCategory</code> 属性进行比较>CoinCategoryMO</code> 以便以正确的顺序获取它们(因为您的 FRC 使用 <code>coinCategory</code> 属性进行排序)。</p>

<p>所以直接的答案是您需要为您的 <code>CoinCategory</code> 类实现一个 <code>compare:</code> 方法。但我认为这只是你需要改变方法的一个指标。而不是拥有一个具有自定义对象(或其集合)属性的实体,您可能应该致力于拥有多个实体(例如,一个 <code>CoinMO</code> 实体,一个 <code>CoinCategoryMO</code> 实体, <code>CoinCategoryTypeMO</code> 实体等),它们之间具有一对多的关系。如果您显示自定义对象的代码(<code>Coin</code> 和 <code>CoinCategory</code>),则更容易建议如何在 CoreData 中对它们进行最佳建模。</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 核心数据变更处理错误,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/44762356/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/44762356/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 核心数据变更处理错误