FREE TRIAL: Accelerate your app development career with Hacking with Swift+! >>

CoreData woes

Forums > macOS

I have been trying to figure out CoreData. Swift for that matter! LOL!

Anyway, I am starting small to try and understand it.

So, here's my simple app "CoreDataTest"

I have two entities in my CoreDat Model. Test1, and Test2. Test1 has two attributes, name1 as type String and array1 as type Transformable. Test2 has name1 as type String and dictionary1 as type Transformable. CodeGen is set to Manual/None, and I created the class and extension files as shown in a tutorial via Edit > Create NSManagedObject Subclass.

I have a DataHelper class that holds all my methods.

The issue I am having is that in my fetchRequest method for either entity, I am having to Type the holding property to be either Test1, or Test2, respectively. However, when the fetchRequest occurs on Test1, I get a failure with no error codes. The fetchRequest for the dictionary is returning what appears to be a string representation of the dictionary data.

I want to store an Array & Dictionary, and I want to retrieve an Array & Dictionary.

I have created a github repository of the project at https://github.com/tcarroll2/CoreDataTest

I appreciate any help.

Tom

   

So I've been working through more of the tutorial I was following, and it appears that plain arrays are the issue. Is there a special way I need to fetch an Array from the store?

   

There are some ways how to store array in an entity but it looks like a not elegant design. Traditionally in Core Data if you want to have a array of items you would create separate entity and use relationship to connect them. Then one entity would have set of these related entities.

If you really want to dive deep into Core Data and dont mind paying then I can highly recommend the book Core Data by objc.io. It is great and I still regret not reading it sooner.

   

Well crap. Scratch that. I added an array to the entity that is working, and it's returning the data just fine. I'll have to go back and take another refined look at the non-working entity to see if I can discover why its not working...

   

hi,

i would not give up on the array of Int; that's transformable and should work well. especially if the amount of data is small, the order is important, and you'll not be doing a Core Data fetch based on any of the values. it's a lot cleaner than putting lots of Entities into Core Data whose only attribute is an Int (along with the relationship needed to track it), and handling the NSOrderedSet relationship implementation to track them.

i think your problem is the Dictionary of type [String:Int]. that could be implemented in Core Data as an Entity which has Int and String attributes. you could look through those entities for the one whose String value is what you want and return the associated Int attribute.

hope that helps,

DMG

   

@delawaremathguy I've steered clear of the struct / entity thing just because I don't understand how to search the store for a particular item within an entity using the struct. It seems logical that I would have something like name: String, value: NSNumber in an entity/struct of Record.

I just don't how I would search the store to find "foo" with a value of 72839472102.

I'm sure I'll get there. I've been learning a lot lately and when I come back to that part of my app I may have learned enough to figure it out.

   

hi Tom,

i'm not sure why i did not respond to this earlier ... apologies.

other than writing your own transformable implementation for a Dictionary of type [String:Int] -- which might be the right solution -- a possible solution just using what Core Data offers you:

  • create a new Entity in Core Data, e.g. NameValuePair, whose attributes are name (of type String) and value (of type Int64).

  • establish a relationship in the Core Data model from your Test2 entity to the NameValuePair entity, perhaps labeled nameValuePairs <-- to many -->> test2Object, where test2Object is the name of the reciprocal relationship attribute in NameValuePair.

  • if a Test2 object test2Object needs to lookup the value for a name "Fred" -- e.g., if you need test2Object.dictionary1["Fred"] in normal dictionary syntax -- you can look through all the NameValuePairs associated with the test2Object for the one where the name is "Fred" and return the value, or return nil if no such value exists. like this, calling test2Object.valueForName(name: "Fred") where valueForName is a method on the Test2 class:

func valueForName(name: String) -> Int? {
  guard let nvpairs = nameValuePairs as? Set<NameValuePair>  else {
    return nil
  }
  if let nvPair = nameValuePairs.filter({ $0.name == name }).first {
    return Int(nvPair.value)
  }
  return nil
}
  • but you need to ensure uniqueness in storing values in the mock-dictionary. the corresponding method on the Test2 class, would look like this:
func setValueForName(name: String, newValue: Int) {
  guard let nvpairs = nameValuePairs as? Set<NameValuePair>  else {
    return 
  }
  if let nvPair = nameValuePairs.filter({ $0.name == name }).first {
    nvPair = Int64(newValue)
  } else {
    let nvPair = NameValuePair(context: managedObjectContext) // this test2Object knows its own moc
    nvPair.name = name
    nvPair.value = Int64(newValue)
    addToNameValuePairs(nvPair) // this method is generated for you by XCode
  }
  try? managedObjectContext.save() // or call back to the AppDelegate to save
}

finally (hoping that i don't have to come back to do any serious editing on what i wrote above -- it's a little bit from memory), you asked about searching for "foo" with a value of 72839472102. i'm not sure why you would do this in traditional dictionary usage. usually, if you had a test2Object in front of you, you'd ask the object for the value of "foo" in its dictionary.

but you could do this with a generic fetch request in Core Data to find all NameValuePairs where the name is "foo" and the value is "72839472102". however, there could be several different test2Objects that have such an associated name and value pair.

whew!

ADDED AS AN AFTERTHOUGHT: how about storing your dictionary as simple Data? both String and Int are Codable, so your dictionary would be Codable. you could write it as data with a JSONEncoder and bring it back with a JSONDecoder. you'd use two functions very similar to those above to access and update the data.

hope that helps,

DMG

   

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Get started

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.