mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-16 05:56:50 +01:00
WIP: iCloud support
This commit is contained in:
@@ -85,6 +85,10 @@
|
||||
B519E45A1C4CD2DA00E7B469 /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B519E4571C4CD2CA00E7B469 /* GCDKit.framework */; };
|
||||
B519E45B1C4CD2ED00E7B469 /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B519E4571C4CD2CA00E7B469 /* GCDKit.framework */; };
|
||||
B51BE06A1B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */; };
|
||||
B51F259A1C5747DD0083A5DD /* DataStack+iCloud.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51F25991C5747DD0083A5DD /* DataStack+iCloud.swift */; };
|
||||
B51F259B1C57875E0083A5DD /* DataStack+iCloud.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51F25991C5747DD0083A5DD /* DataStack+iCloud.swift */; };
|
||||
B51F259C1C57875F0083A5DD /* DataStack+iCloud.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51F25991C5747DD0083A5DD /* DataStack+iCloud.swift */; };
|
||||
B51F259D1C5787600083A5DD /* DataStack+iCloud.swift in Sources */ = {isa = PBXBuildFile; fileRef = B51F25991C5747DD0083A5DD /* DataStack+iCloud.swift */; };
|
||||
B5202CFA1C04688100DED140 /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; };
|
||||
B5202CFD1C046E8400DED140 /* NSFetchedResultsController+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */; };
|
||||
B52DD17E1BE1F8CD00949AFE /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B52DD1741BE1F8CC00949AFE /* CoreStore.framework */; };
|
||||
@@ -306,6 +310,7 @@
|
||||
B504D0D51B02362500B2BBB1 /* CoreStore+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStore+Setup.swift"; sourceTree = "<group>"; };
|
||||
B519E4571C4CD2CA00E7B469 /* GCDKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GCDKit.framework; path = "../../Library/Developer/Xcode/DerivedData/Build/Products/Debug-iphoneos/GCDKit.framework"; sourceTree = "<group>"; };
|
||||
B51BE0691B47FC4B0069F532 /* NSManagedObjectModel+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectModel+Setup.swift"; sourceTree = "<group>"; };
|
||||
B51F25991C5747DD0083A5DD /* DataStack+iCloud.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DataStack+iCloud.swift"; sourceTree = "<group>"; };
|
||||
B5202CF91C04688100DED140 /* NSFetchedResultsController+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSFetchedResultsController+Convenience.swift"; sourceTree = "<group>"; };
|
||||
B52DD1741BE1F8CC00949AFE /* CoreStore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreStore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B52DD17D1BE1F8CC00949AFE /* CoreStoreTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreStoreTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -478,6 +483,7 @@
|
||||
2F291E2619C6D3CF007AF63F /* CoreStore.swift */,
|
||||
B5D1E22B19FA9FBC003B2874 /* NSError+CoreStore.swift */,
|
||||
B5E84EDA1AFF84500064E85B /* Setting Up */,
|
||||
B51F25981C5747790083A5DD /* iCloud */,
|
||||
B5E84EE21AFF84610064E85B /* Logging */,
|
||||
B5E84EE91AFF846E0064E85B /* Saving and Processing */,
|
||||
B5E834B61B7630BD001D3D50 /* Importing Data */,
|
||||
@@ -540,6 +546,14 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B51F25981C5747790083A5DD /* iCloud */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B51F25991C5747DD0083A5DD /* DataStack+iCloud.swift */,
|
||||
);
|
||||
path = iCloud;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B56964D11B22FF700075EE4A /* Migrating */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -987,6 +1001,7 @@
|
||||
B5E84F0D1AFF847B0064E85B /* BaseDataTransaction+Querying.swift in Sources */,
|
||||
B5FAD6AC1B51285300714891 /* MigrationManager.swift in Sources */,
|
||||
B5E84EF61AFF846E0064E85B /* DataStack+Transaction.swift in Sources */,
|
||||
B51F259A1C5747DD0083A5DD /* DataStack+iCloud.swift in Sources */,
|
||||
B5E84EDF1AFF84500064E85B /* DataStack.swift in Sources */,
|
||||
B59AFF411C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift in Sources */,
|
||||
B5E834BB1B7691F3001D3D50 /* Functions.swift in Sources */,
|
||||
@@ -1065,6 +1080,7 @@
|
||||
82BA18CD1C4BBD7100A0916E /* AssociatedObjects.swift in Sources */,
|
||||
82BA18B71C4BBD3F00A0916E /* CoreStore+Querying.swift in Sources */,
|
||||
82BA18A41C4BBD2200A0916E /* PersistentStoreResult.swift in Sources */,
|
||||
B51F259B1C57875E0083A5DD /* DataStack+iCloud.swift in Sources */,
|
||||
82BA18AA1C4BBD3100A0916E /* BaseDataTransaction.swift in Sources */,
|
||||
82BA18A91C4BBD3100A0916E /* Into.swift in Sources */,
|
||||
82BA18D11C4BBD7100A0916E /* NotificationObserver.swift in Sources */,
|
||||
@@ -1117,6 +1133,7 @@
|
||||
B52DD1BF1BE1F94600949AFE /* AssociatedObjects.swift in Sources */,
|
||||
B52DD1A11BE1F92C00949AFE /* DataStack+Transaction.swift in Sources */,
|
||||
B52DD19E1BE1F92C00949AFE /* AsynchronousDataTransaction.swift in Sources */,
|
||||
B51F259D1C5787600083A5DD /* DataStack+iCloud.swift in Sources */,
|
||||
B52DD1981BE1F92500949AFE /* CoreStore+Setup.swift in Sources */,
|
||||
B52DD1941BE1F92500949AFE /* CoreStore.swift in Sources */,
|
||||
B52DD1A61BE1F92F00949AFE /* BaseDataTransaction+Importing.swift in Sources */,
|
||||
@@ -1208,6 +1225,7 @@
|
||||
B56321A71BD65216006C9394 /* MigrationResult.swift in Sources */,
|
||||
B56321A11BD65216006C9394 /* ListMonitor.swift in Sources */,
|
||||
B56321881BD65216006C9394 /* BaseDataTransaction.swift in Sources */,
|
||||
B51F259C1C57875F0083A5DD /* DataStack+iCloud.swift in Sources */,
|
||||
B56321A31BD65216006C9394 /* DataStack+Migration.swift in Sources */,
|
||||
B56321901BD65216006C9394 /* ImportableUniqueObject.swift in Sources */,
|
||||
B56321871BD65216006C9394 /* Into.swift in Sources */,
|
||||
|
||||
@@ -58,6 +58,11 @@ public enum CoreStoreErrorCode: Int {
|
||||
An `NSMappingModel` could not be found for a specific source and destination model versions.
|
||||
*/
|
||||
case MappingModelNotFound
|
||||
|
||||
/**
|
||||
The container could not be located or if iCloud storage is unavailable for the current user or device.
|
||||
*/
|
||||
case ICloudContainerNotFound
|
||||
}
|
||||
|
||||
|
||||
|
||||
169
CoreStore/iCloud/DataStack+iCloud.swift
Normal file
169
CoreStore/iCloud/DataStack+iCloud.swift
Normal file
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// DataStack+iCloud.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright © 2016 John Rommel Estropia
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
#if USE_FRAMEWORKS
|
||||
import GCDKit
|
||||
#endif
|
||||
|
||||
public extension DataStack {
|
||||
|
||||
public func addICloudStore(ubiquitousContentName: String, ubiquitousContentURLRelativePath: String? = nil, ubiquitousContainerID: String? = nil, ubiquitousPeerToken: String? = nil, configuration: String? = nil, mappingModelBundles: [NSBundle]? = NSBundle.allBundles(), automigrating: Bool, resetStoreOnModelMismatch: Bool = false, completion: (PersistentStoreResult) -> Void) throws -> NSProgress? {
|
||||
|
||||
CoreStore.assert(
|
||||
!ubiquitousContentName.isEmpty,
|
||||
"The ubiquitousContentName cannot be empty."
|
||||
)
|
||||
CoreStore.assert(
|
||||
!ubiquitousContentName.containsString("."),
|
||||
"The ubiquitousContentName cannot contain periods."
|
||||
)
|
||||
CoreStore.assert(
|
||||
ubiquitousContentURLRelativePath?.isEmpty != true,
|
||||
"The ubiquitousContentURLRelativePath should not be empty if provided."
|
||||
)
|
||||
CoreStore.assert(
|
||||
ubiquitousPeerToken?.isEmpty != true,
|
||||
"The ubiquitousPeerToken should not be empty if provided."
|
||||
)
|
||||
|
||||
let fileManager = NSFileManager.defaultManager()
|
||||
guard let fileURL = fileManager.URLForUbiquityContainerIdentifier(ubiquitousContainerID) else {
|
||||
|
||||
throw NSError(coreStoreErrorCode: .ICloudContainerNotFound)
|
||||
}
|
||||
|
||||
let coordinator = self.coordinator;
|
||||
if let store = coordinator.persistentStoreForURL(fileURL) {
|
||||
|
||||
guard store.type == NSSQLiteStoreType
|
||||
&& store.configurationName == (configuration ?? Into.defaultConfigurationName) else {
|
||||
|
||||
let error = NSError(coreStoreErrorCode: .DifferentPersistentStoreExistsAtURL)
|
||||
CoreStore.handleError(
|
||||
error,
|
||||
"Failed to add SQLite \(typeName(NSPersistentStore)) at \"\(fileURL)\" because a different \(typeName(NSPersistentStore)) at that URL already exists."
|
||||
)
|
||||
throw error
|
||||
}
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(store))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_ = try? fileManager.createDirectoryAtURL(
|
||||
fileURL.URLByDeletingLastPathComponent!,
|
||||
withIntermediateDirectories: true,
|
||||
attributes: nil
|
||||
)
|
||||
|
||||
var options = self.optionsForSQLiteStore()
|
||||
options[NSPersistentStoreUbiquitousContentNameKey] = ubiquitousContentName
|
||||
options[NSMigratePersistentStoresAutomaticallyOption] = automigrating
|
||||
options[NSInferMappingModelAutomaticallyOption] = automigrating
|
||||
|
||||
if let ubiquitousContentURLRelativePath = ubiquitousContentURLRelativePath {
|
||||
|
||||
options[NSPersistentStoreUbiquitousContentURLKey] = ubiquitousContentURLRelativePath
|
||||
}
|
||||
if let ubiquitousContainerID = ubiquitousContainerID {
|
||||
|
||||
options[NSPersistentStoreUbiquitousContainerIdentifierKey] = ubiquitousContainerID
|
||||
}
|
||||
if let ubiquitousPeerToken = ubiquitousPeerToken {
|
||||
|
||||
options[NSPersistentStoreUbiquitousPeerTokenOption] = ubiquitousPeerToken
|
||||
}
|
||||
|
||||
var store: NSPersistentStore?
|
||||
var storeError: NSError?
|
||||
coordinator.performBlockAndWait {
|
||||
|
||||
do {
|
||||
|
||||
store = try coordinator.addPersistentStoreWithType(
|
||||
NSSQLiteStoreType,
|
||||
configuration: configuration,
|
||||
URL: fileURL,
|
||||
options: options
|
||||
)
|
||||
}
|
||||
catch {
|
||||
|
||||
storeError = error as NSError
|
||||
}
|
||||
}
|
||||
|
||||
if let store = store {
|
||||
|
||||
self.updateMetadataForPersistentStore(store)
|
||||
return store
|
||||
}
|
||||
|
||||
if let error = storeError
|
||||
where (resetStoreOnModelMismatch && error.isCoreDataMigrationError) {
|
||||
|
||||
fileManager.removeSQLiteStoreAtURL(fileURL)
|
||||
|
||||
var store: NSPersistentStore?
|
||||
coordinator.performBlockAndWait {
|
||||
|
||||
do {
|
||||
|
||||
store = try coordinator.addPersistentStoreWithType(
|
||||
NSSQLiteStoreType,
|
||||
configuration: configuration,
|
||||
URL: fileURL,
|
||||
options: options
|
||||
)
|
||||
}
|
||||
catch {
|
||||
|
||||
storeError = error as NSError
|
||||
}
|
||||
}
|
||||
|
||||
if let store = store {
|
||||
|
||||
self.updateMetadataForPersistentStore(store)
|
||||
return store
|
||||
}
|
||||
}
|
||||
|
||||
let error = storeError ?? NSError(coreStoreErrorCode: .UnknownError)
|
||||
CoreStore.handleError(
|
||||
error,
|
||||
"Failed to add SQLite \(typeName(NSPersistentStore)) at \"\(fileURL)\"."
|
||||
)
|
||||
throw error
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -11,7 +11,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright © 2015 John Rommel Estropia. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.92549019607843142" green="0.94117647058823528" blue="0.94509803921568625" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
Reference in New Issue
Block a user