Create Reference List Pointing to Multiple CKRecords in CloudKit - cloudkit

Swift 3.1, Xcode 8.3.3
I have a record type in CloudKit called Aircraft and it has a field called fieldValues that is of type Reference List.
In my code, I have an aircraft CKRecord and several fieldValue CKRecords that are children of the aircraft.
How do I put all those fieldValue records into the aircraft's reference list?
Creating a CKReference appears to only allow a single record in it:
let reference = CKReference(record: fieldValueRecord, action: .deleteSelf)
But I'm trying to connect many fieldValues to a single aircraft. Any ideas?

Swift 3.1, Xcode 8.3.3
After some trial and error, I finally figured it out. It goes something like this:
//Parent record (Aircraft)
let recordAircraft = CKRecord(recordType: "Aircraft", recordID: ...)
//Add child references (FieldValue). As far as I know, the child records must have already been created and sent to CloudKit
var fieldValueReferences = [CKReference]()
for fieldValue in fieldValues{
let ref = CKReference(record: fieldValue, action: .deleteSelf)
fieldValueReferences.append(ref)
}
//Assign the array of references to the key that represents your Reference List field
recordAircraft["fieldValues"] = fieldValueReferences as CKRecordValue
I hope that helps someone else.

Related

Realm updates are not saving

So I'm trying to update a List property of an Object class in Realm. The property of the Object updates, but for some reason when it gets to the Realm, the update never occurs. In other words, I've confirmed that the changes have been made to the actual object just after I made the changes(the List updates in the object), but after I add to the realm, and then get the object back from the realm, it's as if nothing ever changed. Here is the code:
do{
try! realm.write{
let course = realm.objects(Course.self).filter("id =='\(courseID!)'").first
course!.days = List<String>()
for day in daysSelected{
course?.days.append(day)
}
realm.add(course!, update: .modified)
}
}catch{
print(error)
}
Also, you should know that when I update other properties like Strings, the changes go through just fine. Am I doing something wrong with lists? In my object class, the list is declared as:
var days: List<String> = List<String>()
According to the documentation:
Properties of List type defined on Object subclasses must be declared
as let and cannot be dynamic.
Rather than defining your list as:
var days: List<String> = List<String>()
Define it as:
let days = List<String>()

Set reference value in swift for CloudKit database

I'm trying to set some value for a record in my CloudKit database. I haven't problem to set any other kind of value on other fields like string or int but for Reference filedname(storyid) i get this error :
"invalid attempt to set value type STRING for field 'storyid' for type
'Storypage', defined to be: REFERENCE"
func saveToCloud(note: String)
{
let newpage = CKRecord (recordType: "Storypage")
newpage.setValue(note, forKey: "pagecontent")
newpage.setValue("UTENTE1", forKey:"username" )
newpage.setValue("84EC8E60-1467-6411-5CDC-7E85DDB51C89", forKey: "storyid")
database.save(newpage) { (record, error) in
guard record != nil else {return}
}
A reference field stores a CKReference object, not a String:
Linking to Another Record
To link records together and create a strong
relationship between them, create a new CKReference object, initialize
it with the owner record, and assign that reference object to a field
of the owned record. When you design the relationships among your own
records, make the owner the more important of two related records.
So you'll want to get the recordID of the record you're relating newpage to, then use that to create a reference object, which you can then use to set the storyid field.

Getting an array from Firebase Database

I've a [String] Array under the "urls" key. How can i get it out? Here is my structure:
You can read it by using an observer to the urls reference and initializing an array with its value.
ref = Database.database().reference()
ref.child("sectionList").child("name of").child("urls")observe(.value, with: { (snapshot:FIRDataSnapshot) in
var urls : [String] = snapshot.children
}
"This function takes two parameters: an instance of FIRDataEventType and a closure.
The event type specifies what event you want to listen for. The code listens for a .value event type, which in turn listens for all types of changes to the data in your Firebase database—add, removed, and changed.
When the change occurs, the database updates the app with the most recent data.
The app is notified of the change via the closure, which is passed an instance of FIRDataSnapshot. The snapshot, as its name suggests, represents the data at that specific moment in time. To access the data in the snapshot, you use the value property."
Source:(https://www.raywenderlich.com/139322/firebase-tutorial-getting-started-2)
I got it like this
let ref = Database.database().reference(withPath: "sectionList")
ref.child("name of").child("urls").observeSingleEvent(of: .value, with: { (dataSnapshot:DataSnapshot) in
for object in dataSnapshot.children.allObjects as! [DataSnapshot] {
for obj in object.value as! NSArray {
print("value = \(obj)")
}
}
})
Basicly, I highly recomend you to take a look at this tutorial, especially the part about retrieving Data. To devide your project in standard MVC model will be very useful. I hope my answer will help you ;)

Making a counter app - Do I have to do something after saving to Core Data?

Trying my hand in Swift and creating my first "app". I'm essentially creating a cookie-clicker clone where you just click an image in the center of your screen repeatedly to increment your score.
I'm experiencing some issues where clicking the image once will increment my score by 1, but upon clicking it again, the score stays 1.
I'm almost positive I'm supposed to do something after saving to CoreData - I just don't know what. Do I have to refresh the View? Sorry for the newbie question
#IBAction func tapHomeImage(sender: AnyObject) {
//Score is the name of my Entity, with "points" being an attribute
let entity = NSEntityDescription.entityForName("Score", inManagedObjectContext: managedObjectContext!)
let score = Score(entity: entity!, insertIntoManagedObjectContext: managedObjectContext!)
// **As an aside question, is there a more efficient way to code the below? The issue I have is that score.points is of type NSNumber
let intScore = score.points as Int
let incrementedIntScore = intScore + 1
score.points = NSNumber(integer: incrementedIntScore)
var error: NSError?
managedObjectContext?.save(&error)
//homeScoreLabel is an IBOutlet for the Score displayed on the page
homeScoreLabel?.text = "\(score.points)"
}
Thank you very much!
You don't need to do anything after saving, you need to do something before calling this method. You need to find an instance of Score that already exists, and use that.
When you get to this line:
let score = Score(entity: entity!, insertIntoManagedObjectContext: managedObjectContext!)
You create a new instance of the Score entity, every time this method runs. So when you do this:
let intScore = score.points as Int
let incrementedIntScore = intScore + 1
score.points = NSNumber(integer: incrementedIntScore)
You're working with a brand new instance every time. The score is initially zero, and you always increase it to 1.
What you should do:
Use a single instance of Score and save that as a property of your view controller. That is, have something like this:
var score: Score?
Assign a value to this property once, when the view controller loads. Since you're saving data, you should use executeFetchRequest to look up a previously-saved instance. If no previous instance exists, then create a new one via insertIntoManagedObjectContext.
Use that instance in this IBAction.
There are other ways to fix the code. The key is to make sure that you use the same instance of Score every time instead of creating a new one at every tap.

How to add two items at a specific index in an entity in CoreData in Swift

I am moving rows inside a collectionView, I have no sorting on the data so all new cells are inserted at the end of the table, but when I move a cell I want to specifically select the index where it should be moved inside the entity in core data, this way the collectionView will automatically display the moved cell at the updated row without any additional work, is that possible without creating an additional ID attribute?
The entity is named List and it has two attributes, task_name and task_bool.
var myData:[NSManagedObject] = []
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let newItem: AnyObject = NSEntityDescription.insertNewObjectForEntityForName("List",
inManagedObjectContext:
managedContext)
var deleltedRow = myArray[indexPath.row].valueForKey("task_name") as! String
myData.removeAtIndex(indexPath.row)
newItem.setValue(deleltedRow, forKey: "task_name"); // how would I add atIndex: here??
newItem.setValue(true, forKey: "task_bool"); // how would I add atIndex: here??
Core data maintains an unordered collection of objects. If you want to display those objects in a specific order then you need to sort them, either while fetching or afterwards. That means that the objects need to have some information inside them on which you can sort. You don't have anything currently so you'd need to add an order type attribute and maintain it with appropriate values.
Core Data does not store objects in an ordered manner. If you want to display these objects in a specific order, you will need a property/attribute in your entity which lets you order the list the way you want.
It might be a good idea to add a order attribute to the entity and use that for the ordering.