In my app, I have a Record type (UserActivity) which just stores images a user wants to save to their profile. This record type only contains a single attribute - a CKReference to another record type (RecordTypeA for example). It works perfectly...I'm able to store and retrieve the data via the references to construct the images and display it appropriately on screen. However, I just realized I need to add a second attribute to the UserActivity record type, which will be a CKReference to a different record type (call it RecordTypeB). Record type B is a second kind of image that needs to be separately identified. So each row in UserActivity will now have 1 of 2 possible CKReferences, but not both.
I can save the new RecordTypeB reference with no problem, but I have a couple of issues as a result. First, when I save it, whether through code or CKDashboard, the record now shows the title as "No Name" because there is nothing for the attribute for RecordTypeA. Originally, the record names would be ref:followed-by-recordid. It works as it did originally if the UA record has a reference to RecordTypeA. So is there a way to make it create the record name for RecordTypeB reference only? Is it possible that I should change this to a CKReference List now that I have a 2nd attribute? Secondly, and more importantly, when I'm retrieving UserActivity records, how can I tell for a given record if it contains a reference to RecordTypeA or RecordTypeB? Is there a way similar to the isKindOfClass method? In this case, that method just shows it's a CKReference and not what record type it's a reference to. And maybe the second question would be automatically solved if the CKReference List is the appropriate solution? Thanks in advance for the guidance!
Experience shows that the title of the record will be the first field that you created for that recordType. I haven't found any documentation about this so it could be a coincidence. If you want your title be the RecordTypeB field, then recreate your recordType and then first create RecordTypeB. There is no other way to influence what the title will be.
You could change it to a CKReference List, but i think in your case it would be easier to keep the 2 separate fields. Only when you don't mind what item is what then you should use a list. But in your case the references are 2 different types.
If you did not write one of the fields, then when you read the record and look at the reference, then it should be nil. You can't ask the recordType of a CKReference. But if you create a field for a reference, then you know what recordType it should be. Otherwise you need to create an extra field for indicating what recordType it is.
Related
Overview:
I have an iOS app that uses CoreData
There is an entity called Animal
It has a set of records Lion, Tiger and Elephant
I would like to mark only one of the records as favourite.
Similar entities with the same approach:
Similarly I could have other entities such as Car, Bike.
Each entity would have a set of records.
Again each entity should only have one favourite record
Reason:
App has an option to create a new document
When the new document is created, it would be populated with default values for each entity (by selecting the favourite record of each entity)
Note: Only one record can be marked as favourite at a given time
Possible models I thought of:
1. Field called isFavourite
Create a field in Animal called isFavourite.
Mark only one of the rows as isFavourite as true.
Much of the logic to maintain isFavourite is managed in code.
2. Separate entity called Favourite
Create a separate table called Favourite and have a dummy row in it.
Establish a relationship from Favourite to Animal called animal.
This will point to the favourite record.
Questions:
What is the preferred approach to tackle this problem ?
Are there any other alternatives ?
Go with option 2, maybe call it Config. If you want to ensure it is just a singleton add a attribute that is unique and can only be zero.
You can write a helper computed var returning true if the reverse relationship is non-nil.
Main advantage of option 2 is the simplicity of changing the favourite, you don't have to scan through all the items to to set them non-favourite just change it on the singleton config.
Give some thought to other parts of the app and to what you might want to do in the future.
Adding a field: Works OK but requires some code to maintain, which might be error prone. On the other hand maybe one day the app might allow multiple favorites, and this will just work with that.
Using a separate entity: Also works OK but adds a whole new entity where you'll only have a single instance. In general, if you have an entity where you only ever want one instance, you're doing it wrong. On the other hand this also works well with the potential for multiple favorites.
A third approach is to save the objectID for the favorite animal somewhere outside of Core Data, like UserDefaults. Save it, and then find the favorite by using NSManagedObjectContext's existingObject(with:) method. You can't save the NSManagedObjectID directly but you can get its uriRepresentation() and save that.
I'd probably go with #1 in most cases but it depends what else I need in the app.
I'm having an issue with the fields (or attributes, they used to be called) in my cloud kit database. Whenever I create a new field, the records that are stored in that field are always titled "No Name" according to the record type ("State") despite what the actual record title which is "happy" as shown here:
I already tried editing and saving the record it again but that did not work. Can anybody help clarify this issue?
When looking at actual records in the public database in the CloudKit Dashboard, it looks at the field names for that that record type (the "State" record type in your case) and tries to pick the one most likely acting as a title. If the field it chooses has an empty value, it shows "No Name" for the title.
Looking at your screenshot, it seems to be picking the first field ("WI") and showing it's value, which is not set for the selected record.
On a separate note, it seems odd that you have what look like state abbreviations as field names for your State record type. It's possible that you want an "abbreviation" field on your State record type, where the value might be "WI" or "CA".
I have two tables which has "photo URL" columns, that contain same image URL. So when I change value in one table, I would like the value in another to update automatically. So how can I set this relationship in Backendless? Like foreign key in SQL.
EDIT:
I have included Users table as property of ActionCreation table. Users have property for URL of logo for the user. In ActionCreation table I need to have exactly the same photo URL. When I included Users as property of ActionCreation, there is no custom properties are loaded form Users object. But I need access photo URL in my app. What the best way to do it?
Thank you.
Is there a relationship between the tables?
How does the same value get into two tables? Do you write it there twice?
Mark
This is a simplified version of my scenario, but that's OK.
Let's say you have three CoreData entities, each with a corresponding subclass of NSManagedObject, and 1-to-1 relationships as follows:
Person -> ContactRecord -> PhoneNumber
The Person entity has a vcard attribute, which holds the vCard data for that person in a string.
The PhoneNumber entity has two attributes: the actual number, and the type of phone number (cell, home, work, etc).
Right now, in the Person willSave method, I'm updating the vcard property. This works fine, if another property on the Person object has changed. But, if I change the type or number on the PhoneNumber object, or any properties on the ContactRecord, the willSave method isn't called on the Person object.
Is there a good way to update the Person object when a property changes over on the PhoneNumber object?
Right now, the best option I see is using NSManagedObjectContextWillSaveNotification. The method called by that notification could sift through the changed objects and work back up the inverse relationships to call some method on the Person object, but this happens after the NSManagedObjectContext has already saved, so it would require another save after that. My hope was to set this property to the correct value before the save happens.
The NSManagedObjectContextWillSaveNotification method is called just before the save occurs, so you could make the change there and it should not need a second save.
My preference in a situation like this would be to not store the vcard at all, but make it a dependent property that is readonly. I assume you don't need to access the vcard very often, so generating the data on-the-fly in the getter method should work OK, and the data will always be up-to-date.
One problem with updating the data just before a save is that you have to make sure you save. If you try to get the vcard without saving, it will be out-of-date. The dependent read-only property won't have that issue.
A straight-forward way is to continue to use the -willSave: method in the children. When the -willSave: fires on ContactRecord then ping the parent and ask it to recalculate the vcard. You can do the same thing for PhoneNumber. Just work back up the relationships.
This is assuming your relationships are bi-directional which, while flagged as a warning, really is a requirement with Core Data.
I'm new to Core Data and I got stuck at this part of my xCode project.
I have created a core data entity "Person" and this entity has the following attributes:
name;
age;
birthday;
address;
and this attributes are getting displayed in a tableview. So far so good.
My problem is that I want the table to have an "Add Field" or "Add Row" cell so when the user wants to add more information in addition to these already created attributes he just clicks the cell and chooses the field name and type.
For example if he wants the person's "phone number" in the detail view of the table he names the new field "phone number" and chooses its type "number". Then he has an extra field where he can add the person's phone number.
How can I do this in core data? Is there a way for a user to manually add a new attribute to an entity and choosing its format? What is the best approach? Thanks.
You can't do exactly what you want with Core Data. Core Data can't change structure except if you make a new version of your design, but you do that in xcode.
But you can easily add another table called f.ex. information, which links to the person single connection and has the person linking back many to the information table.
This way, you can add as many fields and values as you want, of course all the extra fields you add would follow the same person, so if you want to use cellPhone field, you must add that to all.
I would recommend that you use direct SQL, and don't use Core Data. Core Data is not a database, it is an object store, and when you get better at iOS development, you will understand the difference, it is much bigger than you might think at first.
There is an excellent high level library for SQLite, called FMDB, you can find it on github here : https://github.com/ccgus/fmdb
Here you can do direct SQL queries like "Alter Table" and more on the fly, though what you are after isn't very simple, it could be real fun project to do.
Good luck with this.
I don't think this is directly possible in Core Data because its purpose is object persistence and you can't add new properties to objects dynamically. It could be faked to some degree using a to-many relationship to an "extra property" entity that had name, value (as string), and data type fields.
I believe your best option would be using SQLite in order to modify the table structure on the fly. (http://www.sqlite.org/lang_altertable.html)
My last company did something like this, but its not trivial. I don't have access to the code so this is more or less going to be from memory.
you provide transformable property in your entity (which will be a dictionary)
the model object has to provide the getter and setter for this that in turn drive the primitive methods to set/get an attribute
you provide a getter/setter along the lines of -objectForKey and -setObject forKey, which read and write values
when you are told to 'fault', you update the dictionary in the entity
In summary, maintain a dictionary of key value pairs. Perhaps you maintain a shadow dictionary that gets initialized and updated as needed. Its been around 4 years since I last saw this code so a little fuzzy on it. But you should get the idea. It was like magic - you can arbitrarily set any key/value pair (assuming string keys and NSCoding compliant values), and can always ask for the keys by asking the dictionary for its current set of keys.