I'm working on a project that uses Realm for the database (that will come into the picture later). I've just discovered key-value coding and I want to use it in converting a TSV table into object properties (using the column headers from the table as the keys). Right now it looks like this:
let mirror = Mirror(reflecting: newSong)
for property in mirror.children {
if let index = headers.index(of: property.label!) {
newSong.setValue(headers[index], forKey: property.label!)
} else {
propertiesWithoutHeaders.append(property.label!)
}
}
Is there a way to iterate over properties without a mirror? I really could have sworn that I read in the Realm documentation (or maybe even in Apple's KVC documentation) that you can do something like for property in Song.properties or for property in Song.self.properties to achieve the same thing.
Besides it being a little more efficient, the main reason I want to do this is because in the same place I think I read this, I think they said that the iterating (or the KVC?) only works with Strings, Ints, Bools and Dates, so it would automatically skip the properties that are Objects (since you can't set them with in the same way). The above code is actually a simplification of my code, in the actual version I'm currently skipping over the Objects like this:
let propertiesToSkip = ["title", "artist", "genre"]
for property in mirror.children where !propertiesToSkip.contains(property.label!) {
...
Did I imagine this .properties thing? Or, is there a way to iterate in this way, automatically skipping over Objects/Classes without having to name them as I do above?
Thanks :)
No you didn't imagine it. :)
Realm exposes the schema encompassing the properties of each type of model in a database in two places: in the parent Realm instance, or in an Object itself.
In the Realm instance:
// Get an instance of the Realm object
let realm = try! Realm()
// Get the object schema for just the Mirror class. This contains the property names
let mirrorSchema = realm.schema["Mirror"]
// Iterate through each property and print its name
for property in mirrorSchema.properties {
print(property.name)
}
Realm Object instances expose the schema for that object via the Object.objectSchema property.
Check out the schema property of Realm in the Realm Swift Documentation for more information on what kind of data you can get out of the schema properties. :)
Related
Context
I am working on a feature, that allows users to add Components to CoreData. Those Components are obviously NSManagedObjects inserted and saved into a Context.
In addition, I also want to give the user a variety of predefined Components. However, I do not like the idea of populating those predefined ones into CoreData at the first App Launch, since this is really prone to bugs, especially when utilising CloudKit. So my idea was to generate a List of predefined NSManagedObjects without inserting them into a Context, which would make them temporarily, but they could be used in the same way as the real ones. However, as far as I understand, creating NSManagedObjects without a Context isn't really working.
Code
let predefinedComponents: [Component] {
var components: [Component] = []
for name in names {
let component = Component() // This was my idea of creating a temporary NSManagedObject without inserting it into a Context.
component.name = name
components.append(component)
}
return components
}
struct ComponentsView: View {
#FetchRequest(sortDescriptors: [SortDescriptor(\.name)]) private var components: FetchedResults<Component>
var body: some View {
ForEach(allComponents) { component in
ComponentRow(component: component)
}
}
private var allComponents: [Component] {
var allComponents: [Component] = predefinedComponents
for component in components {
allComponents.append(component)
}
return allComponents
}
}
struct ComponentRow: View {
#ObservedObject var component: Component
var body: some View {
Text(component.name)
}
}
Question
How can I achieve my goal described above while being able to work with predefined Components without having to populate them into CoreData at the first AppLaunch?
The easiest and most elegant way is to create a "throwaway scratchpad" context just for the pre-defined Components.
This scratchpad context will be a child of the viewContext, or any background context depending on your use case.
This is how you create the scratchpad:
let scratchpadContext = NSManagedObjectContext(.mainQueue)
scratchpadContext.parent = dataProvider.container.viewContext
The example above creates a context for the main queue, which I assume is your case based on your question. But if you need to access it from a background thread, you initialise it with .privateQueue.
So, as long as you don't save the scratchpadContext, your temporary pre-defined Components will never be saved on your Persistent store. And when it's de-initialised, any NSManagedObject that you've created with it will be thrown away.
You can create "free floating" managed objects that don't belong to a context but you need to provide the entity description to do it-- so you would use Component(entity:insertInto:). The first argument is the NSEntityDescription for Component. The second one is a context, but it's an optional, so you can make it nil. If you wanted to add it to a context later, use NSManagedObjectContext.insert().
It might be better to use an in-memory persistent store instead of a SQLite store. Then you would have a context that only existed while the app was running but did not save to a file. You can set one of those up with NSPersistentContainer if you change the persistent store description.
I can't tell from your question which of these would be better for you.
This is more of a generalized question as I have yet to write the code for the question I am asking. Before I get started writing the code I wanted to make sure I am on the right track and possibly getting suggestions for better ways to do what I want to do. Basically right now I have a core data model setup in a way that I think is correct for what I am trying to do and just need some guidance on a very specific part of the code but want to make sure overall I created it correctly.
The first part to the question is more of a clarification on how relationships work in core data. Right now I have 5 entities and to make sure I have the correct idea on how it works I will use a few examples to make sure I am on the right track.
So lets save I have an entity I called name. Within that Name entity that contains only a name attribute. Next I have an entity that has classes, that each have a boolean of true or false to determine which class it is. These 2 are related in a inverse relationship of Name entity having a to one relationship and the Classes having a to many relationship because multiple names can have multiple classes but each name can only have 1 class. If I am right on this one that means I full understand core data relationships!
Now the second part of the question is related to the booleans in the class. I have the Class entity which is like I said a boolean containing a true false set as default to false. When the user selects one of the class buttons before presenting the popover where they actually give the name of the class selected it saves the boolean to true then passes that data over to the popover Name view controller. I am very unsure as to how to do this as it isn't a widely asked question on here nor have I been able to find any info through researching. I am one of those people who needs to actually learn by clear examples....any help with this would be appreciated! Sorry I don't have any example code for this.
The first part seems correct. The ManagedObject of your Class CoreDataObject should have an NSSet property which will contain the names (as the Class can have multiple names)
For the second part, Core Data uses objects. When you 'get' the data from Core Data it will be a (probably extended) NSManagedObject (named Class in our case). You can send this object as a parameter just as you would do with any other object and use it as you would use any other object :-). For example looping over de NSSet Names
func iterateOverNames(someClass: Class) {
for name: Name in someClass.names {
// do stuff
}
}
You can check these links for more information:
https://realm.io/news/jesse-squires-core-data-swift/
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/index.html
I'm using a web service which returns results like the following example:
{
"name":"Frank",
"meals":[
"cheeseburger",
"lasagne"
]
}
My Core Data schema looks like this:
Using MagicalRecord's MR_importValuesForKeysWithObject method, how would I set about mapping the meals key to the related Meals.name attribute?
I can map the meals manually after, using a for in loop, but just wondered if there was a way MR_importValuesForKeysWithObject would perform this for me?
Basically I want each object in the JSON "meals" array to become a new Meals entity.
Override importMeals: on the Person object and do the lookup/create/associate manually.
(longer answer)
every property imported via MagicalRecord calls import(PropertyName) on the target object, by implementing it you can override functionality.
I am using this code to map a list of DTO's to their EF counterparts. I'd like to eliminate the loop, not to mention the fetch. The latter I can do by caching all Employee objects in a dictionary, but I'm stuck on the loop.
var gridEmps = (List<EmployeeDescriptor>) employeeDescriptorBindingSource.DataSource;
Mapper.CreateMap<EmployeeDescriptor, Employee>();
foreach (var newEmp in gridEmps)
{
var oldEmp = context.Employees.Single(emp => emp.Id == newEmp.Id);
Mapper.Map(newEmp,oldEmp);
}
As used above, AutoMapper maps from my DTO to an already instantiated entity object, but if I were to try this using two lists, like so,
var gridEmps = (List<EmployeeDescriptor>) employeeDescriptorBindingSource.DataSource;
var dbEmps = context.Employees.ToList();
Mapper.CreateMap<EmployeeDescriptor, Employee>();
Mapper.Map(gridEmps, dbEmps);
how will AutoMapper know how to link the correct objects from one list to the other, based on their key property? I know the key property is also mapped, but surely this will mess with the EF change tracking?
How can I tell AutoMapper to link source and destination objects by their key properties?
I have not found how to tell auto mapper collection merging rules without loops. My solution is following:
Create TypeConvertor: List<EmployeeDescriptor> -> List<Employee>
Mapper
.CreateMap<List<EmployeeDescriptor>, List<Employee>>()
.ConvertUsing(new EmployeeListConverter());
Put your loops inside Convert method of the EmployeeListConverter
Use Mapper.Map(gridEmps, dbEmps);
I want a Dictionary<string, string> property which should not be changed/set by the outside code. To achieve this, I can declare private variable and it's property with get accessor only.
e.g.
private static Dictionary<string, string> myDic = new Dictionary <string, string>();
Public static Dictionary<string, string> MyDictionary
{
get { return myDic;}
}
But in this case, outside code can manipulate 'contents' of the dictionary.
e.g. MYClass.MyDictionary["FirstSampleKey"] = "Replacing original value by New Value";
I dont want any outside code to manipulate contents of the dictionary. How can I achieve this?
I don't believe there is a read only dictionary (which would be nice as there is a ReadOnlyCollection). Your best bet would probably be to not expose the dictionary at all and expose properties/methods that allow the developer to get at the information without allowing them to directly access the dictionary.
If this is something you will be doing a lot of, you can look into either using someone else's ReadOnlyDictionary implementation (there are plenty out there if you Google it), or you can write your own.
I would also say that you could write a method for the developers to look up their words, or else you could return a copy of the dictionary, this way the dictionary works as it do now, but of cause you would have to copy the dictionary every time the get method is called which could take some time if it's a large dictionary.