JSON to Core Data and back. Swift Core Data Sync.

Overview

Notice: Sync was supported from it's creation back in 2014 until March 2021

Moving forward I won't be able to support this project since I'm no longer active in making iOS apps with Core Data. I'm leaving this repository as a historical reference of what happened during this time. Sync had in total 130 releases with almost 30 contributors. If you still support this project I encourage you to fork it and continue the development. I don't feel comfortable with passing this project to another developer due to the fact that I want to have some involvement in all the projects that live under my account. 7 years was a good run, thank you everyone for using this project and thank you to everyone that has contributed to it. Best of luck in your careers and in what this constantly evolving tech world has for all of us.

Initial releases: https://github.com/3lvis/Sync/releases?after=0.4.1


Sync

Sync eases your everyday job of parsing a JSON response and syncing it with Core Data. Sync is a lightweight Swift library that uses a convention-over-configuration paradigm to facilitate your workflow.

Syncing JSON to Core Data is a repetitive tasks that often demands adding a lot of boilerplate code. Mapping attributes, mapping relationships, diffing for inserts, removals and updates are often tasks that don't change between apps. Taking this in account we took the challenge to abstract this into a library. Sync uses the knowledge of your Core Data model to infer all the mapping between your JSON and Core Data, once you use it, it feels so obvious that you'll wonder why you weren't doing this before.

  • Automatic mapping of camelCase or snake_case JSON into Core Data
  • Thread-safe saving, we handle retrieving and storing objects in the right threads
  • Diffing of changes, updated, inserted and deleted objects (which are automatically purged for you)
  • Auto-mapping of relationships (one-to-one, one-to-many and many-to-many)
  • Smart-updates, only updates your NSManagedObjects if the server values are different from your local ones
  • Uniquing, one Core Data entry per primary key
  • NSOperation subclass, any Sync process can be queued and cancelled at any time!

Table of Contents

Basic example

Model

Model

JSON

[
  {
    "id": 6,
    "name": "Shawn Merrill",
    "email": "[email protected]",
    "created_at": "2014-02-14T04:30:10+00:00",
    "updated_at": "2014-02-17T10:01:12+00:00",
    "notes": [
      {
        "id": 0,
        "text": "Shawn Merril's diary, episode 1",
        "created_at": "2014-03-11T19:11:00+00:00",
        "updated_at": "2014-04-18T22:01:00+00:00"
      }
    ]
  }
]

DataStack

DataStack is a wrapper on top of the Core Data boilerplate, it encapsulates dealing with NSPersistentStoreCoordinator and NSManageObjectContexts.

self.dataStack = DataStack(modelName: "DataModel")

You can find here more ways of initializing your DataStack.

Sync

dataStack.sync(json, inEntityNamed: "User") { error in
    // New objects have been inserted
    // Existing objects have been updated
    // And not found objects have been deleted
}

Alternatively, if you only want to sync users that have been created in the last 24 hours, you could do this by using a NSPredicate.

let now = NSDate()
let yesterday = now.dateByAddingTimeInterval(-24*60*60)
let predicate = NSPredicate(format:@"createdAt > %@", yesterday)

dataStack.sync(json, inEntityNamed: "User", predicate: predicate) { error in
    //..
}

Demo Project

We have a simple demo project of how to set up and use Sync to fetch data from the network and display it in a UITableView. The demo project features both Networking and Alamofire as the networking libraries.

DataStack with Storyboards

Configuring a DataStack with Storyboard is different than doing it via dependency injection here you'll find a sample project in how to achieve this setup.

https://github.com/3lvis/StoryboardDemo

Getting Started

Core Data Stack

Replace your Core Data stack with an instance of DataStack.

self.dataStack = DataStack(modelName: "Demo")

Primary key

Sync requires your entities to have a primary key, this is important for diffing, otherwise Sync doesn’t know how to differentiate between entries.

By default Sync uses id from the JSON and id (or remoteID) from Core Data as the primary key.

You can mark any attribute as primary key by adding sync.isPrimaryKey and the value true (or YES). For example, in our Designer News project we have a Comment entity that uses body as the primary key.

Custom primary key

If you add the flag sync.isPrimaryKey to the attribute contractID then:

  • Local primary key will be: contractID
  • Remote primary key will be: contract_id

If you want to use id for the remote primary key you also have to add the flag sync.remoteKey and write id as the value.

  • Local primary key will be: articleBody
  • Remote primary key will be: id

Attribute Mapping

Your attributes should match their JSON counterparts in camelCase notation instead of snake_case. For example first_name in the JSON maps to firstName in Core Data and address in the JSON maps to address in Core Data.

There are some exception to this rule:

  • Reserved attributes should be prefixed with the entityName (type becomes userType, description becomes userDescription and so on). In the JSON they don't need to change, you can keep type and description for example. A full list of reserved attributes can be found here
  • Attributes with acronyms will be normalized (id, pdf, url, png, jpg, uri, json, xml). For example user_id will be mapped to userID and so on. You can find the entire list of supported acronyms here.

If you want to map your Core Data attribute with a JSON attribute that has different naming, you can do by adding sync.remoteKey in the user info box with the value you want to map.

Custom remote key

Attribute Types

Array/Dictionary

To map arrays or dictionaries just set attributes as Binary Data on the Core Data modeler.

screen shot 2015-04-02 at 11 10 11 pm

Retrieving mapped arrays

{
  "hobbies": [
    "football",
    "soccer",
    "code"
  ]
}
let hobbies = NSKeyedUnarchiver.unarchiveObjectWithData(managedObject.hobbies) as? [String]
// ==> "football", "soccer", "code"

Retrieving mapped dictionaries

{
  "expenses" : {
    "cake" : 12.50,
    "juice" : 0.50
  }
}
let expenses = NSKeyedUnarchiver.unarchiveObjectWithData(managedObject.expenses) as? [String: Double]
// ==> "cake" : 12.50, "juice" : 0.50

Dates

We went for supporting ISO8601 and unix timestamp out of the box because those are the most common formats when parsing dates, also we have a quite performant way to parse this strings which overcomes the performance issues of using NSDateFormatter.

let values = ["created_at" : "2014-01-01T00:00:00+00:00",
              "updated_at" : "2014-01-02",
              "published_at": "1441843200"
              "number_of_attendes": 20]

managedObject.fill(values)

let createdAt = managedObject.value(forKey: "createdAt")
// ==> "2014-01-01 00:00:00 +00:00"

let updatedAt = managedObject.value(forKey: "updatedAt")
// ==> "2014-01-02 00:00:00 +00:00"

let publishedAt = managedObject.value(forKey: "publishedAt")
// ==> "2015-09-10 00:00:00 +00:00"

Relationship mapping

Sync will map your relationships to their JSON counterparts. In the Example presented at the beginning of this document you can see a very basic example of relationship mapping.

One-to-many

Lets consider the following Core Data model.

One-to-many

This model has a one-to-many relationship between User and Note, so in other words a user has many notes. Here can also find an inverse relationship to user on the Note model. This is required for Sync to have more context on how your models are presented. Finally, in the Core Data model there is a cascade relationship between user and note, so when a user is deleted all the notes linked to that user are also removed (you can specify any delete rule).

So when Sync, looks into the following JSON, it will sync all the notes for that specific user, doing the necessary inverse relationship dance.

[
  {
    "id": 6,
    "name": "Shawn Merrill",
    "notes": [
      {
        "id": 0,
        "text": "Shawn Merril's diary, episode 1",
      }
    ]
  }
]

One-to-many Simplified

As you can see this procedures require the full JSON object to be included, but when working with APIs, sometimes you already have synced all the required items. Sync supports this too.

For example, in the one-to-many example, you have a user, that has many notes. If you already have synced all the notes then your JSON would only need the notes_ids, this can be an array of strings or integers. As a side-note only do this if you are 100% sure that all the required items (notes) have been synced, otherwise this relationships will get ignored and an error will be logged. Also if you want to remove all the notes from a user, just provide "notes_ids": null and Sync will do the clean up for you.

[
  {
    "id": 6,
    "name": "Shawn Merrill",
    "notes_ids": [0, 1, 2]
  }
]

One-to-one

A similar procedure is applied to one-to-one relationships. For example lets say you have the following model:

one-to-one

This model is simple, a user as a company. A compatible JSON would look like this:

[
  {
    "id": 6,
    "name": "Shawn Merrill",
    "company": {
      "id": 0,
      "text": "Facebook",
    }
  }
]

One-to-one Simplified

As you can see this procedures require the full JSON object to be included, but when working with APIs, sometimes you already have synced all the required items. Sync supports this too.

For example, in the one-to-one example, you have a user, that has one company. If you already have synced all the companies then your JSON would only need the company_id. As a sidenote only do this if you are 100% sure that all the required items (companies) have been synced, otherwise this relationships will get ignored and an error will be logged. Also if you want to remove the company from the user, just provide "company_id": null and Sync will do the clean up for you.

[
  {
    "id": 6,
    "name": "Shawn Merrill",
    "company_id": 0
  }
]

JSON Exporting

Sync provides an easy way to convert your NSManagedObject back into JSON. Just use the export() method.

let user = //...
user.set(value: "John" for: "firstName")
user.set(value: "Sid" for: "lastName")

let userValues = user.export()

That's it, that's all you have to do, the keys will be magically transformed into a snake_case convention.

{
  "first_name": "John",
  "last_name": "Sid"
}

Excluding

If you don't want to export certain attribute or relationship, you can prohibit exporting by adding sync.nonExportable in the user info of the excluded attribute or relationship.

non-exportable

Relationships

It supports exporting relationships too.

"first_name": "John",
"last_name": "Sid",
"notes": [
  {
    "id": 0,
    "text": "This is the text for the note A"
  },
  {
    "id": 1,
    "text": "This is the text for the note B"
  }
]

If you don't want relationships you can also ignore relationships:

let dictionary = user.export(using: .excludedRelationships)
"first_name": "John",
"last_name": "Sid"

Or get them as nested attributes, something that Ruby on Rails uses (accepts_nested_attributes_for), for example for a user that has many notes:

var exportOptions = ExportOptions()
exportOptions.relationshipType = .nested
let dictionary = user.export(using: exportOptions)
"first_name": "John",
"last_name": "Sid",
"notes_attributes": [
  {
    "0": {
      "id": 0,
      "text": "This is the text for the note A"
    },
    "1": {
      "id": 1,
      "text": "This is the text for the note B"
    }
  }
]

FAQ

Check our FAQ document.

Installation

CocoaPods

pod 'Sync', '~> 6'

Carthage

github "3lvis/Sync" ~> 6.0

Supported iOS, OS X, watchOS and tvOS Versions

  • iOS 8 or above
  • OS X 10.10 or above
  • watchOS 2.0 or above
  • tvOS 9.0 or above

Backers

Finding Sync helpful? Consider supporting further development and support by becoming a sponsor: 👉 https://github.com/sponsors/3lvis

License

Sync is available under the MIT license. See the LICENSE file for more info.

Comments
  • Rewrite: Swift

    Rewrite: Swift

    To do:

    • [x] Rewrite categories into extensions
      • [x] Rewrite Sync
      • [x] Rewrite NSManagedObject
      • [x] Rewrite NSEntityDescription
    • [x] Migration of the Demos
    • [x] Update README with Swift support
    • [x] Update README with how to get iOS 7 support
    • [ ] Fix failing test regarding custom primary key and custom mapping
    • [ ] Fix failing test regarding custom primary key
    opened by zenangst 46
  • Relationships not being synced since 1.0.10

    Relationships not being synced since 1.0.10

    I updated from 1.0.8 to the latest 1.0.11 and noticed relationships are no longer being sync'd; they show nil. I tried 1.0.10 with the same results, then 1.0.9 which works. Did something change between 1.0.9 and 1.0.10 that I'm not aware of that requires an update on my end? I checked the README and didn't see anything...

    opened by bonebox 26
  • Looks like Smart-updates not working

    Looks like Smart-updates not working

    Hello, I'm using Sync to update my managedobjects. I retrieve 1000 objects from my api and use Sync.changes to update objects. Though there are absolutely no changes since last fetch 200+ objects are being refreshed (from NSManagedObjectContextObjectsDidChangeNotificationt).

    NSFetchedResultsControllers also update the whole collectionview as number of updates is rather big.

    As a result I get collectionview.reloadData though no changes have been made.

    By the way, logging is not working the same way as in README:

        func changeNotification(notification: NSNotification) {
            NSLog("Updated: \(notification.userInfo?[NSUpdatedObjectsKey])") // =nil
            NSLog("Deleted: \(notification.userInfo?[NSDeletedObjectsKey])") // =nil
            NSLog("Inserted: \(notification.userInfo?[NSInsertedObjectsKey])") // =nil
        }
    
    userInfo    __NSDictionaryM *   2 key/value pairs   0x00007fb2b09e8460
    [0] (null)  "refreshed" : 280 objects   
    [1] (null)  "managedObjectContext" : (no summary)   
    

    I'm using swift and tvOS

    opened by f1nality 25
  • To-Many Relationship not relating.

    To-Many Relationship not relating.

    I tried syncing first a one-to many. None of the manys were "relate". I went the opposite with using the many linking to the to-one and that worked.

    Now I have a large product sync. But my to-ones are written to the database but when I use core data to drill down, the inverse relationship shows nothing.

    Don't know what is happening but that my to-many relationships aren't being created in CoreData.

    opened by jimijon 23
  • I need help getting started with your great Library

    I need help getting started with your great Library

    Hi there!

    I am sorry for bothering you but I tried to get this running for two hours right now and I seem to be stuck.

    I am using the following setup in CoreData bildschirmfoto 2015-06-22 um 23 06 48

    and I have an [NSDictionary] array (that I formed out of a json response). (I don't get to choose the json response and I get the same error using the json response instead of the array so I figured that I could go on in using the array.)

    [{
        id = 224f02078c4278c2;
        name = "Pascal Blunk";
        ownCollection = 0;
        owner =     {
            id = 32492cc981632817;
            name = "Pascal Blunk";
        };
    }, {
        id = e393ed8b0c1368fc;
        name = pascal7;
        ownCollection = 1;
        owner =     {
            id = 739b7ba364ddd874;
            name = pascal7;
        };
        users =     (
            739b7ba364ddd874
        );
    }]
    

    Every item in that array is a specific collection. The owner property is an object of type User. Users is an array of user_ids. I used to fill in the CoreData myself but now I want to switch to your powerful code. When primitively calling Sync.changes with the array given I get the following stack trace

    2015-06-22 22:54:19.615 Grocli[11780:3544854] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0x7ff821c5dcb0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key id.'
    *** First throw call stack:
    (
        0   CoreFoundation                      0x000000010dd31c65 __exceptionPreprocess + 165
        1   libobjc.A.dylib                     0x000000010d9cabb7 objc_exception_throw + 45
        2   CoreFoundation                      0x000000010dd318a9 -[NSException raise] + 9
        3   Foundation                          0x000000010d40582a -[NSObject(NSKeyValueCoding) valueForUndefinedKey:] + 226
        4   Foundation                          0x000000010d35eb23 -[NSObject(NSKeyValueCoding) valueForKey:] + 251
        5   Foundation                          0x000000010d35e914 -[NSArray(NSKeyValueCoding) valueForKey:] + 437
        6   Grocli                              0x000000010cd08bf7 -[NSManagedObject(Sync) sync_processToManyRelationship:usingDictionary:andParent:dataStack:] + 1095
        7   Grocli                              0x000000010cd083de -[NSManagedObject(Sync) sync_processRelationshipsUsingDictionary:andParent:dataStack:error:] + 606
        8   Grocli                              0x000000010cd0ac2c __78+[Sync changes:inEntityNamed:predicate:parent:inContext:dataStack:completion:]_block_invoke + 172
        9   Grocli                              0x000000010ccfdcc6 +[DATAFilter changes:inEntityNamed:localKey:remoteKey:context:predicate:inserted:updated:] + 1942
        10  Grocli                              0x000000010cd0a934 +[Sync changes:inEntityNamed:predicate:parent:inContext:dataStack:completion:] + 1748
        11  Grocli                              0x000000010cd09a99 __61+[Sync changes:inEntityNamed:predicate:dataStack:completion:]_block_invoke + 121
        12  Grocli                              0x000000010cd014ba __43-[DATAStack performInNewBackgroundContext:]_block_invoke + 58
        13  CoreData                            0x000000010cfd7a79 developerSubmittedBlockToNSManagedObjectContextPerform + 201
        14  libdispatch.dylib                   0x0000000110a7c614 _dispatch_client_callout + 8
        15  libdispatch.dylib                   0x0000000110a636a7 _dispatch_queue_drain + 2176
        16  libdispatch.dylib                   0x0000000110a62cc0 _dispatch_queue_invoke + 235
        17  libdispatch.dylib                   0x0000000110a663b9 _dispatch_root_queue_drain + 1359
        18  libdispatch.dylib                   0x0000000110a67b17 _dispatch_worker_thread3 + 111
        19  libsystem_pthread.dylib             0x0000000110de9637 _pthread_wqthread + 729
        20  libsystem_pthread.dylib             0x0000000110de740d start_wqthread + 13
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException
    

    I am not quite sure, but I would guess, that the code fails when it comes to handling the array 'users' since there is no 'id' field given. So I basically have two questions: a) Do you think that this is the problem and b) Can I somehow tell your code that it should handle all items in the users array as IDs?

    opened by Gerungofulus 23
  • Update notification not fired

    Update notification not fired

    When I receive a new json I need to do some clean up on my local data. For each deleted object I need to delete files the a user could have download, and the same is true for each update, where I need to delete the previously downloaded files and set a property that marks the update status. I'm kind of new to core data son I thought to use notification:

    func changeNotification(notification: NSNotification) {
            let updatedObjects = notification.userInfo?[NSUpdatedObjectsKey]
            let deletedObjects = notification.userInfo?[NSDeletedObjectsKey]
            let insertedObjects = notification.userInfo?[NSInsertedObjectsKey]
            let refreshedObjects = notification.userInfo?[NSRefreshedObjectsKey]
    
            print("updatedObjects: \(updatedObjects)")
            print("deletedObjects: \(deletedObjects)")
            print("insertedObjects: \(insertedObjects)")
            print("refreshedObjects: \(refreshedObjects)")
        }
    

    I don't know if there is a better place to do what I need to do. the problem is that if an entity gets its properties updated, those are reflected by Sync to core data, but the updatedObjects event is not fired, while is working on deleted and inserted.

    opened by violabg 22
  • Crashing on Exporting model having a To-Many relationship

    Crashing on Exporting model having a To-Many relationship

    I have two Core Data models, having To-Many relationship and inverse relation as well. Whenever, im trying to export the model, its getting crashed. Can u pls help me out with this? Thanks screen shot 2018-08-01 at 2 45 12 am

    opened by himanshuNetsol 21
  • How to map relationships that don't have remote IDs?

    How to map relationships that don't have remote IDs?

    Hello @3lvis,

    I consider using Sync as a replacement for RestKit in my project. While RestKit is super powerful, it is also very complicated, and outdated.

    Now to my question? How can I map nested objects that don't return an unique ID? But based on their parent object they are unique?

    Example:

    {
      "id": "578613fc037aaaa70a829",
      "firstname": "John",
      "lastname": "Doe",
      "address": {
        "street": "Main Street",
        "city": "Naples",
        "state": "FL",
      },
    }
    

    I get an user with an unique ID. I can easily map that object. But the embedded address doesn't have any exposed ID. With RestKit it was possible to map the parent's ID to this child to make it unique. Basically take user.id as remote ID.

    Is there any way to do that with Sync?

    opened by falkobuttler 18
  • Update instead of replace?

    Update instead of replace?

    Hey @3lvis !

    I have a project where I need to add multiple objects of the same entity to Core Data at different times (and retain all of them). It seems the default behavior of Sync is to delete everything and replace it each time you sync. For other projects using Sync, I've worked around this by using a predicate along with the new object being sync'd of the kind "remoteID == %@", newObject.id. This will cause the new object to be added if another object with that id isn't already found in Core Data.

    This works well for adding new objects, however, the problem I'm encountering is when the object already exists in Core Data. Apparently, Sync is deleting it and re-adding it. This is a problem in my case, because the objects in question are set as a relationship with another entity in Core Data whose objects are created at a separate time (and not by Sync) and then get linked up. So obviously, when Sync deletes the object and re-adds it, it breaks this relationship.

    It seems a nicer solution would be instead of deleting and replacing, if any existing object is found in Core Data with a matching primary key as the one you are trying to sync, to just update its attribute values instead of deleting and replacing the entire object.

    The way RestKit handled this was if it found a matching primary key, it just ignored the object completely unless you also set a property that told it which specific keys to inspect for changes between the matching objects. If that key(s) had changed, it updated the existing object's attributes. Of course, RestKit also just added new objects by default (if the primary key didn't already exist) which seems like a better desired behavior than deleting everything each time.

    So I'm not sure what the best way would be to implement this in Sync, but it would be great to have. For now, I'm considering just keeping the objects unlinked, and carry an additional attribute in one of them that stores the unique key of the other. Of course, I don't prefer this approach since it requires doing an additional fetch to retrieve the referenced object. Thoughts?

    opened by bonebox 17
  • no documentation? I can't figure out how to use this

    no documentation? I can't figure out how to use this

    I have a model.xcodedatamodeld in a framework integrated in my app and I want to sync objects to my model! how can I do that ? what is dataStack ? you do not use it in your example !

    what I understood is something like this DataStack(name:"Model").sync(usersJson, inEntityNamed: Users.entity().name!, completion: { (e) in }) but it can not find the Model 2017-11-22 21:13:47.527082+0000 app3[2312:1375074] [error] error: Failed to load model named Model

    note that my model dose not exist in my app, but it exist in a framework (model) where I have all my entities and I do a import model in my app

    opened by siempay 16
  • Duplicate entries even though primary key is the same

    Duplicate entries even though primary key is the same

    I'm trying to sync the following json:

    [  
       {  
          "id":1,
          "recent_tags":[  
             {  
                "id":10
             }
          ],
          "categories":[  
             {  
                "id":100,
                "defaultTag":{  
                   "id":10
                }
             }
          ]
       }
    ]
    

    In this example, a Website has tags and categories. Since there can be lots of tags, only the most recent ones are being send. Categories can have a defaultTag.

    When I sync the above JSON I end up with 2 tags, both with id: 10.

    Btw I just became a Patreon, thanks for your open source libraries, they are awesome!

    opened by batjo 16
  • protocol SyncDelegate: class

    protocol SyncDelegate: class

    Hi,

    in Xcode 12.5 we receive this warning for the SyncDelegate declaration

    public protocol SyncDelegate: class

    Using 'class' keyword for protocol inheritance is deprecated; use 'AnyObject' instead

    Could we fix this please to

    public protocol SyncDelegate: AnyObject

    as suggested ?

    opened by tbechtum 0
  • Sync export skips over well defined Transformable Attributes

    Sync export skips over well defined Transformable Attributes

    Trying to define array in core data that will import / export with Sync. Defined attribute arrays as per core data documentation. The transformable attributes work fine in my app. They are just failing to import / export. Does Sync handle Transformable data.

    Method #1) Loading data into core data . . .

        let newLocation = IARLocation(context: context)
        newLocation.uniqueID = UUID().uuidString
        newLocation.textDescription = "location 1"
        let gpsLocation: [Double] = [Double(1.0), Double(1.3)]
        newLocation.gps = gpsLocation
        newLocation.gpsLatitude = 1.0
        newLocation.gpsLongitude = 1.3
    

    Method #1) Export output for Location entity . . .

    "location": { "gps_latitude" = 1; "gps_longitude" = "1.3"; "location_image" = { "image_filename" = "5BBD3652-0D52-41AD-A744-78CB9CBF9D83"; "image_path" = ""; "image_type" = png; name = locationImage; "text_description" = "Location Image"; "unique_id" = "5BBD3652-0D52-41AD-A744-78CB9CBF9D83"; };

    Method #1) Core Data def attached location core data def.png

    Method #2) Loading data into core data . . .

        let newAddress = IARAddress(context: context)
        newAddress.uniqueID = UUID().uuidString
        newAddress.textDescription = "address 1"
        let gpsAddress: [NSNumber] = [NSNumber(5.0), NSNumber(5.8)]
        newAddress.gps = gpsAddress
        newAddress.gpsLatitude = 5.0
        newAddress.gpsLongitude = 5.8
        newAddress.city = "Whoville"
        newAddress.zipcode = "00000"
        newAddress.state = "WV"
        newAddress.apartment = "3C"
        newAddress.street = "Main"
        newAddress.number = "140303"
        newDoor.address = newAddress
    

    Method #2) Export output for Location entity . . .

        address =         {
            apartment = 3C;
            city = Whoville;
            "gps_latitude" = 5;
            "gps_longitude" = "5.8";
            name = address;
            number = 140303;
            state = WV;
            street = Main;
            "text_description" = "address 1";
            "unique_id" = "91B70457-33DE-48F8-925A-67C6E0C09B58";
            zipcode = 00000;
        };
    

    Method #2) Core Data def attached address core data def.png

    I currently have gpsLatatude and gpsLongitude defined as Doubles in my code data entity attributes just for verification purposes. I would much prefer to use transformable arrays.

    Address core data def Location core data def

    opened by ghost 6
  • Application crash on NSManagedObject model.export() take 2

    Application crash on NSManagedObject model.export() take 2

    I'm running into the same issue as was reported in August of last year.

    When I export the model, the application crashes. error is ; Thread 1: EXC_BAD_ACCESS (code=2, address= 0x16bc8bf90)

    (NSString *)remotePrefixUsingInflectionType:(SyncPropertyMapperInflectionType)inflectionType { switch (inflectionType) { case SyncPropertyMapperInflectionTypeSnakeCase: return [NSString stringWithFormat:@"%@", [self.entity.name hyp_snakeCase]]; break; case SyncPropertyMapperInflectionTypeCamelCase: return [self.entity.name hyp_camelCase]; break; } } it dies in the line return [NSString stringWithFormat:@"%@", [self.entity.name hyp_snakeCase]];

    from what I can see the code is caught in an infinite loop. see attached thread crawl.

    bus error thread trace.txt

    I've tried changing around my data model in various ways, to no avail. any clue as to what I can try next?

    Richard Hood [email protected]

    opened by ghost 4
  • Insert/Update issue

    Insert/Update issue

    Coredata i am facing issue in insert and update don't know why some time it inserted data on same model but once data is inserted unable new data is not inserted or existing data is not updating. Data which is not inserted intoEntry it have about 19000 record if it was the reason then please let me know how to handle large number of records I am using sync version 6.0.3
    //JSON
    {
        "deviceId": "154",
        "fieldId": "uuid",
        "farmId": "uuid",
        "companyId": "uuid",
        "points": [
            {
                "ts": 1614091886000,
                "v": {
                    "cv": 0.1,
                    "sr": 1
                },
                "b": 3281,
                "s": 5
            }
        ]
    }
    

    remoteKey is deviceId and and ts.

    opened by junaid04 1
  • Firebase use

    Firebase use

    Hi all and @3lvis Can I use this with firebase? I have .childAdded and .childRemoved and .childChanged. How this can be used with Sync so it does not delete previous records?

    opened by yarodevuci 0
Releases(6.5.0)
  • 6.0.3(Jun 6, 2020)

  • 6.0.2(Jun 4, 2020)

  • 6.0.0(Apr 16, 2019)

  • 5.2.1(Jan 28, 2019)

    • Support for Swift 4.2 and Xcode 10 (@philip-zhan)
    • Improved the way nested relationships work (@joeboyscout04)
    • Improved support for parsing dates (@Kemmey)
    • Added an extra parameter to public class func changes... (@petkrein)
    Source code(tar.gz)
    Source code(zip)
  • 5.1.0(Oct 6, 2018)

  • 5.0.1(Sep 17, 2018)

  • 5.0.0(Aug 23, 2018)

    • Added support for extended operation options #433

    Before you could set insert, update and delete operations and that worked for both parents and children, now you have more control and can also decide if children follow these rules using insertRelationships, updateRelationships and deleteRelationships.

    ⚠️ Breaking change ⚠️

    If you were using the .insert, .update, or .delete options now you'll also need to set .insertRelationships, .updateRelationships or . deleteRelationships based on what are your needs.

    If you weren't using OperationOptions then you won't need to do anything since it will default to .all

    What's operation options?

    It's a feature that allows you to have more control over what happens when using Sync, you can then tell sync to only do inserts and updates, or only do inserts and deletes and so on.

    Looks like this:

    dataStack.sync(updated, inEntityNamed: "User", operations: [.insert, .update, .delete, .deleteRelationships], completion: nil)
    
    Source code(tar.gz)
    Source code(zip)
    Sync.framework.zip(9.48 MB)
  • 4.3.0(Aug 23, 2018)

    • Rollback extended sync operations

    Extended operations was a breaking change, it didn't break the compilation but it broke functionality, this release aims for fix that, I'll reintroduce the feature in a separate major release: https://github.com/3lvis/Sync/issues/497

    Source code(tar.gz)
    Source code(zip)
    Sync.framework.zip(9.45 MB)
  • 4.2.1(Jul 24, 2018)

    • Fixes an issue with forcing all requests to work in "isTesting" mode, meaning synchronously. https://github.com/3lvis/Sync/pull/522

    • Introduced an extension to FileManager to get the directory URL where the sqlite file is stored. Since it can be different when running on device or in unit tests (because of sandboxing reasons we switch between caches folder and directory when needed). https://github.com/3lvis/Sync/commit/d970043d47b92b8be01d38b499ba7df7e1e2368c

    FileManager.sqliteDirectoryURL
    
    Source code(tar.gz)
    Source code(zip)
    Sync.framework.zip(9.40 MB)
  • 4.2.0(Jul 20, 2018)

    • Updated to Xcode 9.4.1
    • Improve handling of microseconds and miliseconds (https://github.com/3lvis/Sync/commit/8ee867884196a5dd38e2c512ff2e08639af01703)
    • Support for new UUID and URI data types (https://github.com/3lvis/Sync/pull/511)

    • Fixes export not working for nested JSON objects (https://github.com/3lvis/Sync/pull/485)
    Source code(tar.gz)
    Source code(zip)
    Sync.framework.zip(9.29 MB)
  • 4.1.2(Feb 14, 2018)

  • 4.1.1(Feb 1, 2018)

    • Annotates the background context with a name to avoid calling it when other contexts are saved https://github.com/3lvis/Sync/pull/473 https://github.com/3lvis/DATAStack/issues/111

    • Adds support for the new UUID (both insertion and export) https://github.com/3lvis/Sync/pull/472

    Source code(tar.gz)
    Source code(zip)
    Sync.framework.zip(6.47 MB)
  • 4.1.0(Jan 31, 2018)

    • Fixes a crash in to-many relationships #467

    • Fixes an issue with duplicated primary keys #471 (@batjo)

    Before the following JSON would create 6 body entries, now is only 3.

    [{
        "id":0,
        "title":"story 1",
        "comments":[{
            "body":"comment 1"
          },{
            "body":"comment 2"
          },{
            "body":"comment 3"
          }]
      },
      {
        "id":1,
        "title":"story 2",
        "comments":[{
            "body":"comment 1"
          },{
            "body":"comment 2"
          },{
            "body":"comment 3"
          }]
      }]
    
    • Fixes an issue where sending empty or null wouldn't remove the element #459

    • Added a code of conduct #468

    • Added support for extended operation options #433

    Before you could set insert, update and delete operations and that worked for both parents and children, now you have more control and can also decide if children follow these rules using insertRelationships, updateRelationships and deleteRelationships.

    Source code(tar.gz)
    Source code(zip)
    Sync.framework.zip(6.31 MB)
  • 4.0.3(Nov 2, 2017)

    • Fixes an issue where if you had several stores the completion block would be triggered when every store was dropped.

    https://github.com/3lvis/Sync/pull/439

    Source code(tar.gz)
    Source code(zip)
  • 4.0.2(Oct 24, 2017)

  • 4.0.1(Oct 18, 2017)

  • 4.0.0(Sep 22, 2017)

  • 3.3.1(Sep 20, 2017)

  • 3.3.0(Jun 26, 2017)

    • Add Objective-C support for syncing changes using Sync operations

    Options

    @objc public enum CompatibleOperationOptions: Int {
        case insert = 0
        case update = 1
        case delete = 2
        case insertUpdate = 3
        case insertDelete = 4
        case updateDelete = 5
        case all = 6
    }
    

    APIs

    class func compatibleChanges(_ changes: [[String: Any]], inEntityNamed entityName: String, dataStack: DataStack, operations: CompatibleOperationOptions, completion: ((_ error: NSError?) -> Void)?)
    
    class func compatibleChanges(_ changes: [[String: Any]], inEntityNamed entityName: String, predicate: NSPredicate?, dataStack: DataStack, operations: CompatibleOperationOptions, completion: ((_ error: NSError?) -> Void)?)
    
    Source code(tar.gz)
    Source code(zip)
    Sync.framework.zip(9.57 MB)
  • 3.2.3(Apr 27, 2017)

  • 3.2.2(Apr 19, 2017)

  • 3.2.1(Mar 28, 2017)

  • 3.2.0(Mar 26, 2017)

    Updated Core Data Model user info keys

    Added support for:

    • sync.remoteKey
    • sync.isPrimaryKey
    • sync.nonExportable
    • sync.valueTransformer

    This is backwards compatible, the hyper ones still work.

    Improved JSON export API

    Besides hyp_dictionary now you'll get a export() method.

    More info about exporting here.

    Source code(tar.gz)
    Source code(zip)
    Sync.framework.zip(9.75 MB)
  • 3.1.0(Mar 22, 2017)

    • Improved Sync helpers (https://github.com/SyncDB/Sync/pull/381)
    // For example now you can do
    dataStack.sync(objectsB, inEntityNamed: "User", operations: [.update], completion: nil)
    
    // Instead of
    Sync.changes(objectsB, inEntityNamed: "User", dataStack: dataStack, operations: [.update], completion: nil)
    
    • Improved performance when using operations filtering will be done only in the requested operations (https://github.com/SyncDB/Sync/pull/384)

    • Added support for deep-mapping for to-many relationships (https://github.com/SyncDB/Sync/pull/385)

    • Added support for sync.isPrimaryKey as an alternative to hyper.isPrimaryKey and sync.remoteKey to be used instead of hyper.remoteKey. All of this without breaking backward compatibility so you don't have to change anything. (https://github.com/SyncDB/Sync/pull/388 and https://github.com/SyncDB/Sync/pull/390)

    Source code(tar.gz)
    Source code(zip)
    Sync.framework.zip(9.48 MB)
  • 3.0.0(Mar 16, 2017)

    • Bundled all the dependencies

    Breaking changes

    • DATAStack renamed to DataStack
    • You might need to remove all your import DATAStack and replace it with import Sync
    • OperationOptions before .Insert, .Update, .Delete and .All, now .insert, .update, .delete and .all
    Source code(tar.gz)
    Source code(zip)
    Sync.framework.zip(9.15 MB)
  • 2.7.0(Jan 5, 2017)

  • 2.6.3(Jan 4, 2017)

  • 2.6.2(Dec 10, 2016)

Owner
Nes
Nes
A powerful and elegant Core Data framework for Swift.

A powerful and elegant Core Data framework for Swift. Usage Beta version. New docs soon... Simple do that: let query = persistentContainer.viewContext

null 782 Nov 6, 2022
CloudCore is a framework that manages syncing between iCloud (CloudKit) and Core Data written on native Swift.

CloudCore CloudCore is a framework that manages syncing between iCloud (CloudKit) and Core Data written on native Swift. Features Leveraging NSPersist

deeje cooley 123 Dec 31, 2022
Unleashing the real power of Core Data with the elegance and safety of Swift

Unleashing the real power of Core Data with the elegance and safety of Swift Dependency managers Contact Swift 5.4: iOS 11+ / macOS 10.13+ / watchOS 4

John Estropia 3.7k Jan 9, 2023
JustPersist is the easiest and safest way to do persistence on iOS with Core Data support out of the box.

JustPersist JustPersist is the easiest and safest way to do persistence on iOS with Core Data support out of the box. It also allows you to migrate to

Just Eat 167 Mar 13, 2022
A minimalistic, thread safe, non-boilerplate and super easy to use version of Active Record on Core Data.

Skopelos A minimalistic, thread-safe, non-boilerplate and super easy to use version of Active Record on Core Data. Simply all you need for doing Core

Alberto De Bortoli 235 Sep 9, 2022
Super awesome Swift minion for Core Data (iOS, macOS, tvOS)

⚠️ Since this repository is going to be archived soon, I suggest migrating to NSPersistentContainer instead (available since iOS 10). For other conven

Marko Tadić 306 Sep 23, 2022
HitList is a Swift App shows the implementation of Core Data.

HitList HitList is a Swift App shows the implementation of Core Data. It is the demo app of Ray Wenderlich's tech blog. For details please reference G

Kushal Shingote 2 Dec 9, 2022
A type-safe, fluent Swift library for working with Core Data

Core Data Query Interface (CDQI) is a type-safe, fluent, intuitive library for working with Core Data in Swift. CDQI tremendously reduces the amount o

null 31 Oct 26, 2022
100% Swift Simple Boilerplate Free Core Data Stack. NSPersistentContainer

DATAStack helps you to alleviate the Core Data boilerplate. Now you can go to your AppDelegate remove all the Core Data related code and replace it wi

Nes 216 Jan 3, 2023
This project server as a demo for anyone who wishes to learn Core Data in Swift.

CoreDataDemo This project server as a demo for anyone who wishes to learn Core Data in Swift. The purpose of this project is to help someone new to Co

null 1 May 3, 2022
A type-safe, fluent Swift library for working with Core Data

Core Data Query Interface (CDQI) is a type-safe, fluent, intuitive library for working with Core Data in Swift. CDQI tremendously reduces the amount o

null 31 Oct 26, 2022
JSQCoreDataKit - A swifter Core Data stack

JSQCoreDataKit A swifter Core Data stack About This library aims to do the following: Encode Core Data best practices, so you don't have to think "is

Jesse Squires 596 Dec 3, 2022
QueryKit, a simple type-safe Core Data query language.

QueryKit QueryKit, a simple type-safe Core Data query language. Usage QuerySet<Person>(context, "Person")

QueryKit 1.5k Dec 20, 2022
A synchronization framework for Core Data.

Core Data Ensembles Author: Drew McCormack Created: 29th September, 2013 Last Updated: 15th February, 2017 Ensembles 2 is now available for purchase a

Drew McCormack 1.6k Dec 6, 2022
Core Data code generation

mogenerator Visit the project's pretty homepage. Here's mogenerator's elevator pitch: mogenerator is a command-line tool that, given an .xcdatamodel f

Wolf Rentzsch 3k Dec 30, 2022
Super Awesome Easy Fetching for Core Data!

MagicalRecord In software engineering, the active record pattern is a design pattern found in software that stores its data in relational databases. I

Magical Panda Software 10.9k Dec 29, 2022
A feature-light wrapper around Core Data that simplifies common database operations.

Introduction Core Data Dandy is a feature-light wrapper around Core Data that simplifies common database operations. Feature summary Initializes and m

Fuzz Productions 33 May 11, 2022
The Big Nerd Ranch Core Data Stack

BNR Core Data Stack The BNR Core Data Stack is a small Swift framework that makes it both easier and safer to use Core Data. A better fetched results

Big Nerd Ranch 561 Jul 29, 2022
Example repo of working with Core Data in a SwiftUI application

CoreData in SwiftUI This repository serves many purpose. But mostly so I can experiment with Core Data in SwiftUI, and also so I can use it show my ap

Donny Wals 4 Jan 30, 2022