Skip to content

Commit

Permalink
Merge branch 'release/3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
deeje committed Aug 20, 2019
2 parents b0b874e + a9b2157 commit 592529a
Show file tree
Hide file tree
Showing 19 changed files with 64 additions and 47 deletions.
1 change: 0 additions & 1 deletion .swift-version

This file was deleted.

6 changes: 3 additions & 3 deletions CloudCore.podspec
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Pod::Spec.new do |s|
s.name = "CloudCore"
s.summary = "Framework that enables synchronization between CloudKit (iCloud) and Core Data."
s.summary = "Framework that enables synchronization between CloudKit and Core Data."
s.version = "3.0"
s.homepage = "https://github.com/deeje/CloudCore"
s.license = 'MIT'
s.author = { "Vasily Ulianov" => "vasily@me.com", "deeje" => "deeje@mac.com" }
s.author = { "deeje" => "deeje@mac.com", "Vasily Ulianov" => "vasily@me.com" }
s.source = {
:git => "https://github.com/deeje/CloudCore.git",
:tag => s.version.to_s
Expand All @@ -20,6 +20,6 @@ Pod::Spec.new do |s|
s.ios.frameworks = 'Foundation', 'CloudKit', 'CoreData'
s.osx.frameworks = 'Foundation', 'CloudKit', 'CoreData'

s.pod_target_xcconfig = { 'SWIFT_VERSION' => '4.2' }
s.pod_target_xcconfig = { 'SWIFT_VERSION' => '5.0' }
s.documentation_url = 'http://cocoadocs.org/docsets/CloudCore/'
end
14 changes: 6 additions & 8 deletions CloudCore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -623,14 +623,14 @@
};
E29BB2271E436F310020F5B6 = {
CreatedOnToolsVersion = 8.2.1;
LastSwiftMigration = 0900;
LastSwiftMigration = 1030;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = D5B2E8991C3A780C00C0327D /* Build configuration list for PBXProject "CloudCore" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Expand Down Expand Up @@ -934,7 +934,7 @@
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
TVOS_DEPLOYMENT_TARGET = 10.0;
WATCHOS_DEPLOYMENT_TARGET = 3.0;
};
Expand All @@ -958,7 +958,7 @@
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
TVOS_DEPLOYMENT_TARGET = 10.0;
WATCHOS_DEPLOYMENT_TARGET = 3.0;
};
Expand Down Expand Up @@ -1078,8 +1078,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
Expand All @@ -1097,8 +1096,7 @@
PRODUCT_BUNDLE_IDENTIFIER = uvasily.CloudCoreTests;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 5.0;
};
name = Release;
};
Expand Down
15 changes: 9 additions & 6 deletions Example/CloudCoreExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,13 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0820;
LastUpgradeCheck = 1010;
LastUpgradeCheck = 1030;
ORGANIZATIONNAME = "Vasily Ulianov";
TargetAttributes = {
E2C3E34F1E53299800A733BF = {
CreatedOnToolsVersion = 8.2.1;
DevelopmentTeam = 26Y8AQV29F;
LastSwiftMigration = 1010;
LastSwiftMigration = 1030;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.BackgroundModes = {
Expand All @@ -214,6 +214,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
Expand Down Expand Up @@ -265,7 +266,7 @@
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-CloudCoreExample/Pods-CloudCoreExample-frameworks.sh",
"${PODS_ROOT}/Target Support Files/Pods-CloudCoreExample/Pods-CloudCoreExample-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/CloudCore/CloudCore.framework",
"${BUILT_PRODUCTS_DIR}/Fakery/Fakery.framework",
"${BUILT_PRODUCTS_DIR}/ReachabilitySwift/Reachability.framework",
Expand All @@ -278,7 +279,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CloudCoreExample/Pods-CloudCoreExample-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CloudCoreExample/Pods-CloudCoreExample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
Expand Down Expand Up @@ -327,6 +328,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
Expand Down Expand Up @@ -384,6 +386,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
Expand Down Expand Up @@ -442,7 +445,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
Expand All @@ -458,7 +461,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
SWIFT_VERSION = 5.0;
};
name = Release;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
LastUpgradeVersion = "1030"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
8 changes: 6 additions & 2 deletions Example/Sources/Class/FRCTableViewDataSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ class FRCTableViewDataSource<FetchRequestResult: NSFetchRequestResult>: NSObject
case .delete: tableView?.deleteSections(sectionIndexSet, with: .automatic)
case .update: tableView?.reloadSections(sectionIndexSet, with: .automatic)
case .move: break
}
@unknown default:
break
}
}

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
Expand All @@ -88,7 +90,9 @@ class FRCTableViewDataSource<FetchRequestResult: NSFetchRequestResult>: NSObject
case .move:
guard let indexPath = indexPath, let newIndexPath = newIndexPath else { return }
tableView?.moveRow(at: indexPath, to: newIndexPath)
}
@unknown default:
break
}
}

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
Expand Down
4 changes: 2 additions & 2 deletions Example/Sources/View Controller/DetailViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class DetailViewController: UITableViewController {
moc.name = CloudCore.config.pushContextName

let employee = ModelFactory.insertEmployee(context: moc)
let organization = try? moc.existingObject(with: self.organizationID) as! Organization
let organization = try? moc.existingObject(with: self.organizationID) as? Organization
employee.organization = organization

try? moc.save()
Expand All @@ -51,7 +51,7 @@ class DetailViewController: UITableViewController {
persistentContainer.performBackgroundTask { (moc) in
moc.name = CloudCore.config.pushContextName

let organization = try? moc.existingObject(with: self.organizationID) as! Organization
let organization = try? moc.existingObject(with: self.organizationID) as? Organization
organization?.name = newTitle

try? moc.save()
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ At WWDC 2019, Apple announced support for NSPersistentCloudKitContainer in iOS 1
* Offline Synchronization is opaque, but doesn't appear to require NSPersistentHistoryTracking
* All Core Data names are preceeded with "CD_" in CloudKit
* Core Data Relationships are mapped thru CDMR records in CloudKit
* Uses a specific custom zone in the Private Database

###### CloudCore
* Support requires specific configuration in the Core Data Model
Expand Down
7 changes: 3 additions & 4 deletions Source/Classes/CloudCore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,7 @@ open class CloudCore {
- completion: `PullResult` enumeration with results of operation
*/
public static func pull(using userInfo: NotificationUserInfo, to container: NSPersistentContainer, error: ErrorBlock?, completion: @escaping (_ fetchResult: PullResult) -> Void) {
let notification = CKNotification(fromRemoteNotificationDictionary: userInfo)

guard let cloudDatabase = self.database(for: notification) else {
guard let notification = CKNotification(fromRemoteNotificationDictionary: userInfo), let cloudDatabase = self.database(for: notification) else {
completion(.noData)
return
}
Expand Down Expand Up @@ -176,7 +174,8 @@ open class CloudCore {
- Returns: `true` if notification contains CloudCore data
*/
public static func isCloudCoreNotification(withUserInfo userInfo: NotificationUserInfo) -> Bool {
let notification = CKNotification(fromRemoteNotificationDictionary: userInfo)
guard let notification = CKNotification(fromRemoteNotificationDictionary: userInfo) else { return false }

return (database(for: notification) != nil)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class PublicDatabaseSubscriptions {
// - completion: returns subscriptionID and error upon operation completion
static public func subscribe(recordType: String, predicate: NSPredicate, completion: ((_ subscriptionID: String, _ error: Error?) -> Void)?) {
let id = prefix + recordType + "-" + predicate.predicateFormat
if self.cachedIDs.index(of: id) != nil { return }
if self.cachedIDs.firstIndex(of: id) != nil { return }

let options: CKQuerySubscription.Options = [.firesOnRecordCreation, .firesOnRecordUpdate, .firesOnRecordDeletion]
let subscription = CKQuerySubscription(recordType: recordType, predicate: predicate, subscriptionID: id, options: options)
Expand Down Expand Up @@ -55,7 +55,7 @@ public class PublicDatabaseSubscriptions {
let operation = CKModifySubscriptionsOperation(subscriptionsToSave: [], subscriptionIDsToDelete: [subscriptionID])
operation.modifySubscriptionsCompletionBlock = { _, _, error in
if error == nil {
if let index = self.cachedIDs.index(of: subscriptionID) {
if let index = self.cachedIDs.firstIndex(of: subscriptionID) {
self.cachedIDs.remove(at: index)
}
}
Expand Down
3 changes: 3 additions & 0 deletions Source/Classes/Push/CoreDataObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ class CoreDataObserver {
deletedRecordIDs.append(recordIDWithDatabase)
}
}

default:
break
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@ class ObjectToRecordConverter {
guard let serviceAttributeNames = object.entity.serviceAttributeNames else { continue }

for scope in serviceAttributeNames.scopes {
if let triedRestoredRecord = try? object.restoreRecordWithSystemFields(for: scope),
let restoredRecord = triedRestoredRecord {
if let restoredRecord = try? object.restoreRecordWithSystemFields(for: scope) {
let targetScope = self.targetScope(for: scope, and: object)
let database = self.database(for: targetScope)
let recordIDWithDB = RecordIDWithDatabase(restoredRecord.recordID, database)
Expand Down
4 changes: 3 additions & 1 deletion Source/Classes/Push/PushOperationQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ class PushOperationQueue: OperationQueue {
private func removeCachedAssets(for record: CKRecord) {
for key in record.allKeys() {
guard let asset = record.value(forKey: key) as? CKAsset else { continue }
try? FileManager.default.removeItem(at: asset.fileURL)
if let url = asset.fileURL {
try? FileManager.default.removeItem(at: url)
}
}
}

Expand Down
13 changes: 10 additions & 3 deletions Source/Model/CloudKitAttribute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ class CloudKitAttribute {

func makeCoreDataValue() throws -> Any? {
switch value {
case let reference as CKRecord.Reference: return try findManagedObject(for: reference.recordID)
case let reference as CKRecord.Reference:
return try findManagedObject(for: reference.recordID)

case let references as [CKRecord.Reference]:
let managedObjects = NSMutableSet()
for ref in references {
Expand All @@ -41,8 +43,13 @@ class CloudKitAttribute {

if managedObjects.count == 0 { return nil }
return managedObjects
case let asset as CKAsset: return try Data(contentsOf: asset.fileURL)
default: return value

case let asset as CKAsset:
guard let url = asset.fileURL else { return nil }
return try Data(contentsOf: url)

default:
return value
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ class CoreDataAttributeTests: CoreDataTestCase {
do {
// External binary
if let recordExternalValue = try externalAttribute?.makeRecordValue() as? CKAsset {
let recordData = try Data(contentsOf: recordExternalValue.fileURL)
let recordData = try Data(contentsOf: recordExternalValue.fileURL!)
XCTAssertEqual(recordData, externalData)
} else {
XCTFail("External binary isn't stored correctly")
}

// External big binary
if let recordExternalValue = try externalBigAttribute?.makeRecordValue() as? CKAsset {
let recordData = try Data(contentsOf: recordExternalValue.fileURL)
let recordData = try Data(contentsOf: recordExternalValue.fileURL!)
XCTAssertEqual(recordData, externalBigData)
} else {
XCTFail("External big binary isn't stored correctly")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class CoreDataRelationshipTests: CoreDataTestCase {
let filledObjectRecord = try! object.restoreRecordWithSystemFields(for: .private)!

var manyUsers = [UserEntity]()
var manyUsersRecordsIDs = [CKRecordID]()
var manyUsersRecordsIDs = [CKRecord.ID]()
for _ in 0...2 {
let user = UserEntity(context: context)
try! user.setRecordInformation(for: .private)
Expand Down Expand Up @@ -56,12 +56,12 @@ class CoreDataRelationshipTests: CoreDataTestCase {
}

// Check single relationship
let singleReference = filledObjectRecord.value(forKey: "singleRelationship") as! CKReference
let singleReference = filledObjectRecord.value(forKey: "singleRelationship") as! CKRecord.Reference
XCTAssertEqual(manyUsersRecordsIDs[0], singleReference.recordID)

// Check many relationships
let multipleReferences = filledObjectRecord.value(forKey: "manyRelationship") as! [CKReference]
var filledRecordRelationshipIDs = [CKRecordID]()
let multipleReferences = filledObjectRecord.value(forKey: "manyRelationship") as! [CKRecord.Reference]
var filledRecordRelationshipIDs = [CKRecord.ID]()

for recordReference in multipleReferences {
filledRecordRelationshipIDs.append(recordReference.recordID)
Expand Down
2 changes: 1 addition & 1 deletion Tests/CloudCoreTests/CustomFunctions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import XCTest

func XCTAssertThrowsSpecific<T>(_ expression: @autoclosure () throws -> T, _ error: Error) {
XCTAssertThrowsError(expression) { (throwedError) in
XCTAssertThrowsError(try expression()) { (throwedError) in
XCTAssertEqual("\(throwedError)", "\(error)", "XCTAssertThrowsSpecific: errors are not equal")
}
}
Expand Down
5 changes: 3 additions & 2 deletions Tests/CloudCoreTests/Model/CKRecordTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import CloudKit

class CKRecordTests: XCTestCase {
func testEncodeAndInit() {
let zoneID = CKRecordZoneID(zoneName: "zone", ownerName: CKCurrentUserDefaultName)
let record = CKRecord(recordType: "type", zoneID: zoneID)
let zoneID = CKRecordZone.ID(zoneName: "zone", ownerName: CKCurrentUserDefaultName)
let recordID = CKRecord.ID(recordName: "name", zoneID: zoneID)
let record = CKRecord(recordType: "type", recordID: recordID)
record.setValue("testValue", forKey: "testKey")

let encodedData = record.encdodedSystemFields
Expand Down
7 changes: 4 additions & 3 deletions Tests/Shared/CorrectObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ struct CorrectObject {
}

func makeRecord() -> CKRecord {
let record = CKRecord(recordType: "TestEntity", zoneID: CloudCore.config.privateZoneID())

let recordID = CKRecord.ID(recordName: UUID().uuidString, zoneID: CloudCore.config.privateZoneID())
let record = CKRecord(recordType: "TestEntity", recordID: recordID)

let asset = try? CoreDataAttribute.createAsset(for: externalBinary)
XCTAssertNotNil(asset)
record.setValue(asset, forKey: "externalBinary")
Expand Down Expand Up @@ -143,7 +144,7 @@ func assertEqualPlainTextAttributes(_ managedObject: TestEntity, _ record: CKRec

func assertEqualBinaryAttributes(_ managedObject: TestEntity, _ record: CKRecord) {
if let recordAsset = record.value(forKey: "externalBinary") as! CKAsset? {
let downloadedData = try! Data(contentsOf: recordAsset.fileURL)
let downloadedData = try! Data(contentsOf: recordAsset.fileURL!)
XCTAssertEqual(managedObject.externalBinary, downloadedData)
}

Expand Down

0 comments on commit 592529a

Please sign in to comment.