Giter Club home page Giter Club logo

synckit's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

synckit's Issues

Carthage 3.3

Carthage Install gives the following errors;

Build Failed
Task failed with exit code 65:
/usr/bin/xcrun xcodebuild -workspace /Users/lukemcdonald/Documents/Core/SyncKitTutorial/Carthage/Checkouts/SyncKit/Framework/SyncKit.xcworkspace -scheme SyncKitiOS -configuration Release -derivedDataPath /Users/lukemcdonald/Library/Caches/org.carthage.CarthageKit/DerivedData/SyncKit/0.3.3 -sdk iphoneos ONLY_ACTIVE_ARCH=NO BITCODE_GENERATION_MODE=bitcode CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES clean build

LOG Below;

The following build commands failed:
CompileC /Users/lukemcdonald/Library/Caches/org.carthage.CarthageKit/DerivedData/SyncKit/0.3.1/Build/Intermediates/SyncKit.build/Release-iphoneos/SyncKit.build/Objects-normal/armv7/QSOriginObjectIdentifier+CoreDataProperties.o /Users/lukemcdonald/Documents/Core/SyncKitTutorial/Carthage/Checkouts/SyncKit/SyncKit/Classes/CoreData/QSOriginObjectIdentifier+CoreDataProperties.m normal armv7 objective-c com.apple.compilers.llvm.clang.1_0.compiler
CompileC /Users/lukemcdonald/Library/Caches/org.carthage.CarthageKit/DerivedData/SyncKit/0.3.1/Build/Intermediates/SyncKit.build/Release-iphoneos/SyncKit.build/Objects-normal/armv7/QSOriginObjectIdentifier.o /Users/lukemcdonald/Documents/Core/SyncKitTutorial/Carthage/Checkouts/SyncKit/SyncKit/Classes/CoreData/QSOriginObjectIdentifier.m normal armv7 objective-c com.apple.compilers.llvm.clang.1_0.compiler
CompileC /Users/lukemcdonald/Library/Caches/org.carthage.CarthageKit/DerivedData/SyncKit/0.3.1/Build/Intermediates/SyncKit.build/Release-iphoneos/SyncKit.build/Objects-normal/armv7/QSRecord.o /Users/lukemcdonald/Documents/Core/SyncKitTutorial/Carthage/Checkouts/SyncKit/SyncKit/Classes/CoreData/QSRecord.m normal armv7 objective-c com.apple.compilers.llvm.clang.1_0.compiler
(3 failures)

Any plans for Swift?

Apple has already added some reflection features in Swift 3 to introspect object structure during runtime. Any plans to make this awesome library available to be used in Swift projects?

sample code

I run the sample code.
Add company and employees.
On the CloudKit dashboard I saw 2 new recordTypes:
QSCompany2
QSEmployee2

I add "BMW company" and "emp bmw 1" and "emp bmw 2" press Synchroinze
and logout and login to cloudkit dashboard, query for the records of RecordType "QSCompany2"
and no results (I add Queryable index to recordName)

Am I missing something ?

Thanks in advance

Existing subscriptions on reinstallation

hey i'm having a small issue with the update notifications feature. When setting this feature up on application launch, I attempt to subscribe the device for update notifications and check to make sure the device isn't subscribed already as such:

        var sync: QSCloudKitSynchronizer!
        ...
        // subscribe for update notifications
        if !sync.isSubscribedForUpdateNotifications() {
            sync.subscribeForUpdateNotifications { (error) in
                guard error == nil else {
                    NSLog(error!.localizedDescription)
                    return
                }
                NSLog("Remote iCloud updates live")
            }
        }

On first launch with a device that has no iCloud records yet logs Remote iCloud updates live. The issue I'm seeing is that isSubscribedForUpdateNotifications() seems to continue returning false on subsequent launches even when there is an existing subscription as indicated by the error that is logged: Error saving record subscription with id 9BC150CC-ED7D-40B6-9CDD-E4E9D76EE68A to server: subscription is duplicate of '0E44F8CB-B3C5-411B-A056-0496190E6854'

Despite the error, the device will still receive update notifications and everything still seems to work correctly so I'm not terribly concerned. Is this a bug with the isSubscribedForUpdateNotifications() getter or is my understanding incorrect with how to proceed here?

Make it available for Watch OS

Hi,

Could you make it (the pod file) available for Watch OS too? Watchkit Extension has a separate Core Data stack but with the same model and CloudKit Framework available too, so we could use it on that device too. I think so the integration is the same as at the IOS side. So that would be really great!

Thank you!

carthage build downloads only SyncKitCoreData

When I add SyncKit to my Cartfile and carthage update, I see Downloading SyncKit.framework binary at "0.5.7" and end up with only the SyncKitCoreData files. When I run carthage update --no-use-binaries, I get a build error on the SyncKitRealmOSX scheme. The error log says things like "/Users/manuel/Documents/Apps/SyncKit/SyncKit/Classes/QSSynchronizer/SyncKitLog.h", leading me to believe that there are some absolute file references in there. Anyway, carthage update SyncKit --no-use-binaries --platform iOS ends up working.

Duplications insert Object in cloudKit database + solution

Hi,

It's a great Sync method!! First of All really thanks for it! ;) And I will use for my new IOSApp, and I also wanna create a tutorial for it. I have only one annoying thing with your codes, the duplications after synchronization.
I have a CoreData stack, and I'm importing for 2 entity 10 and 15 objects at the First launch. Sync is running every time when you open or close the app, but not at First launch (cause problems with import, because it is so slow, that the UI update and other codes can't wait the end of the Sync). And of course, at the very first launch, the user hasn't got any objects, so don't need to sync the database.
But if you imported these objects, and after that delete the App, and later download it again (I'm just test it now from Xcode on real device, and delete the app form device and start running again), the App has a First Launch, so the import starts, but you check just the ObjectID in the CoreDataChangeManager, and not the Object properties. I believe this is a mistake, because, if I create a new Object, the Object ID will be different, even if the object property is the same. So for 1 entity, there will be not 15 object, there will be 30. And later when the sync starts, in the App these objects will duplicate.
I wrote a code for this situation, to delete those object, if they have for example the same name property, or the same displayOrder property. But this is not a perfect solution (I checked the objects at a collection view, but the import is running at launch, sot till i go to that collection view, these objects still duplicated, which can cause other problems too).
So I suggest a solution, if you could set for CoreDataChangeManager a "mainattribute", wich could set globally in AppDelegate, or anywhere else, as the Synchronizer, than developers could set 1 attribute to every Entity, as a main attribute, which can't be the same, so you should write an if statement for the "mainattribute", in this block: - (QSSyncedEntity *)createSyncedEntityForRecord:(CKRecord *)record, to check if it already exists, and if yes, than avoid the targetContext insertation.

The second solution this "after deletion" what I'm using now, if after the Sync, there are duplications, than I delete the objects with the same name or other property. And for those who have Problems with these things it is strongly recommended to running Sync after every deletion in the App! so with this logic:

                                      [self.managedObjectContext deleteObject:deleteTarget];
                                      [self.managedObjectContext save:nil];
                                      NSLog(@"deleted!");
                                      [self startSync];

And yes there are some words about this SycKit hasn't got Deduplicator, and developer has to write one, but deduplicator for the CoreCata object in the app locally is different as a deduplicator for the CloudKit what you made, so you should improve it. And of course easier modifying your codes and using a global variable implement in a unique App, as with a unique property/database overwrite your SyncKit changemanager, which is otherwise awesome! ;)

<SyncKit/QSCloudKitSynchronizer+CoreData.h> is not found in example project

I tried to build SyncKitCoreDataExample, but got this error:

/Users/user/path/SyncKit/Example/SyncKit/QSAppDelegate.m:10:9: 'SyncKit/QSCloudKitSynchronizer+CoreData.h' file not found

bildschirmfoto 2017-05-29 um 15 58 30

That file is in /Users/user/path/SyncKit/SyncKit/Classes/CoreData/QSCloudKitSynchronizer+CoreData.h

How do I import it?

Crash QSCoreDataChangeManager.m line 969

Hi,

i get a crash sometimes when i start [self.synchronizer synchronizeWithCompletion:^(NSError *error) {
I am using MagicalRecord for the CoreData Model and its only crashing when i start the app directly from the simulator without the debugging menu (press play from xcode)

#7. Crashed: com.twitter.crashlytics.ios.exception
0  App                           0x105972b70 CLSProcessRecordAllThreads + 174
1  App                           0x105972ec1 CLSProcessRecordAllThreads + 1023
2  App                           0x105963ae1 CLSHandler + 45
3  App                           0x105971543 __CLSExceptionRecord_block_invoke + 87
4  libdispatch.dylib              0x10caef779 _dispatch_client_callout + 8
5  libdispatch.dylib              0x10caf5e71 _dispatch_queue_barrier_sync_invoke_and_complete + 94
6  App                           0x105970f8a CLSExceptionRecord + 208
7  App                           0x105970db8 CLSExceptionRecordNSException + 601
8  App                           0x1059709ec CLSTerminateHandler() + 323
9  libc++abi.dylib                0x10c9f40ae std::__terminate(void (*)()) + 8
10 libc++abi.dylib                0x10c9f4123 std::terminate() + 51
11 libobjc.A.dylib                0x10b78c233 _destroyAltHandlerList + 7
12 libdispatch.dylib              0x10caef78d _dispatch_client_callout + 28
13 libdispatch.dylib              0x10caf71b2 _dispatch_queue_serial_drain + 735
14 libdispatch.dylib              0x10caf79af _dispatch_queue_invoke + 321
15 libdispatch.dylib              0x10caf416a _dispatch_queue_override_invoke + 477
16 libdispatch.dylib              0x10caf9cf8 _dispatch_root_queue_drain + 473
17 libdispatch.dylib              0x10caf9ac1 _dispatch_worker_thread3 + 119
18 libsystem_pthread.dylib        0x10d012169 _pthread_wqthread + 1387
19 libsystem_pthread.dylib        0x10d011be9 start_wqthread + 13

--

Fatal Exception: NSInvalidArgumentException
0  CoreFoundation                 0x10c0ef1ce (Missing)
1  libobjc.A.dylib                0x10b78c031 objc_exception_throw
2  CoreData                       0x1069e12ce (Missing)
3  App                           0x1057fcceb -[QSCoreDataChangeManager configureImportContext] (QSCoreDataChangeManager.m:969)
4  App                           0x1057fd0d4 -[QSCoreDataChangeManager prepareForImport] (QSCoreDataChangeManager.m:1008)
5  App                           0x1057ed5f8 __48-[QSCloudKitSynchronizer performSynchronization]_block_invoke (QSCloudKitSynchronizer.m:243)
6  libdispatch.dylib              0x10caee73b (Missing)
7  libdispatch.dylib              0x10caef779 (Missing)
8  libdispatch.dylib              0x10caf71b2 (Missing)
9  libdispatch.dylib              0x10caf79af (Missing)
10 libdispatch.dylib              0x10caf416a (Missing)
11 libdispatch.dylib              0x10caf9cf8 (Missing)
12 libdispatch.dylib              0x10caf9ac1 (Missing)
13 libsystem_pthread.dylib        0x10d012169 (Missing)
14 libsystem_pthread.dylib        0x10d011be9 (Missing)

#0. com.apple.main-thread
0  libsystem_kernel.dylib         0x10cfd220a mach_msg_trap + 10
1  libsystem_kernel.dylib         0x10cfd1724 mach_msg + 60
2  CoreFoundation                 0x10c0767d5 __CFRunLoopServiceMachPort + 229
3  CoreFoundation                 0x10c075c19 __CFRunLoopRun + 1689
4  CoreFoundation                 0x10c07530b CFRunLoopRunSpecific + 635
5  GraphicsServices               0x10fe73a73 GSEventRunModal + 62
6  UIKit                          0x108af70b7 UIApplicationMain + 159
7  App                           0x10568b9d6 main (main.m:17)
8  libdyld.dylib                  0x10cb64955 start + 1

#1. com.twitter.crashlytics.ios.binary-images
0  libsystem_kernel.dylib         0x10cfdc2f2 access + 10
1  Foundation                     0x1075ed92f -[NSBundle initWithPath:] + 428
2  Foundation                     0x1075ee602 +[NSBundle bundleWithPath:] + 45
3  App                           0x10595b82f __CLSBinaryImageChanged_block_invoke + 345
4  libdispatch.dylib              0x10caee73b _dispatch_call_block_and_release + 12
5  libdispatch.dylib              0x10caef779 _dispatch_client_callout + 8
6  libdispatch.dylib              0x10caf71b2 _dispatch_queue_serial_drain + 735
7  libdispatch.dylib              0x10caf79af _dispatch_queue_invoke + 321
8  libdispatch.dylib              0x10caf416a _dispatch_queue_override_invoke + 477
9  libdispatch.dylib              0x10caf9cf8 _dispatch_root_queue_drain + 473
10 libdispatch.dylib              0x10caf9ac1 _dispatch_worker_thread3 + 119
11 libsystem_pthread.dylib        0x10d012169 _pthread_wqthread + 1387
12 libsystem_pthread.dylib        0x10d011be9 start_wqthread + 13

#2. Thread
0  libsystem_kernel.dylib         0x10cfdc292 __workq_kernreturn + 10
1  libsystem_pthread.dylib        0x10d01220e _pthread_wqthread + 1552
2  libsystem_pthread.dylib        0x10d011be9 start_wqthread + 13

#3. com.crashlytics.analytics.maintenance
0  libsystem_kernel.dylib         0x10cfdbce2 __rmdir + 10
1  libsystem_kernel.dylib         0x10cfd8d33 rmdir + 11
2  libremovefile.dylib            0x10cbab775 __removefile_process_file + 305
3  libremovefile.dylib            0x10cbab8de __removefile_tree_walker + 258
4  libremovefile.dylib            0x10cbabbff removefile + 147
5  Foundation                     0x1076582d3 -[NSFilesystemItemRemoveOperation main] + 171
6  Foundation                     0x10761d6b2 -[__NSOperationInternal _start:] + 766
7  Foundation                     0x107658162 -[NSFileManager removeItemAtPath:error:] + 84
8  App                           0x10598411e -[CLSEventLogSessionRepository removeSessionFragmentDirectory:error:] + 143
9  App                           0x10597b64a -[CLSAnalyticsController runPackageClosedSessionFragments:] + 483
10 App                           0x10597b767 __56-[CLSAnalyticsController packageClosedSessionFragments:]_block_invoke + 38
11 libdispatch.dylib              0x10caee73b _dispatch_call_block_and_release + 12
12 libdispatch.dylib              0x10caef779 _dispatch_client_callout + 8
13 libdispatch.dylib              0x10caf71b2 _dispatch_queue_serial_drain + 735
14 libdispatch.dylib              0x10caf79af _dispatch_queue_invoke + 321
15 libdispatch.dylib              0x10caf416a _dispatch_queue_override_invoke + 477
16 libdispatch.dylib              0x10caf9cf8 _dispatch_root_queue_drain + 473
17 libdispatch.dylib              0x10caf9ac1 _dispatch_worker_thread3 + 119
18 libsystem_pthread.dylib        0x10d012169 _pthread_wqthread + 1387
19 libsystem_pthread.dylib        0x10d011be9 start_wqthread + 13

#4. com.apple.uikit.eventfetch-thread
0  libsystem_kernel.dylib         0x10cfd220a mach_msg_trap + 10
1  libsystem_kernel.dylib         0x10cfd1724 mach_msg + 60
2  CoreFoundation                 0x10c0767d5 __CFRunLoopServiceMachPort + 229
3  CoreFoundation                 0x10c075c19 __CFRunLoopRun + 1689
4  CoreFoundation                 0x10c07530b CFRunLoopRunSpecific + 635
5  Foundation                     0x107604b4a -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 274
6  Foundation                     0x10768167f -[NSRunLoop(NSRunLoop) runUntilDate:] + 79
7  UIKit                          0x10974dba2 -[UIEventFetcher threadMain] + 118
8  Foundation                     0x1076123b3 __NSThread__start__ + 1221
9  libsystem_pthread.dylib        0x10d012661 _pthread_body + 340
10 libsystem_pthread.dylib        0x10d01250d _pthread_start + 375
11 libsystem_pthread.dylib        0x10d011bf9 thread_start + 13

#5. com.apple.network.connections
0  libboringssl.dylib             0x10eacb759 extend_handshake_buffer + 116
1  libboringssl.dylib             0x10ea6f3b5 ssl3_connect + 905
2  libboringssl.dylib             0x10ead1896 SSL_do_handshake + 69
3  libboringssl.dylib             0x10ea59422 boringssl_session_handshake_continue + 199
4  libboringssl.dylib             0x10ea59004 boringssl_context_handshake_negotiate + 463
5  libboringssl.dylib             0x10ea637f2 nw_protocol_boringssl_handshake_negotiate + 82
6  libdispatch.dylib              0x10caee73b _dispatch_call_block_and_release + 12
7  libdispatch.dylib              0x10caef779 _dispatch_client_callout + 8
8  libdispatch.dylib              0x10caf71b2 _dispatch_queue_serial_drain + 735
9  libdispatch.dylib              0x10caf79af _dispatch_queue_invoke + 321
10 libdispatch.dylib              0x10caf9cf8 _dispatch_root_queue_drain + 473
11 libdispatch.dylib              0x10caf9ac1 _dispatch_worker_thread3 + 119
12 libsystem_pthread.dylib        0x10d012169 _pthread_wqthread + 1387
13 libsystem_pthread.dylib        0x10d011be9 start_wqthread + 13

#6. Thread
0  libsystem_pthread.dylib        0x10d011bdc _pthread_workqueue_addthreads + 67

#7. Crashed: com.twitter.crashlytics.ios.exception
0  App                           0x105972b70 CLSProcessRecordAllThreads + 174
1  App                           0x105972ec1 CLSProcessRecordAllThreads + 1023
2  App                           0x105963ae1 CLSHandler + 45
3  App                           0x105971543 __CLSExceptionRecord_block_invoke + 87
4  libdispatch.dylib              0x10caef779 _dispatch_client_callout + 8
5  libdispatch.dylib              0x10caf5e71 _dispatch_queue_barrier_sync_invoke_and_complete + 94
6  App                           0x105970f8a CLSExceptionRecord + 208
7  App                           0x105970db8 CLSExceptionRecordNSException + 601
8  App                           0x1059709ec CLSTerminateHandler() + 323
9  libc++abi.dylib                0x10c9f40ae std::__terminate(void (*)()) + 8
10 libc++abi.dylib                0x10c9f4123 std::terminate() + 51
11 libobjc.A.dylib                0x10b78c233 _destroyAltHandlerList + 7
12 libdispatch.dylib              0x10caef78d _dispatch_client_callout + 28
13 libdispatch.dylib              0x10caf71b2 _dispatch_queue_serial_drain + 735
14 libdispatch.dylib              0x10caf79af _dispatch_queue_invoke + 321
15 libdispatch.dylib              0x10caf416a _dispatch_queue_override_invoke + 477
16 libdispatch.dylib              0x10caf9cf8 _dispatch_root_queue_drain + 473
17 libdispatch.dylib              0x10caf9ac1 _dispatch_worker_thread3 + 119
18 libsystem_pthread.dylib        0x10d012169 _pthread_wqthread + 1387
19 libsystem_pthread.dylib        0x10d011be9 start_wqthread + 13

#8. Thread
0  libsystem_pthread.dylib        0x10d011bdc _pthread_workqueue_addthreads + 67

#9. com.twitter.crashlytics.ios.MachExceptionServer
0  libsystem_kernel.dylib         0x10cfd220a mach_msg_trap + 10
1  libsystem_kernel.dylib         0x10cfd1724 mach_msg + 60
2  App                           0x10595ebb7 CLSMachExceptionServer + 120
3  libsystem_pthread.dylib        0x10d012661 _pthread_body + 340
4  libsystem_pthread.dylib        0x10d01250d _pthread_start + 375
5  libsystem_pthread.dylib        0x10d011bf9 thread_start + 13

Can't share twice

I've an issue with the SyncKitCoreDataExample and sharing feature.
If I stop a share and try to share it again, it produce this error:
(it's reproductible with the current release)

<CKError 0x60c000257100: "Partial Failure" (2/1011); "Failed to modify some records"; uuid = B006F530-D182-4632-9AD8-44B500677AD7; container ID = "MYCONTAINERIDHERE"; partial errors: {
Company.776B3C03-B3AF-40D4-8E43-B26B3A71607B:(QSCloudKitCustomZoneName:defaultOwner) = <CKError 0x60c00024f960: "Server Record Changed" (14/2004); server message = "client oplock error updating record"; uuid = B006F530-D182-4632-9AD8-44B500677AD7>
... 95 "Batch Request Failed" CKError's omited ...
}>

I've try to use removeShare instead of deleteShare without success....

I've found a possible explanation here: https://stackoverflow.com/questions/48391834/ckshare-server-record-changed-error but I don't know how exactly works SyncKit...

Memory usage

Even after fixing leak(s) - #59 - I am not able to sync my quite huge database. It contains ~150000 CKRecords in CloudKit. The memory usage keeps increasing slowly when SyncKit downloads changes. After download is completed, used memory increases become slower, but it still goes up (when syncKit is applying attributes/relationships). Then finally it reaches ~700 MB and on one device (iPad) it receives memory warning and OS kills it. Do you have any suggestions what can be done here? What can I try to improve SyncKit performance?

`nil` values for attributes not syncing to iCloud (CoreData)

I'm seeing an issue with syncing relationships when values are removed / nullified.

consider the example case

class Parent {
    @NSManaged var children: NSSet
}

class Child {
    @NSManaged var parent: Parent?
}

if for some arbitrary instance of child parent is set

let arb = Child(context: ...)
arb.parent = someInstanceOfParent

and saved, this will sync fine. If it's changed to a different value and saved again it syncs fine etc. The problem is when it is set to nil on one device and synchronized to another, this change is not synchronized to the local core data store and the last set value persists.

The problem exists from the other direction as well where if an object is removed from an NSSet and synchronized, the changes are not reflected in the iCloud store.

I've verified this with both one-to-one and one-to-many relationships. nil values just don't stick to the cloud store. Note that in these cases the objects are not being deleted, the relationship is just being nullified.

TL;DR

  • when a relationship is set to nil, or an object is removed from a relationship set and saved, the changes do not synchronize correctly with iCloud

Example in Swift -> can't convert QSAppDelegate.m

Hello,
First THANKS YOU for SyncKit, that's exactly for what I'm looking for my futur App.
For more clarity with the code, I've translate your QSCoreDataExample in Swift.
I can do a Sync at first launch and data are well retrieved from CloudKit if any. But if I try to add or delete a Company, the next sync always return this error:
Sync Error : <CKError 0x604000057a60: "Invalid Arguments" (12); "You can't save the same record twice: <CKRecordID: 0x608000439360; recordName=QSCompany.F46B8460-1552-46C7-877F-244F0AF3881A, zoneID=QSCloudKitCustomZoneName:defaultOwner>">

The issue appears to be in my Swift implementation of QSAppDelegate because all works fine with the .h/.m ones...
I've try a lot of things but I can't understand what I'm doing wrong...

I have a working copy with QSAppDelegate.h/.m here:
https://github.com/LeJeko/SyncKit/tree/swift/Example/CoreData/SyncKit

To have the error, I unlink QSAppDelegate.m and main.m and link QSAppDelegate.swift to the target.
Remove the App and rebuild it.

Thanks for your help

Error Domain=QSCloudKitSynchronizerErrorDomain Code=0 "(null)"

Hello,

Could you help please, I always got this error:
Error Domain=QSCloudKitSynchronizerErrorDomain Code=0 "(null)"

if not, the sync is running without the completion block. So
Here nothing called in the completion block, or just got this error:

[self.synchronizer synchronizeWithCompletion:^(NSError *error) {
                    //  [self.indicatorView stopAnimating];
                    NSLog(@"Sync Start");
                    NSLog(@"error %@", error);
                    if (error) {
                        NSLog(@"error snyc end: %@", error);
                    }else{
                         //CHECK SYNCKIT SUBSCRIBES!!!!
                        NSLog(@"Sync END check Zone ID");
                    }

2018-11-20 14:14:43.579750+0100 error Error Domain=QSCloudKitSynchronizerErrorDomain Code=0 "(null)"
2018-11-20 14:14:43.579932+0100 Purp[43018:2262975] error snyc end: Der Vorgang konnte nicht abgeschlossen werden. (QSCloudKitSynchronizerErrorDomain-Fehler 0.)

And I can't see the saved objects in the TableView, just after I launch the App again. (Checked saved in the ManagedObjectContext, and I can log them out, but fetch controller can't recognize it.. Without sync, and the AdapterImport there is no problem.

And sometimes the app is crashing at QSCoreDataAdapter if the sync completion not called
2018-11-20 14:14:40.397866+0100 Purp[43018:2263064] <0x282125340 QSCoreDataAdapter.m:(139)> ADAPTER savePrivateContext

Do you have any idea? I have already checked the developer team at signing, so it has an access to the CloudKit, prov.profile has the CloudKit container, which is the same as in the code. Maybe I miss something, an idea can help to overcome.

Thank you!

Eva

[QSCoreDataAdapter saveToken:] wrong thread

It looks like, that saveToken: method is using wrong thread when modifying QSServerToken object. As far as I know managedObjects modifications should be done in thoeir managedObjectContexts threads. I recently updated SyncKit and during server token transfer (from older commit/system) I got multithreading violation. I run app "with -com.apple.CoreData.ConcurrencyDebug 1" flag. It seems to me that qsToken.token = [NSKeyedArchiver archivedDataWithRootObject:token] should be performed in self.privateContext thread (performBlock: ... ). Unless I am doing something wrong.

Sharing more complex data models.

As I understand, SyncKit supports only such "trees" where child objects have a to-one (many to one, or one to one) relationship to a parent object (parent <- child <- subchild). I need an ability to sync a more complex model. Lets say there is an entity called Property, that has one-to-many relationship to Child objects:
parent <- child1 (-> propertyA) <- subchild1 , .. , parent <- child2 (-> propertyA) <- subchild2. Have you ever thought about supporting sharing such models? If you have thought, but don't have plans to implement it, maybe you have any suggestions/recommendations how it could be achieved?

As far as I can see now in the Cloudkit dashboard - objects child1 and child2 have correct ckrecordids set for their to-one relationship to the entity Property in the shared database. The problem is that this Property object is not being shared. If it was, then I suppose all info could be seen/fetched on the device where a share was accepted. Maybe just including Property objects to the same ckshare object as parent could be enough. Or maybe creating a new ckshare that would include all Property objects as childs of that ckshare object could do the trick (when both ckshare objects are accepted). I hope you understood what I want to do and any suggestions are welcomed.

To add capability use NSUserDefaults with appGroup

Hi, your library is amazing, thank you. I use appgroup userDefaults in my app for widget, watch extension and main app. My CoreData is stored in appgroup container. And was bug, when I sync data for main app, widget, watch extension - as dublicate actions (add data or delete data). I found problem - deviceIdentifier was different for main app, widget, watch extension. When I save deviceIdentifier in appgroup userDefaults instead of sharedUserDefaults and use it from appgroup userDefaults - i get solution - no dublicate actions. What are you think about it?
Can you add capability to use appgroup userDefaults? Or is it wrong?

Carthage platform iOS?

We're using SyncKit with our app that has lots of other dependencies. The other dependencies only work with _carthage update --platform iOS .
I'm getting build errors when trying the same with SyncKit. Right now we're extracting the SyncKit Framework from the sample project, since header files are missing for realm when trying usual carthage update.
We're using it for iOS only with CoreData.

support latest IOS (10-11) and Watch OS (3-4) versions

I have a lot of deprecations and warnings in SyncKit, could you update the library with the most common things? I have summarized them in a list instead of overwriting this git library.

A recent iOS version stats counter from Apple showing that there are only 11% devices which are still having iOS 9 (9%) or earlier (2%), and 89% of devices have IOS 10. I believe you should drop out support for those versions or if you want to support IOS 9, it should be better a version check, but don't use basically deprecated codes. Watch OS 4 will available at all Watch series, so it is simply not worth supporting older versions than WatchOS 3.0.

1. Nullability Issues in Obj-C - nonnul and nullable QSChangeManager.h file mostly
2. Deprecations:
suggestion:
if #available(iOS 9, *) {}
for:

  • CKOwnerDefaultName in QSCloudKitSynchronizer+CoreData.m - row 43
CK_EXTERN NSString * const CKCurrentUserDefaultName API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0));
CK_EXTERN NSString * const CKOwnerDefaultName API_DEPRECATED_WITH_REPLACEMENT("CKCurrentUserDefaultName", macos(10.10, 10.12), ios(8.0, 10.0), tvos(9.0, 10.0), watchos(3.0, 3.0));
  • CKFetchRecordChangesOperation in QSCloudKitSynchronizer.m - row 494 and 565
API_DEPRECATED_WITH_REPLACEMENT("CKFetchRecordZoneChangesOperation", macos(10.10, 10.12), ios(8.0, 10.0), tvos(9.0, 10.0), watchos(3.0, 3.0))

one more in QSManagedObjectContext.m

(void)performBlock:(void(^)())block
{
    [self performBlockAndWait:block];
}
Conflicting parameter types in implementation of 'performBlock:': 'void (^ _Nonnull __strong)(void)' vs 'void (^__strong _Nonnull)()'

objects disappear on Device B if app is deleted on Device A

  • Device A has objects: Obj1, Obj2
  • Device B has objects: Obj3, Obj4
  • sync downloads Obj1, Ob2, on Device B and sync downloads Obj3, Obj4 on Device A
  • user deletes App on Device A
  • at next sync on Device B Obj1 and Obj2 disappear, but they should stay, shouldn't?

QSChangemanager missing CoreData Sync

Hi,

I've just updated from 0.5.8 to 0.6.5 pod, but I checked, and from 0.6.0 the QSChangeManager.h is missing. It causes more problems - see attachements.
I can not find any references to this update or at Core data migration in the readme.

Did you intent to remove it, and there is a new way to check the changes, or it was a coincidence? If the latter, could you put it back?

Thank you,

Eva

screenshot 2018-10-09 at 16 18 16
screenshot 2018-10-09 at 16 16 29
screenshot 2018-10-09 at 16 17 34

Merge/Modify coreData after didImportChanges

Hi, after sync cloudKit synkKit sdk call delegate method from QSCoreDataChangeManagerDelegate

  • (void)changeManager:(QSCoreDataChangeManager *)changeManager didImportChanges:(NSManagedObjectContext *)importContext completion:(void(^)(NSError *error))completion

and

  • (void)changeManagerRequestsContextSave:(QSCoreDataChangeManager *)changeManager completion:(void(^)(NSError *error))completion

inside didImportChanges: i have logic saving managedObjecContext and I have case where logic change/delete data if need for my CoreData. And I have problem - because after that action - result incorrent CoreData Object QSSyncedEntity inside synkKit and incorrent data to CloudKit

For example:

  • (void)changeManager:(QSCoreDataChangeManager *)changeManager didImportChanges:(NSManagedObjectContext *)importContext completion:(void(^)(NSError *error))completion
    {
    __block NSError *error = nil;
    [importContext performBlockAndWait:^{
    [importContext save:&error];
    }];

    if (!error)
    {
    [[NSManagedObjectContext MR_rootSavingContext] MR_saveToPersistentStoreAndWait];

    //any action delete my entity
    

    [[NSManagedObjectContext MR_contextForCurrentThread] MR_saveToPersistentStoreAndWait];
    }
    }

After this code, SyncKit don't correct detection removed entity and CloudKit get incorrect data and problem with sync for other device by single icloud account.

SyncKit has condition like self.isMergingImportedChanges == NO then don't logic sync QSSyncedEntity entity - but maybe it's my problem

Tell me please, some best practice or instruction how modify coreData after response sync cloudKit and sync again with new data with corrent sync/merge local entity SyncKit sdk

In general sutation, when I modify entity on mainThread and call synchronizeWithCompletion - I don't have problem - good local sync QSSyncedEntity entity and cloudKit data - only if I modify data inside
didImportChanges method

circular reference : upload large amount of data failed (but download ok)

I have a data model with circular references like this:
image

SyncKit is working fine with this model, except when I try to sync (upload) more than 100 records to CloudKit at the same time. It is not a issue when the games and scores are created and synced as you go, but it fail with an imported group with large amount of data.
I know I can increase the limit near 400 but no more...

Which is weird, when I sync the same huge group (created ans synced as you go) from CloudKit to another empty device all is working fine! (502 records in my case).

Can you tell me if is it an issue with SyncKit implementation or the cause of different behavior of CloudKit when downloading or uploading data ?

Is it works with iOS 10+ ?

Hi,

First of all: it's awesome library!๐ŸŽ‰

I have question: is it works with iOS 10 and latest iCloud deprecations for CoreData?

Limit exceeded error from CloudKit

Hi

I'm using SyncKit for synchronising a local Core Data model into iCloud. SyncKit has proven to be very stable and reliable. Great job on that.

I had one persistent issue on 1 device that was getting error due to 'Limit Exceeded'.
It turned out about 200 records were not being synced anymore after having added many records off-line.

After investigation I could fix this issue by manually changing the default batchSize from 100 to 20.
static const NSInteger QSDefaultBatchSize = 20; //WAS 100;

I noticed that SyncKit has a feature to automatically reduce the batchSize in case of LimitExceeded.
This was clearly not working for some reason. Or maybe I don't fully get the implementation details.

          if (operationError.code == CKErrorLimitExceeded) {
                self.batchSize = self.batchSize / 2;
                ...

I'm using SyncKit 0.5.5.

Hopefully this is helpful for you to further improve SyncKit.

regards
Rodge

Below the (partial) stack trace:

Synchronize ERROR
Optional(<CKError 0x1c4459980: "Partial Failure" (2/1011); "Failed to modify some records"; uuid = 03CAFB05-9A39-41F8-B7C6-71ADB20B8B02; container ID = "iCloud.com.myapp"; partial errors: {
Parent.70B5CA5C-D5EF-4CDC-AD2B-33AF95298ED6-1149-00000548904E7DEC:(QSCloudKitCustomZoneName:defaultOwner) = <CKError 0x1c8442e20: "Limit Exceeded" (27/2023); server message = "Database commit size exceeds limit"; uuid = 03CAFB25-9A39-41F8-B7D6-31ADB20D8B02>
Child.E91E0362-59A3-43B8-8136-0116B2145DBB-1129-0000059A7379915C:(QSCloudKitCustomZoneName:defaultOwner) = <CKError 0x1c8444f80: "Limit Exceeded" (27/2023); server message = "Database commit size exceeds limit"; uuid = 03CAAB05-9A29-4BF8-B7C6-71ADB90B8B02>

Synchronization from extensions duplicates all records

I've just stumbled upon an issue where synchronization from extensions (Today Extensions in this case) results in the database being duplicated entirely then synchronized to iCloud. When I check the object IDs of the newly created duplicates they read differently than the originals. Originally the extensions were designed using AppGroups so they could access the same CoreData stack as my application. I wanted the extensions to be able to sync when they load so if new data was generated on another device and not currently synced to the one viewing the extension, it would reload with the new data. The extensions set the QSCloudKitSynchronizer to download only, so i'm thinking that when they run they're downloading records and assigning them new objectIDs and storing them in the shared data store. Then whenever the application opens next it synchronizes these new records to CloudKit resulting in the other connected devices downloading the records.

Am I right in interpreting this as a bug or is this an error in my understanding of iOS extensions/SyncKit?

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

I tried to follow the example and implement a similar code but whenever i click on the share button, I get an error saying Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value on the
`
// MARK: - Sync

func synchronize(completion: ((Error?)->())?) {
    
    showLoading(true)


    synchronizer.synchronize { [weak self] (error) in // ERROR LINE

......
` any reason for this error?

Memory leak in QSFetchZoneChangesOperation.swift

When running with Instruments, they show quite a lot memory leaks. As far as I can tell, they originated from QSFetchZoneChangesOperation.swift. It seems that QSFetchZoneChangesOperation has a strong pointer to CKFetchRecordZoneChangesOperation and CKFetchRecordZoneChangesOperation has a strong pointer to QSFetchZoneChangesOperation in one (or several) of the blocks (completions). And ARC cannot release them. If I add
self.operation = nil
at the end of operation.fetchRecordZoneChangesCompletionBlock:

                if let error = operationError {
                    self.finish(error: error)
                } else if higherModelVersionFound {
                    self.finish(error: NSError(domain: QSCloudKitSynchronizerErrorDomain, code: QSCloudKitSynchronizerErrorCode.higherModelVersionFound.rawValue, userInfo: nil))
                } else if self.isCancelled {
                    self.finish(error: NSError(domain: QSCloudKitSynchronizerErrorDomain, code: QSCloudKitSynchronizerErrorCode.cancelled.rawValue, userInfo: nil))
                } else {
                    self.completion(self.zoneResults)
                    self.finish(error: nil)
                }
                self.operation = nil

then Instruments don't show leaks anymore during fetching changes from cloudkit. Not 100% sure if a pointer to operation is still needed there (my guess is that it is not). So, if not, I suppose that could be a fix for these leaks.

New case about CKErrorUserDeletedZone

Hello, sometimes user delete icloud data from general device settings. After that action I call synchronizeWithCompletion and I have error CKErrorUserDeletedZone. I call eraseLocal or eraseRemoteAndLocalDataWithCompletion then again repeat synchronizeWithCompletion and I again have CKErrorUserDeletedZone - and so endlessly.

I study code in library and I think in setupCustomZoneWithCompletion to need add condition instead

else if (error.code == CKErrorZoneNotFound && ... to else if ((error.code == CKErrorZoneNotFound || error.code == CKErrorUserDeletedZone) && ...

After that I get reinitialize and new working customZone without errors

What do you think about it?

Error after pod install

Errors after installing via pod pod 'SyncKit/RealmSwift', '~> 0.6.4'

'Participant' is not a member type of 'CKShare'
CKRecordZone.ID gives'ID' is not a member type of 'CKRecord' etc i got over 30 errors. Any reason for this happening?

Public Database sync

Would it be possible for you to add support for synchronising PUBLIC databases?

I am using RealmSwift for local data storage.

The use case I have is that my app has private data AND public data.

Currently I am achieving this using 2 Realms which is a nice separation but causes issues when relating data across realms.

In my idealised world..... I would love to only require one single Realm and know that SyncKit is processing specific models to PRIVATE and other models to PUBLIC. A big ask I know. Maybe adding a property to specific models could detail to SyncKit how to process that model? All that said - I'd be happy with syncing 2 Realms one for each PRIVATE and PUBLC data.

Thanks! Keep up the good work.

[RLMProperty array]: unrecognized selector sent to instance 0x1c40abac0

got this issue when fetching data

QSRealmChangeManager.m

} else {

    for (RLMProperty *property in object.objectSchema.properties) {
        if ([self shouldIgnoreKey:property.name]) {
            continue;
        }
        if (property.array || property.type == RLMPropertyTypeLinkingObjects) {
            continue;
        }
        
        [self applyChangeForProperty:property.name inRecord:record toObject:object withSyncedEntity:syncedEntity realmProvider:provider];
    }
}

is there any situation? thanks!!

Syncing NSTransformableAttributeType

My core data model uses transformable attributes. I was not being able to sync them using the current SyncKit code. (Probably because they contained some type of objects, that CKRecord does not support, such as NSPredicate). With the modifications below I am being able to sync them. So, I suggest/ask adding such addition in the future to support them. Unless you see any problems with it:
- (CKRecord *)recordToUploadForSyncedEntity:(QSSyncedEntity *)entity context:(NSManagedObjectContext *)objectContext

                else if (attributeDescription.attributeType == NSTransformableAttributeType)
                 {
                     NSData *encodedValue = nil;
                     if (value)
                     {
                         encodedValue = [NSKeyedArchiver archivedDataWithRootObject:value];
                     }
                     record[attributeName] = encodedValue;
                 }

and in the
- (void)assignAttributeValue:(id)value toManagedObject:(NSManagedObject *)object attributeName:(NSString *)attributeName

    else if (object.entity.attributesByName[attributeName].attributeType == NSTransformableAttributeType)
     {
         NSData *decodedValue = nil;
         if (value)
         {
             decodedValue = [NSKeyedUnarchiver unarchiveObjectWithData:value];
         }
         [object setValue:decodedValue forKey:attributeName];
     }

Crash on first synchronize: PendingRelationship

As soon as I run I'm seeing a crash in realmObjectClass(), line 212. As far as I can tell it's because SyncKit added PendingRelationship to the schema, but because that's not a class in my namespace, NSClassFromString fails in both invocations. I'm not sure what the code is trying to do here, but I think you either need to not force-unwrap here, check against your module's namespace, or not add stuff to the same Realm I'm using. I think I remember seeing something about two different realms in the header for QSRealmChangeManager, but I don't see anything using it in the SyncKitRealm sample project.

Partial backtrace:

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 9.1
  * frame #0: 0x000000010687c32d SyncKitRealmSwift`specialized RealmSwiftChangeManager.realmObjectClass(name:) at RealmSwiftChangeManager.swift:208 [opt]
    frame #1: 0x000000010687107c SyncKitRealmSwift`RealmSwiftChangeManager.setup() [inlined] SyncKitRealmSwift.RealmSwiftChangeManager.realmObjectClass(name: Swift.String) -> RealmSwift.Object.Type at RealmSwiftChangeManager.swift:0 [opt]
    frame #2: 0x000000010687106e SyncKitRealmSwift`RealmSwiftChangeManager.setup(self=0x00007f94d20089f0) at RealmSwiftChangeManager.swift:123 [opt]
    frame #3: 0x000000010687003d SyncKitRealmSwift`RealmSwiftChangeManager.init(persistenceRealmConfiguration=RealmSwift.Realm.Configuration @ 0x00007f8a75c853a0, targetRealmConfiguration=<unavailable>, recordZoneID=<unavailable>) at RealmSwiftChangeManager.swift:95 [opt]
    frame #4: 0x000000010688b0f0 SyncKitRealmSwift`static QSCloudKitSynchronizer.cloudKitSynchronizer(containerName:configuration:suiteName:) [inlined] SyncKitRealmSwift.RealmSwiftChangeManager.__allocating_init(persistenceRealmConfiguration: RealmSwift.Realm.Configuration, targetRealmConfiguration: RealmSwift.Realm.Configuration, recordZoneID: __ObjC.CKRecordZoneID) -> SyncKitRealmSwift.RealmSwiftChangeManager at QSCloudKitSynchronizer+RealmSwift.swift:0 [opt]

Random records aren't downloaded on initial sync

Hello!

Thank you for the amazing library - it makes work with iCloud and CoreData much simpler!

One issue that I'm facing right now and can't find any solutions for couple of weeks:
On initial sync some of records aren't downloaded sometimes. I thought that there is something wrong with specific records but it happens with random records every time. 1 / 3 times everything is downloaded successfully. Can't figure out any dependencies because data is always the same.

Could it be something related to iCloud itself? or iOS 11?

I didn't find any problems in logs but for some reason it downloads 39 records, then 1, then 1 again, then it starts downloading by 200.

Thank you!
Alex

Logs:

2017-08-10 21:21:26.219929-0700 LifeWheel[45920:2988199] <0x6040000e5a00 QSCloudKitSynchronizer.m:(147)> QSCloudKitSynchronizer >> Initiating synchronization
2017-08-10 21:21:26.252758-0700 LifeWheel[45920:2988199] ERROR: Error registering for Apple push notifications. Error: Error Domain=NSCocoaErrorDomain Code=3010 "remote notifications are not supported in the simulator" UserInfo={NSLocalizedDescription=remote notifications are not supported in the simulator}
2017-08-10 21:21:26.569576-0700 LifeWheel[45920:2988336] <0x6040000e5a00 QSCloudKitSynchronizer.m:(103)> QSCloudKitSynchronizer >> Fetched custom record zone
2017-08-10 21:21:27.882957-0700 LifeWheel[45920:2988337] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:27.883370-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:28.372776-0700 LifeWheel[45920:2988337] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:28.373316-0700 LifeWheel[45920:2988350] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:28.867300-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:28.867607-0700 LifeWheel[45920:2988337] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:29.301462-0700 LifeWheel[45920:2988338] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 39 changes
2017-08-10 21:21:29.301820-0700 LifeWheel[45920:2988338] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:29.302478-0700 LifeWheel[45920:2988350] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:29.726164-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:29.726497-0700 LifeWheel[45920:2988338] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:30.226449-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:30.228772-0700 LifeWheel[45920:2988338] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:30.659741-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:30.660117-0700 LifeWheel[45920:2988339] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:31.119141-0700 LifeWheel[45920:2988338] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:31.119616-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:31.635418-0700 LifeWheel[45920:2988350] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 1 changes
2017-08-10 21:21:31.635626-0700 LifeWheel[45920:2988338] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:31.636077-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:32.132447-0700 LifeWheel[45920:2988350] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 1 changes
2017-08-10 21:21:32.132733-0700 LifeWheel[45920:2988350] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:32.133629-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:33.117638-0700 LifeWheel[45920:2988336] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 200 changes
2017-08-10 21:21:33.117773-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:33.212044-0700 LifeWheel[45920:2988337] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:33.866325-0700 LifeWheel[45920:2988338] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 200 changes
2017-08-10 21:21:33.866528-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:33.958965-0700 LifeWheel[45920:2988350] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:34.582547-0700 LifeWheel[45920:2988338] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 200 changes
2017-08-10 21:21:34.582785-0700 LifeWheel[45920:2988338] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:34.672276-0700 LifeWheel[45920:2988339] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:35.264128-0700 LifeWheel[45920:2988336] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 200 changes
2017-08-10 21:21:35.264366-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:35.359592-0700 LifeWheel[45920:2988338] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:36.004343-0700 LifeWheel[45920:2988338] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 200 changes
2017-08-10 21:21:36.004583-0700 LifeWheel[45920:2988350] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:36.127370-0700 LifeWheel[45920:2988339] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:36.730105-0700 LifeWheel[45920:2988339] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 200 changes
2017-08-10 21:21:36.730355-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:36.829979-0700 LifeWheel[45920:2988339] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:37.494185-0700 LifeWheel[45920:2988342] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 200 changes
2017-08-10 21:21:37.494476-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:37.611796-0700 LifeWheel[45920:2988339] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:38.134295-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(598)> Target apply pending relationships
2017-08-10 21:21:38.529987-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(932)> Requesting save
2017-08-10 21:21:38.532562-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(938)> Saved. Now importing.
2017-08-10 21:21:38.644975-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(941)> Saved imported changes
2017-08-10 21:21:38.801314-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(898)> QSCloudKitSynchronizer >> Tracking 0 insertions
2017-08-10 21:21:38.801587-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(899)> QSCloudKitSynchronizer >> Tracking 0 updates
2017-08-10 21:21:38.802031-0700 LifeWheel[45920:2988342] <0x60400028c7b0 QSCoreDataChangeManager.m:(900)> QSCloudKitSynchronizer >> Tracking 0 deletions
2017-08-10 21:21:39.826305-0700 LifeWheel[45920:2988339] <0x6040000e5a00 QSCloudKitSynchronizer.m:(571)> QSCloudKitSynchronizer >> Detected changes after synchronization. Initiating sync
2017-08-10 21:21:40.593819-0700 LifeWheel[45920:2988336] <0x6040000e5a00 QSCloudKitSynchronizer.m:(520)> QSCloudKitSynchronizer >> Downloaded 165 changes
2017-08-10 21:21:40.593968-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(968)> Save changes in records
2017-08-10 21:21:40.683029-0700 LifeWheel[45920:2988339] <0x60400028c7b0 QSCoreDataChangeManager.m:(1011)> Applying attribute changes in records
2017-08-10 21:21:40.771914-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(598)> Target apply pending relationships
2017-08-10 21:21:40.819083-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(932)> Requesting save
2017-08-10 21:21:40.821241-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(938)> Saved. Now importing.
2017-08-10 21:21:40.841544-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(941)> Saved imported changes
2017-08-10 21:21:40.861119-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(898)> QSCloudKitSynchronizer >> Tracking 0 insertions
2017-08-10 21:21:40.861804-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(899)> QSCloudKitSynchronizer >> Tracking 0 updates
2017-08-10 21:21:40.862361-0700 LifeWheel[45920:2988336] <0x60400028c7b0 QSCoreDataChangeManager.m:(900)> QSCloudKitSynchronizer >> Tracking 0 deletions
2017-08-10 21:21:41.124009-0700 LifeWheel[45920:2988336] <0x6040000e5a00 QSCloudKitSynchronizer.m:(329)> QSCloudKitSynchronizer >> Finishing synchronization

Deleted zone

Not sure if I am doing something wrong or SyncKit cannot handle deleted record zone (at least in some cases). There are several zones in my cloudkit container (not only the ones that are being used by syncKit), so after deleting the zone that was used by SyncKit, I cannot successfully make synchronization anymore. Should I make some specific actions in this case?

As far as I can see - there is setupRecordZoneIfNeeded method, but its not being called if changedZoneIDs.count > 0 in the fetchDatabaseChangesWithCompletion method. I think another check for the empty array after getting toFetchZoneIDs could fix the problem:

            if (changedZoneIDs.count) {
...                
                if (toFetchZoneIDs.count)
                {
...
                }
                else
                {
                    callBlockIfNotNil(completion, databaseToken, nil);
                }
            } else {
                callBlockIfNotNil(completion, databaseToken, nil);
            }

Without it the sync process will not go to the setupRecordZoneIfNeeded method, but just ends in the fetch changes step with the cloudKit error, something like no zoneIDs given to fetchChangesOperation.

Or maybe there is something else that I should do in such case?

change PrimaryKey attribute - handle with ObjectID

If primaryKey attribute changes, SyncKit can't identify the origin Object in CloudKit. Now QSSyncedEntity has an attribute originObjectID, which keep the origin ObjectID, or the primaryKey. It should be 2 different attributes, one for the objectID originObjectID which handle the primaryKey or the origin ObjectID as now, and one for keeping the origin ObejcID originManagedObjectID.

And if primaryKey attribute is not nil, than ChangeManager should use it as now here:

- (QSSyncedEntity *)createSyncedEntityForRecord:(CKRecord *)record 
       NSManagedObject *object = [self insertManagedObjectWithEntityName:entityName];
        if ([self useUniqueIdentifierForEntityWithType:entityName]) {
            objectID = [self uniqueIdentifierForObjectFromRecord:record];
            [object setValue:objectID forKey:[self identifierFieldNameForEntityOfType:entityName]];
        } else {
            objectID = [object.objectID.URIRepresentation absoluteString];
        }
 syncedEntity.originObjectID = objectID;

but it should add the new attribute, to not losing the origin ObjectID:

syncedEntity.originManagedObjectID = [object.objectID.URIRepresentation absoluteString];

At the updating method, we could create 2 NSMutableArray for the IDs. The first, as now for the originObjectIDs, and the second for the originManagedObjectID.

- (void)targetContextDidSave:(NSNotification *)notification
        ....
        NSMutableArray *updatedIDs = [NSMutableArray array];
        NSMutableArray *updatedID2s = [NSMutableArray array];
        for (NSManagedObject *updatedObject in updated) {
            NSString *identifier = [self uniqueIdentifierForObject:updatedObject];
            [updatedIDs addObject:identifier];
            [updatedID2s addObject:updatedObject.originManagedObjectID] ;
        }

And if the entity is nil with primaryKey enumeration, then we can call the updatedID2s:

- (QSSyncedEntity *)syncedEntityWithOriginManagedObjectIdentifier:(NSString *)objectIdentifier
{
    NSError *error = nil;
    NSArray *fetchedObjects = [self.privateContext executeFetchRequestWithEntityName:@"QSSyncedEntity"
                                                                           predicate:[NSPredicate predicateWithFormat:@"originManagedObjectID == %@", objectIdentifier]
                                                                               error:&error];
    return [fetchedObjects firstObject];
}
[updatedIDs enumerateObjectsUsingBlock:^(NSString * _Nonnull objectIdentifier, NSUInteger idx, BOOL * _Nonnull stop) {
                QSSyncedEntity *entity = [self syncedEntityWithOriginObjectIdentifier:objectIdentifier];
                DLog(@"entity %@", entity);
                if(!entity){
                    DLog(@"entity nil");
                    [updatedID2s enumerateObjectsUsingBlock:^(NSString * _Nonnull objectIdentifier, NSUInteger idx, BOOL * _Nonnull stop) {
                        QSSyncedEntity *entity = [self syncedEntityWithOriginManagedObjectIdentifier:objectIdentifier];
                        DLog(@"updatedID2s entity %@", entity);
                        if ([entity.state integerValue] == QSSyncedEntityStateSynced && entity.changedKeys.length) {
                            entity.state = @(QSSyncedEntityStateChanged);
                        }
                        entity.updated = [NSDate date];
                    }];

                }else{
                    DLog(@"entity not nil");
                    if ([entity.state integerValue] == QSSyncedEntityStateSynced && entity.changedKeys.length) {
                        entity.state = @(QSSyncedEntityStateChanged);
                    }
                    entity.updated = [NSDate date];
                }
            }];

But with this method, we should change the QSSyncedEntity CroeData Property list. And I'm not sure how this will affect the entire database in Cloudkit.

custom zone name

Would it be possible to support custom zone names? Right now synchronizer creates default QS... zone and I don't see a way to customise it. Or is there any that I miss?
My suggestion would be an initialiser with one more parameter:
+ (QSCloudKitSynchronizer *)cloudKitPrivateSynchronizerWithContainerName:(NSString *)containerName managedObjectContext:(NSManagedObjectContext *)context suiteName:(NSString *)suiteName recordZoneID:(CKRecordZoneID *)recordZoneID;

restore from iCloud backup

Hi, I think there is problem. For example: I use app on device 1 with SyncKit and CoreData informartion with icloud. Device 1 has SyncKit deviceIdentifier "abcdefguniqid". Next, on device 1 on settings I press iCloud Backup Now. Next, I take Device 2 and setup restore icloud back up data from Device 1. Next, Device 2 has same (copy) userDefaults and other documents, also has same (copy) deviceIdentifier as "abcdefguniqid". So Device 1 and Device 2 have the same deviceIdentifier and I think it is big problem, because Device 1 and Device 2 generate unique data, but they don't sync, because logic from SyncKit think it's one device and work uncorrectly. What do you think about it?

My opinion: SyncKit deviceIdentifier must unique on each device, but need logic generated unique deviceIdentifier without reference to the saved earlier deviceIdentifier or something else.

Does SyncKit have some logic for decide this situation?

Performance of storing object notification for every object in Realm?

This is a fantastic library and will certainly go a long way toward helping me implement sync. I understand why Realm's collection notifications are not detailed enough to support the QSRealmChangeManager. However, it seems a little inelegant to register an object notification for every object managed by the Realm and keep them all in NSMutableDictionary *objectNotificationTokens. This looks like the best option, but I'm wondering, have you seen any performance issues with this?

Pod install

using pod 'SyncKit/Realm', '~> 0.6.4'gives and error in my terminal and I cannot install

`Analyzing dependencies
[!] CocoaPods could not find compatible versions for pod "SyncKit/Realm":
In Podfile:
SyncKit/Realm (~> 0.6.4)

None of your spec sources contain a spec satisfying the dependency: SyncKit/Realm (~> 0.6.4).

You have either:

  • out-of-date source repos which you can update with pod repo update or with pod install --repo-update.
  • mistyped the name or version.
  • not added the source repo that hosts the Podspec to your Podfile.

Note: as of CocoaPods 1.0, pod repo update does not happen on pod install by default.
`

Carthage installation fails

I'm currently using Xcode 10 beta and when I try to install SyncKit, I get this error:

Build Failed
	Task failed with exit code 65:
	/usr/bin/xcrun xcodebuild -workspace /Users/Harish/Desktop/Aerivo/Carthage/Checkouts/SyncKit/Example/RealmSwift/SyncKitRealmSwift.xcworkspace -scheme SyncKitRealmSwiftiOS -configuration Release -derivedDataPath /Users/Harish/Library/Caches/org.carthage.CarthageKit/DerivedData/10.0_10L221o/SyncKit/0.6.3 -sdk iphoneos ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES archive -archivePath /var/folders/85/06g7yyx16r553gbdgy5dmd600000gn/T/SyncKit SKIP_INSTALL=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=NO CLANG_ENABLE_CODE_COVERAGE=NO STRIP_INSTALLED_PRODUCT=NO (launched in /Users/Harish/Desktop/Aerivo/Carthage/Checkouts/SyncKit)

This usually indicates that project itself failed to compile. Please check the xcodebuild log for more details: /var/folders/85/06g7yyx16r553gbdgy5dmd600000gn/T/carthage-xcodebuild.IBMRF5.log

I need only to download content from iCloud

Hi,
SyncKIt made my work easy.
I see upload and download happens with same call back. How can i only download data from iCloud?

I don't want to upload to iCloud. Upload will happen from other device.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.