From d043d64cb127dcc2f1a26aa1fb06e09e2268465d Mon Sep 17 00:00:00 2001 From: John Rommel Estropia Date: Mon, 4 May 2015 12:40:16 +0900 Subject: [PATCH] demo app --- .gitignore | 2 + HardcoreData.xcodeproj/project.pbxproj | 8 +- .../xcshareddata/HardcoreData.xccheckout | 4 +- HardcoreData/AssociatedObjects.swift | 68 +++ .../AsynchronousDataTransaction.swift | 24 +- .../BaseDataTransaction+Querying.swift | 32 +- HardcoreData/BaseDataTransaction.swift | 6 +- HardcoreData/DataStack+Observing.swift | 6 +- HardcoreData/DataStack+Querying.swift | 32 +- HardcoreData/DataStack+Transaction.swift | 6 +- HardcoreData/DataStack.swift | 2 +- HardcoreData/DetachedDataTransaction.swift | 2 +- HardcoreData/GroupBy.swift | 2 +- HardcoreData/HardcoreDataLogger.swift | 10 +- .../ManagedObjectListController.swift | 252 +++++++- HardcoreData/ManagedObjectListObserver.swift | 24 +- .../NSManagedObjectContext+HardcoreData.swift | 22 +- .../NSManagedObjectContext+Setup.swift | 21 +- .../NSManagedObjectContext+Transaction.swift | 11 +- HardcoreData/NSObject+HardcoreData.swift | 76 --- HardcoreData/NotificationObserver.swift | 6 +- HardcoreData/Select.swift | 6 +- HardcoreData/SortedBy.swift | 2 +- HardcoreData/SynchronousDataTransaction.swift | 18 +- HardcoreData/Where.swift | 2 +- .../project.pbxproj | 553 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/HardcoreDataDemo.xccheckout | 53 ++ .../HardcoreDataDemo/AppDelegate.swift | 27 + .../Base.lproj/LaunchScreen.xib | 41 ++ .../Base.lproj/Main.storyboard | 102 ++++ .../DetailViewController.swift | 45 ++ HardcoreDataDemo/HardcoreDataDemo/Event.swift | 16 + .../.xccurrentversion | 8 + .../HardcoreDataDemo.xcdatamodel/contents | 12 + .../AppIcon.appiconset/Contents.json | 38 ++ HardcoreDataDemo/HardcoreDataDemo/Info.plist | 50 ++ .../MasterViewController.swift | 137 +++++ .../HardcoreDataDemoTests.swift | 36 ++ .../HardcoreDataDemoTests/Info.plist | 24 + HardcoreDataTests/HardcoreDataTests.swift | 4 +- 41 files changed, 1583 insertions(+), 214 deletions(-) create mode 100644 HardcoreData/AssociatedObjects.swift delete mode 100644 HardcoreData/NSObject+HardcoreData.swift create mode 100644 HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.pbxproj create mode 100644 HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace/xcshareddata/HardcoreDataDemo.xccheckout create mode 100644 HardcoreDataDemo/HardcoreDataDemo/AppDelegate.swift create mode 100644 HardcoreDataDemo/HardcoreDataDemo/Base.lproj/LaunchScreen.xib create mode 100644 HardcoreDataDemo/HardcoreDataDemo/Base.lproj/Main.storyboard create mode 100644 HardcoreDataDemo/HardcoreDataDemo/DetailViewController.swift create mode 100644 HardcoreDataDemo/HardcoreDataDemo/Event.swift create mode 100644 HardcoreDataDemo/HardcoreDataDemo/HardcoreDataDemo.xcdatamodeld/.xccurrentversion create mode 100644 HardcoreDataDemo/HardcoreDataDemo/HardcoreDataDemo.xcdatamodeld/HardcoreDataDemo.xcdatamodel/contents create mode 100644 HardcoreDataDemo/HardcoreDataDemo/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 HardcoreDataDemo/HardcoreDataDemo/Info.plist create mode 100644 HardcoreDataDemo/HardcoreDataDemo/MasterViewController.swift create mode 100644 HardcoreDataDemo/HardcoreDataDemoTests/HardcoreDataDemoTests.swift create mode 100644 HardcoreDataDemo/HardcoreDataDemoTests/Info.plist diff --git a/.gitignore b/.gitignore index 74b724c..a1a4cb5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ HardcoreData.xcodeproj/xcuserdata +HardcoreDataDemo/HardcoreDataDemo.xcodeproj/xcuserdata +HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace/xcuserdata diff --git a/HardcoreData.xcodeproj/project.pbxproj b/HardcoreData.xcodeproj/project.pbxproj index 3cb2e13..e43666f 100644 --- a/HardcoreData.xcodeproj/project.pbxproj +++ b/HardcoreData.xcodeproj/project.pbxproj @@ -45,7 +45,7 @@ B5D5E0CF1A4D6AAB006468AF /* TestEntity2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D5E0CE1A4D6AAB006468AF /* TestEntity2.swift */; }; B5D8080E1A3471A500A44484 /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D808021A34715700A44484 /* GCDKit.framework */; }; B5D808161A34947300A44484 /* NotificationObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D808151A34947300A44484 /* NotificationObserver.swift */; }; - B5D8081A1A3495BD00A44484 /* NSObject+HardcoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D808191A3495BD00A44484 /* NSObject+HardcoreData.swift */; }; + B5D8081A1A3495BD00A44484 /* AssociatedObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D808191A3495BD00A44484 /* AssociatedObjects.swift */; }; B5E126551A7DCE1400AD8B39 /* Where.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E126541A7DCE1400AD8B39 /* Where.swift */; }; B5E126571A7DCE5900AD8B39 /* SortedBy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E126561A7DCE5900AD8B39 /* SortedBy.swift */; }; B5E209E01A0726460089C9D4 /* NSManagedObject+Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E209DF1A0726460089C9D4 /* NSManagedObject+Transaction.swift */; }; @@ -124,7 +124,7 @@ B5D5E0CE1A4D6AAB006468AF /* TestEntity2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestEntity2.swift; sourceTree = ""; }; B5D806C51A34715700A44484 /* GCDKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = GCDKit.xcodeproj; sourceTree = ""; }; B5D808151A34947300A44484 /* NotificationObserver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = NotificationObserver.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; - B5D808191A3495BD00A44484 /* NSObject+HardcoreData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSObject+HardcoreData.swift"; sourceTree = ""; }; + B5D808191A3495BD00A44484 /* AssociatedObjects.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssociatedObjects.swift; sourceTree = ""; }; B5E126541A7DCE1400AD8B39 /* Where.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Where.swift; sourceTree = ""; }; B5E126561A7DCE5900AD8B39 /* SortedBy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SortedBy.swift; sourceTree = ""; }; B5E209DF1A0726460089C9D4 /* NSManagedObject+Transaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Transaction.swift"; sourceTree = ""; }; @@ -349,7 +349,7 @@ children = ( B5D808151A34947300A44484 /* NotificationObserver.swift */, B595CAC71A9A161B009A397F /* WeakObject.swift */, - B5D808191A3495BD00A44484 /* NSObject+HardcoreData.swift */, + B5D808191A3495BD00A44484 /* AssociatedObjects.swift */, B5CFF23D19FD1D1C00D6DFC4 /* NSManagedObjectContext+HardcoreData.swift */, ); name = Internal; @@ -524,7 +524,7 @@ B5F409EF1A8B243D00A228EA /* BaseDataTransaction+Querying.swift in Sources */, 2F291E2719C6D3CF007AF63F /* HardcoreData.swift in Sources */, B5F409E91A8B11CE00A228EA /* HardcoreDataLogger.swift in Sources */, - B5D8081A1A3495BD00A44484 /* NSObject+HardcoreData.swift in Sources */, + B5D8081A1A3495BD00A44484 /* AssociatedObjects.swift in Sources */, B595CAC41A9A11C1009A397F /* NSManagedObjectContext+Setup.swift in Sources */, B5D19BFF1AA14351001D1A99 /* SynchronousDataTransaction.swift in Sources */, B5D10DC21AB4590F004B4EEA /* Select.swift in Sources */, diff --git a/HardcoreData.xcodeproj/project.xcworkspace/xcshareddata/HardcoreData.xccheckout b/HardcoreData.xcodeproj/project.xcworkspace/xcshareddata/HardcoreData.xccheckout index b34317e..eefc0ec 100644 --- a/HardcoreData.xcodeproj/project.xcworkspace/xcshareddata/HardcoreData.xccheckout +++ b/HardcoreData.xcodeproj/project.xcworkspace/xcshareddata/HardcoreData.xccheckout @@ -7,7 +7,7 @@ IDESourceControlProjectIdentifier FE56D6CC-DFA6-4581-B49D-F2486374A545 IDESourceControlProjectName - HardcoreData + project IDESourceControlProjectOriginsDictionary 4B60F1BCB491FF717C56441AE7783C74F417BE48 @@ -16,7 +16,7 @@ github.com:JohnEstropia/GCDKit.git IDESourceControlProjectPath - HardcoreData.xcodeproj + HardcoreData.xcodeproj/project.xcworkspace IDESourceControlProjectRelativeInstallPathDictionary 4B60F1BCB491FF717C56441AE7783C74F417BE48 diff --git a/HardcoreData/AssociatedObjects.swift b/HardcoreData/AssociatedObjects.swift new file mode 100644 index 0000000..578d583 --- /dev/null +++ b/HardcoreData/AssociatedObjects.swift @@ -0,0 +1,68 @@ +// +// NSObject+HardcoreData.swift +// HardcoreData +// +// Copyright (c) 2014 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 + +internal func getAssociatedObjectForKey(key: UnsafePointer, inObject object: AnyObject) -> T? { + + switch objc_getAssociatedObject(object, key) { + + case let associatedObject as T: + return associatedObject + + case let associatedObject as WeakObject: + return associatedObject.object as? T + + default: + return nil + } +} + +internal func setAssociatedRetainedObject(associatedObject: T?, forKey key: UnsafePointer, inObject object: AnyObject) { + + objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) +} + +internal func setAssociatedCopiedObject(associatedObject: T?, forKey key: UnsafePointer, inObject object: AnyObject) { + + objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_COPY_NONATOMIC)) +} + +internal func setAssociatedAssignedObject(associatedObject: T?, forKey key: UnsafePointer, inObject object: AnyObject) { + + objc_setAssociatedObject(object, key, associatedObject, UInt(OBJC_ASSOCIATION_ASSIGN)) +} + +internal func setAssociatedWeakObject(associatedObject: T?, forKey key: UnsafePointer, inObject object: AnyObject) { + + if let associatedObject = associatedObject { + + objc_setAssociatedObject(object, key, WeakObject(associatedObject), UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) + } + else { + + objc_setAssociatedObject(object, key, nil, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) + } +} diff --git a/HardcoreData/AsynchronousDataTransaction.swift b/HardcoreData/AsynchronousDataTransaction.swift index 423b687..23b3f3e 100644 --- a/HardcoreData/AsynchronousDataTransaction.swift +++ b/HardcoreData/AsynchronousDataTransaction.swift @@ -41,8 +41,8 @@ public final class AsynchronousDataTransaction: BaseDataTransaction { */ public func commit(completion: (result: SaveResult) -> Void) { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside its designated queue.") - HardcoreData.assert(!self.isCommitted, "Attempted to commit a <\(self.dynamicType)> more than once.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.") + HardcoreData.assert(!self.isCommitted, "Attempted to commit a \(typeName(self)) more than once.") self.isCommitted = true let semaphore = GCDSemaphore(0) @@ -62,8 +62,8 @@ public final class AsynchronousDataTransaction: BaseDataTransaction { */ public func commitAndWait() { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside its designated queue.") - HardcoreData.assert(!self.isCommitted, "Attempted to commit a <\(self.dynamicType)> more than once.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.") + HardcoreData.assert(!self.isCommitted, "Attempted to commit a \(typeName(self)) more than once.") self.isCommitted = true self.result = self.context.saveSynchronously() @@ -77,8 +77,8 @@ public final class AsynchronousDataTransaction: BaseDataTransaction { */ public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to begin a child transaction from a <\(self.dynamicType)> outside its designated queue.") - HardcoreData.assert(!self.isCommitted, "Attempted to begin a child transaction from an already committed <\(self.dynamicType)>.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to begin a child transaction from a \(typeName(self)) outside its designated queue.") + HardcoreData.assert(!self.isCommitted, "Attempted to begin a child transaction from an already committed \(typeName(self)).") return SynchronousDataTransaction( mainContext: self.context, @@ -97,7 +97,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction { */ public override func create(entity: T.Type) -> T { - HardcoreData.assert(!self.isCommitted, "Attempted to create an entity of type <\(entity)> from an already committed <\(self.dynamicType)>.") + HardcoreData.assert(!self.isCommitted, "Attempted to create an entity of type <\(entity)> from an already committed \(typeName(self)).") return super.create(entity) } @@ -110,7 +110,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction { */ public override func fetch(object: T) -> T? { - HardcoreData.assert(!self.isCommitted, "Attempted to update an entity of type <\(object.dynamicType)> from an already committed <\(self.dynamicType)>.") + HardcoreData.assert(!self.isCommitted, "Attempted to update an entity of type \(typeName(object)) from an already committed \(typeName(self)).") return super.fetch(object) } @@ -122,7 +122,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction { */ public override func delete(object: NSManagedObject) { - HardcoreData.assert(!self.isCommitted, "Attempted to delete an entity of type <\(object.dynamicType)> from an already committed <\(self.dynamicType)>.") + HardcoreData.assert(!self.isCommitted, "Attempted to delete an entity of type \(typeName(object)) from an already committed \(typeName(self)).") super.delete(object) } @@ -132,7 +132,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction { */ public override func rollback() { - HardcoreData.assert(!self.isCommitted, "Attempted to rollback an already committed <\(self.dynamicType)>.") + HardcoreData.assert(!self.isCommitted, "Attempted to rollback an already committed \(typeName(self)).") super.rollback() } @@ -154,7 +154,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction { self.closure(transaction: self) if !self.isCommitted && self.hasChanges { - HardcoreData.log(.Warning, message: "The closure for the <\(self.dynamicType)> completed without being committed. All changes made within the transaction were discarded.") + HardcoreData.log(.Warning, message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.") } } } @@ -166,7 +166,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction { self.closure(transaction: self) if !self.isCommitted && self.hasChanges { - HardcoreData.log(.Warning, message: "The closure for the <\(self.dynamicType)> completed without being committed. All changes made within the transaction were discarded.") + HardcoreData.log(.Warning, message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.") } } return self.result diff --git a/HardcoreData/BaseDataTransaction+Querying.swift b/HardcoreData/BaseDataTransaction+Querying.swift index afd2764..17f3e0c 100644 --- a/HardcoreData/BaseDataTransaction+Querying.swift +++ b/HardcoreData/BaseDataTransaction+Querying.swift @@ -35,112 +35,112 @@ public extension BaseDataTransaction { public func fetchOne(from: From, _ queryClauses: FetchClause...) -> T? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.") return self.context.fetchOne(from, queryClauses) } public func fetchOne(from: From, _ queryClauses: [FetchClause]) -> T? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.") return self.context.fetchOne(from, queryClauses) } public func fetchAll(from: From, _ queryClauses: FetchClause...) -> [T]? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.") return self.context.fetchAll(from, queryClauses) } public func fetchAll(from: From, _ queryClauses: [FetchClause]) -> [T]? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.") return self.context.fetchAll(from, queryClauses) } public func fetchCount(from: From, _ queryClauses: FetchClause...) -> Int? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.") return self.context.fetchCount(from, queryClauses) } public func fetchCount(from: From, _ queryClauses: [FetchClause]) -> Int? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.") return self.context.fetchCount(from, queryClauses) } public func fetchObjectID(from: From, _ queryClauses: FetchClause...) -> NSManagedObjectID? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.") return self.context.fetchObjectID(from, queryClauses) } public func fetchObjectID(from: From, _ queryClauses: [FetchClause]) -> NSManagedObjectID? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.") return self.context.fetchObjectID(from, queryClauses) } public func fetchObjectIDs(from: From, _ queryClauses: FetchClause...) -> [NSManagedObjectID]? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.") return self.context.fetchObjectIDs(from, queryClauses) } public func fetchObjectIDs(from: From, _ queryClauses: [FetchClause]) -> [NSManagedObjectID]? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside its designated queue.") return self.context.fetchObjectIDs(from, queryClauses) } public func deleteAll(from: From, _ queryClauses: FetchClause...) -> Int? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete from a \(typeName(self)) outside its designated queue.") return self.context.deleteAll(from, queryClauses) } public func deleteAll(from: From, _ queryClauses: [FetchClause]) -> Int? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete from a \(typeName(self)) outside its designated queue.") return self.context.deleteAll(from, queryClauses) } public func queryValue(from: From, _ selectClause: Select, _ queryClauses: FetchClause...) -> U? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.") return self.context.queryValue(from, selectClause, queryClauses) } public func queryValue(from: From, _ selectClause: Select, _ queryClauses: [FetchClause]) -> U? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.") return self.context.queryValue(from, selectClause, queryClauses) } public func queryAttributes(from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.") return self.context.queryAttributes(from, selectClause, queryClauses) } public func queryAttributes(from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside its designated queue.") return self.context.queryAttributes(from, selectClause, queryClauses) } diff --git a/HardcoreData/BaseDataTransaction.swift b/HardcoreData/BaseDataTransaction.swift index a4e7cff..2335535 100644 --- a/HardcoreData/BaseDataTransaction.swift +++ b/HardcoreData/BaseDataTransaction.swift @@ -63,7 +63,7 @@ public /*abstract*/ class BaseDataTransaction { */ public func fetch(object: T) -> T? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to update an entity of type <\(object.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to update an entity of type \(typeName(object)) outside its designated queue.") return object.inContext(self.context) } @@ -75,7 +75,7 @@ public /*abstract*/ class BaseDataTransaction { */ public func delete(object: NSManagedObject) { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete an entity of type <\(object.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to delete an entity of type \(typeName(object)) outside its designated queue.") object.deleteFromContext() } @@ -87,7 +87,7 @@ public /*abstract*/ class BaseDataTransaction { */ public func rollback() { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to rollback a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to rollback a \(typeName(self)) outside its designated queue.") self.context.reset() } diff --git a/HardcoreData/DataStack+Observing.swift b/HardcoreData/DataStack+Observing.swift index 16a68d2..1180df9 100644 --- a/HardcoreData/DataStack+Observing.swift +++ b/HardcoreData/DataStack+Observing.swift @@ -34,14 +34,14 @@ public extension DataStack { // MARK: Public - public func observeObjectList(entity: T.Type, _ queryClauses: FetchClause...) -> ManagedObjectListController { + public func observeObjectList(from: From, _ queryClauses: FetchClause...) -> ManagedObjectListController { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") // TODO: sectionNameKeyPath and cacheResults return ManagedObjectListController( dataStack: self, - entity: entity, + entity: T.self, sectionNameKeyPath: nil, cacheResults: false, queryClauses: queryClauses diff --git a/HardcoreData/DataStack+Querying.swift b/HardcoreData/DataStack+Querying.swift index 4a19477..8fec068 100644 --- a/HardcoreData/DataStack+Querying.swift +++ b/HardcoreData/DataStack+Querying.swift @@ -36,112 +36,112 @@ public extension DataStack { public func fetchOne(from: From, _ queryClauses: FetchClause...) -> T? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") return self.mainContext.fetchOne(from, queryClauses) } public func fetchOne(from: From, _ queryClauses: [FetchClause]) -> T? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") return self.mainContext.fetchOne(from, queryClauses) } public func fetchAll(from: From, _ queryClauses: FetchClause...) -> [T]? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") return self.mainContext.fetchAll(from, queryClauses) } public func fetchAll(from: From, _ queryClauses: [FetchClause]) -> [T]? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") return self.mainContext.fetchAll(from, queryClauses) } public func fetchCount(from: From, _ queryClauses: FetchClause...) -> Int? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") return self.mainContext.fetchCount(from, queryClauses) } public func fetchCount(from: From, _ queryClauses: [FetchClause]) -> Int? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") return self.mainContext.fetchCount(from, queryClauses) } public func fetchObjectID(from: From, _ queryClauses: FetchClause...) -> NSManagedObjectID? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") return self.mainContext.fetchObjectID(from, queryClauses) } public func fetchObjectID(from: From, _ queryClauses: [FetchClause]) -> NSManagedObjectID? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") return self.mainContext.fetchObjectID(from, queryClauses) } public func fetchObjectIDs(from: From, _ queryClauses: FetchClause...) -> [NSManagedObjectID]? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") return self.mainContext.fetchObjectIDs(from, queryClauses) } public func fetchObjectIDs(from: From, _ queryClauses: [FetchClause]) -> [NSManagedObjectID]? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to fetch from a \(typeName(self)) outside the main queue.") return self.mainContext.fetchObjectIDs(from, queryClauses) } public func deleteAll(from: From, _ queryClauses: FetchClause...) -> Int? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to delete from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to delete from a \(typeName(self)) outside the main queue.") return self.mainContext.deleteAll(from, queryClauses) } public func deleteAll(from: From, _ queryClauses: [FetchClause]) -> Int? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to delete from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to delete from a \(typeName(self)) outside the main queue.") return self.mainContext.deleteAll(from, queryClauses) } public func queryValue(from: From, _ selectClause: Select, _ queryClauses: FetchClause...) -> U? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside the main queue.") return self.mainContext.queryValue(from, selectClause, queryClauses) } public func queryValue(from: From, _ selectClause: Select, _ queryClauses: [FetchClause]) -> U? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside the main queue.") return self.mainContext.queryValue(from, selectClause, queryClauses) } public func queryAttributes(from: From, _ selectClause: Select, _ queryClauses: QueryClause...) -> [[NSString: AnyObject]]? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside the main queue.") return self.mainContext.queryAttributes(from, selectClause, queryClauses) } public func queryAttributes(from: From, _ selectClause: Select, _ queryClauses: [QueryClause]) -> [[NSString: AnyObject]]? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to query from a \(typeName(self)) outside the main queue.") return self.mainContext.queryAttributes(from, selectClause, queryClauses) } diff --git a/HardcoreData/DataStack+Transaction.swift b/HardcoreData/DataStack+Transaction.swift index b933f51..c038d31 100644 --- a/HardcoreData/DataStack+Transaction.swift +++ b/HardcoreData/DataStack+Transaction.swift @@ -41,7 +41,7 @@ public extension DataStack { */ public func beginAsynchronous(closure: (transaction: AsynchronousDataTransaction) -> Void) { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to begin a transaction from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to begin a transaction from a \(typeName(self)) outside the main queue.") AsynchronousDataTransaction( mainContext: self.rootSavingContext, @@ -57,7 +57,7 @@ public extension DataStack { */ public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to begin a transaction from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to begin a transaction from a \(typeName(self)) outside the main queue.") return SynchronousDataTransaction( mainContext: self.rootSavingContext, @@ -72,7 +72,7 @@ public extension DataStack { */ public func beginDetached() -> DetachedDataTransaction { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to begin a transaction from a <\(self.dynamicType)> outside the main queue.") + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to begin a transaction from a \(typeName(self)) outside the main queue.") return DetachedDataTransaction( mainContext: self.rootSavingContext, diff --git a/HardcoreData/DataStack.swift b/HardcoreData/DataStack.swift index 424e71d..b054766 100644 --- a/HardcoreData/DataStack.swift +++ b/HardcoreData/DataStack.swift @@ -32,7 +32,7 @@ private let applicationSupportDirectory = NSFileManager.defaultManager().URLsFor private let applicationName = ((NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData") -private let defaultSQLiteStoreURL = applicationSupportDirectory.URLByAppendingPathComponent(applicationName, isDirectory: true).URLByAppendingPathExtension("sqlite") +private let defaultSQLiteStoreURL = applicationSupportDirectory.URLByAppendingPathComponent(applicationName, isDirectory: false).URLByAppendingPathExtension("sqlite") // MARK: - DataStack diff --git a/HardcoreData/DetachedDataTransaction.swift b/HardcoreData/DetachedDataTransaction.swift index 4853c34..d46e1cd 100644 --- a/HardcoreData/DetachedDataTransaction.swift +++ b/HardcoreData/DetachedDataTransaction.swift @@ -41,7 +41,7 @@ public final class DetachedDataTransaction: BaseDataTransaction { */ public func commit(completion: (result: SaveResult) -> Void) { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside its designated queue.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.") self.context.saveAsynchronouslyWithCompletion { (result) -> Void in diff --git a/HardcoreData/GroupBy.swift b/HardcoreData/GroupBy.swift index 5e400b7..3a9c38f 100644 --- a/HardcoreData/GroupBy.swift +++ b/HardcoreData/GroupBy.swift @@ -56,7 +56,7 @@ public struct GroupBy: QueryClause { if fetchRequest.propertiesToGroupBy != nil { - HardcoreData.log(.Warning, message: "An existing \"propertiesToGroupBy\" for the <\(NSFetchRequest.self)> was overwritten by <\(self.dynamicType)> query clause.") + HardcoreData.log(.Warning, message: "An existing \"propertiesToGroupBy\" for the <\(NSFetchRequest.self)> was overwritten by \(typeName(self)) query clause.") } fetchRequest.propertiesToGroupBy = self.keyPaths diff --git a/HardcoreData/HardcoreDataLogger.swift b/HardcoreData/HardcoreDataLogger.swift index 7a8fe1e..37173a5 100644 --- a/HardcoreData/HardcoreDataLogger.swift +++ b/HardcoreData/HardcoreDataLogger.swift @@ -46,4 +46,12 @@ public protocol HardcoreDataLogger { func handleError(#error: NSError, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) func assert(@autoclosure condition: () -> Bool, message: String, fileName: StaticString, lineNumber: Int, functionName: StaticString) -} \ No newline at end of file +} + + +// MARK: - Utilities + +internal func typeName(value: T) -> String { + + return "<\(_stdlib_getDemangledTypeName(value))>" +} diff --git a/HardcoreData/ManagedObjectListController.swift b/HardcoreData/ManagedObjectListController.swift index 9d4898d..b4ba15b 100644 --- a/HardcoreData/ManagedObjectListController.swift +++ b/HardcoreData/ManagedObjectListController.swift @@ -28,48 +28,260 @@ import CoreData import GCDKit +private let ManagedObjectListControllerWillChangeListNotification = "ManagedObjectListControllerWillChangeListNotification" +private let ManagedObjectListControllerDidChangeListNotification = "ManagedObjectListControllerDidChangeListNotification" +private let ManagedObjectListControllerDidInsertObjectNotification = "ManagedObjectListControllerDidInsertObjectNotification" +private let ManagedObjectListControllerDidDeleteObjectNotification = "ManagedObjectListControllerDidDeleteObjectNotification" +private let ManagedObjectListControllerDidUpdateObjectNotification = "ManagedObjectListControllerDidUpdateObjectNotification" +private let ManagedObjectListControllerDidMoveObjectNotification = "ManagedObjectListControllerDidMoveObjectNotification" + +private let UserInfoKeyObject = "UserInfoKeyObject" +private let UserInfoKeyIndexPath = "UserInfoKeyIndexPath" +private let UserInfoKeyNewIndexPath = "UserInfoKeyNewIndexPath" + +private struct NotificationKey { + + static var willChangeList: Void? + static var didChangeList: Void? + static var didInsertObject: Void? + static var didDeleteObject: Void? + static var didUpdateObject: Void? + static var didMoveObject: Void? +} + // MARK: - ManagedObjectListController public final class ManagedObjectListController: FetchedResultsControllerHandler { // MARK: Public - public typealias EntityType = T - - public func addObserver(observer: U) { + public subscript(indexPath: NSIndexPath) -> T { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to add a <\(U.self)> outside the main queue.") - - self.observers.addObject(observer) + return self.fetchedResultsController.objectAtIndexPath(indexPath) as! T } - public func removeObserver(observer: U) { + public func numberOfSections() -> Int { - HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to remove a <\(U.self)> outside the main queue.") - - self.observers.removeObject(observer) + return self.fetchedResultsController.sections?.count ?? 0 } + public func numberOfItemsInSection(section: Int) -> Int { + + return (self.fetchedResultsController.sections?[section] as? NSFetchedResultsSectionInfo)?.numberOfObjects ?? 0 + } + + public func addObserver(observer: U) { + + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to add a \(typeName(observer)) outside the main queue.") + + setAssociatedRetainedObject( + NotificationObserver( + notificationName: ManagedObjectListControllerWillChangeListNotification, + object: self, + closure: { [weak self, weak observer] (note) -> Void in + + if let strongSelf = self, let strongObserver = observer { + + strongObserver.managedObjectListWillChange(strongSelf) + } + } + ), + forKey: &NotificationKey.willChangeList, + inObject: observer + ) + setAssociatedRetainedObject( + NotificationObserver( + notificationName: ManagedObjectListControllerDidChangeListNotification, + object: self, + closure: { [weak self, weak observer] (note) -> Void in + + if let strongSelf = self, let strongObserver = observer { + + strongObserver.managedObjectListDidChange(strongSelf) + } + } + ), + forKey: &NotificationKey.willChangeList, + inObject: observer + ) + setAssociatedRetainedObject( + NotificationObserver( + notificationName: ManagedObjectListControllerDidInsertObjectNotification, + object: self, + closure: { [weak self, weak observer] (note) -> Void in + + if let strongSelf = self, + let strongObserver = observer, + let userInfo = note.userInfo, + let object = userInfo[UserInfoKeyObject] as? T, + let newIndexPath = userInfo[UserInfoKeyNewIndexPath] as? NSIndexPath { + + strongObserver.managedObjectList( + strongSelf, + didInsertObject: object, + toIndexPath: newIndexPath + ) + } + } + ), + forKey: &NotificationKey.didInsertObject, + inObject: observer + ) + setAssociatedRetainedObject( + NotificationObserver( + notificationName: ManagedObjectListControllerDidDeleteObjectNotification, + object: self, + closure: { [weak self, weak observer] (note) -> Void in + + if let strongSelf = self, + let strongObserver = observer, + let userInfo = note.userInfo, + let object = userInfo[UserInfoKeyObject] as? T, + let indexPath = userInfo[UserInfoKeyIndexPath] as? NSIndexPath { + + strongObserver.managedObjectList( + strongSelf, + didDeleteObject: object, + fromIndexPath: indexPath + ) + } + } + ), + forKey: &NotificationKey.didDeleteObject, + inObject: observer + ) + setAssociatedRetainedObject( + NotificationObserver( + notificationName: ManagedObjectListControllerDidUpdateObjectNotification, + object: self, + closure: { [weak self, weak observer] (note) -> Void in + + if let strongSelf = self, + let strongObserver = observer, + let userInfo = note.userInfo, + let object = userInfo[UserInfoKeyObject] as? T, + let indexPath = userInfo[UserInfoKeyIndexPath] as? NSIndexPath { + + strongObserver.managedObjectList( + strongSelf, + didUpdateObject: object, + atIndexPath: indexPath + ) + } + } + ), + forKey: &NotificationKey.didUpdateObject, + inObject: observer + ) + setAssociatedRetainedObject( + NotificationObserver( + notificationName: ManagedObjectListControllerDidMoveObjectNotification, + object: self, + closure: { [weak self, weak observer] (note) -> Void in + + if let strongSelf = self, + let strongObserver = observer, + let userInfo = note.userInfo, + let object = userInfo[UserInfoKeyObject] as? T, + let indexPath = userInfo[UserInfoKeyIndexPath] as? NSIndexPath , + let newIndexPath = userInfo[UserInfoKeyNewIndexPath] as? NSIndexPath { + + strongObserver.managedObjectList( + strongSelf, + didMoveObject: object, + fromIndexPath: indexPath, + toIndexPath: newIndexPath + ) + } + } + ), + forKey: &NotificationKey.didMoveObject, + inObject: observer + ) + } + + public func removeObserver(observer: U) { + + HardcoreData.assert(GCDQueue.Main.isCurrentExecutionContext(), "Attempted to remove a \(typeName(observer)) outside the main queue.") + + setAssociatedRetainedObject(nil as AnyObject?, forKey: &NotificationKey.willChangeList, inObject: observer) + setAssociatedRetainedObject(nil as AnyObject?, forKey: &NotificationKey.didChangeList, inObject: observer) + setAssociatedRetainedObject(nil as AnyObject?, forKey: &NotificationKey.didInsertObject, inObject: observer) + setAssociatedRetainedObject(nil as AnyObject?, forKey: &NotificationKey.didDeleteObject, inObject: observer) + setAssociatedRetainedObject(nil as AnyObject?, forKey: &NotificationKey.didUpdateObject, inObject: observer) + setAssociatedRetainedObject(nil as AnyObject?, forKey: &NotificationKey.didMoveObject, inObject: observer) + } // MARK: FetchedResultsControllerHandler - func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { + private func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { + + switch type { + + case .Insert: + NSNotificationCenter.defaultCenter().postNotificationName( + ManagedObjectListControllerDidInsertObjectNotification, + object: self, + userInfo: [ + UserInfoKeyObject: anObject, + UserInfoKeyNewIndexPath: newIndexPath! + ] + ) + + case .Delete: + NSNotificationCenter.defaultCenter().postNotificationName( + ManagedObjectListControllerDidDeleteObjectNotification, + object: self, + userInfo: [ + UserInfoKeyObject: anObject, + UserInfoKeyIndexPath: indexPath! + ] + ) + + case .Update: + NSNotificationCenter.defaultCenter().postNotificationName( + ManagedObjectListControllerDidUpdateObjectNotification, + object: self, + userInfo: [ + UserInfoKeyObject: anObject, + UserInfoKeyIndexPath: indexPath! + ] + ) + + case .Move: + NSNotificationCenter.defaultCenter().postNotificationName( + ManagedObjectListControllerDidMoveObjectNotification, + object: self, + userInfo: [ + UserInfoKeyObject: anObject, + UserInfoKeyIndexPath: indexPath!, + UserInfoKeyNewIndexPath: newIndexPath! + ] + ) + } + } + + private func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { } - func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { + private func controllerWillChangeContent(controller: NSFetchedResultsController) { + NSNotificationCenter.defaultCenter().postNotificationName( + ManagedObjectListControllerWillChangeListNotification, + object: self + ) } - func controllerWillChangeContent(controller: NSFetchedResultsController) { + private func controllerDidChangeContent(controller: NSFetchedResultsController) { + NSNotificationCenter.defaultCenter().postNotificationName( + ManagedObjectListControllerDidChangeListNotification, + object: self + ) } - func controllerDidChangeContent(controller: NSFetchedResultsController) { - - } - - func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? { + private func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? { return nil } @@ -96,7 +308,7 @@ public final class ManagedObjectListController: FetchedResul managedObjectContext: context, sectionNameKeyPath: sectionNameKeyPath, cacheName: (cacheResults - ? "\(ManagedObjectListController.self).\(NSUUID())" + ? "\(self.dynamicType).\(NSUUID())" : nil) ) @@ -105,7 +317,6 @@ public final class ManagedObjectListController: FetchedResul self.fetchedResultsController = fetchedResultsController self.fetchedResultsControllerDelegate = fetchedResultsControllerDelegate self.parentStack = dataStack - self.observers = NSHashTable.weakObjectsHashTable() fetchedResultsControllerDelegate.handler = self fetchedResultsControllerDelegate.fetchedResultsController = fetchedResultsController @@ -125,7 +336,6 @@ public final class ManagedObjectListController: FetchedResul private let fetchedResultsController: NSFetchedResultsController private let fetchedResultsControllerDelegate: FetchedResultsControllerDelegate private weak var parentStack: DataStack? - private let observers: NSHashTable } diff --git a/HardcoreData/ManagedObjectListObserver.swift b/HardcoreData/ManagedObjectListObserver.swift index 3d9d22d..942800b 100644 --- a/HardcoreData/ManagedObjectListObserver.swift +++ b/HardcoreData/ManagedObjectListObserver.swift @@ -45,33 +45,17 @@ public protocol ManagedObjectListObserver: class { // func managedObjectList(listController: ManagedObjectListController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int) - func managedObjectList(listController: ManagedObjectListController, didInsertObject object: EntityType, toItemIndex itemIndex: Int) + func managedObjectList(listController: ManagedObjectListController, didInsertObject object: EntityType, toIndexPath indexPath: NSIndexPath) - func managedObjectList(listController: ManagedObjectListController, didDeleteObject object: EntityType, fromItemIndex itemIndex: Int) + func managedObjectList(listController: ManagedObjectListController, didDeleteObject object: EntityType, fromIndexPath indexPath: NSIndexPath) - func managedObjectList(listController: ManagedObjectListController, didUpdateObject object: EntityType, atItemIndex itemIndex: Int) + func managedObjectList(listController: ManagedObjectListController, didUpdateObject object: EntityType, atIndexPath indexPath: NSIndexPath) - func managedObjectList(listController: ManagedObjectListController, didMoveObject object: EntityType, fromItemIndex: Int, toItemIndex: Int) + func managedObjectList(listController: ManagedObjectListController, didMoveObject object: EntityType, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) func managedObjectListDidChange(listController: ManagedObjectListController) - -// private func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { -// -// } -// -// private func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { -// -// } -// -// private func controllerWillChangeContent(controller: NSFetchedResultsController) { -// -// } -// -// private func controllerDidChangeContent(controller: NSFetchedResultsController) { -// -// } // // private func controller(controller: NSFetchedResultsController, sectionIndexTitleForSectionName sectionName: String?) -> String? { // diff --git a/HardcoreData/NSManagedObjectContext+HardcoreData.swift b/HardcoreData/NSManagedObjectContext+HardcoreData.swift index 3b6652b..ff5fbb8 100644 --- a/HardcoreData/NSManagedObjectContext+HardcoreData.swift +++ b/HardcoreData/NSManagedObjectContext+HardcoreData.swift @@ -38,14 +38,19 @@ internal extension NSManagedObjectContext { get { - let number: NSNumber? = self.getAssociatedObjectForKey(&PropertyKeys.shouldCascadeSavesToParent) + let number: NSNumber? = getAssociatedObjectForKey( + &PropertyKeys.shouldCascadeSavesToParent, + inObject: self + ) return number?.boolValue ?? false } set { - self.setAssociatedCopiedObject( + setAssociatedCopiedObject( NSNumber(bool: newValue), - forKey: &PropertyKeys.shouldCascadeSavesToParent) + forKey: &PropertyKeys.shouldCascadeSavesToParent, + inObject: self + ) } } @@ -106,13 +111,18 @@ internal extension NSManagedObjectContext { get { - return self.getAssociatedObjectForKey(&PropertyKeys.observerForWillSaveNotification) + return getAssociatedObjectForKey( + &PropertyKeys.observerForWillSaveNotification, + inObject: self + ) } set { - self.setAssociatedRetainedObject( + setAssociatedRetainedObject( newValue, - forKey: &PropertyKeys.observerForWillSaveNotification) + forKey: &PropertyKeys.observerForWillSaveNotification, + inObject: self + ) } } } diff --git a/HardcoreData/NSManagedObjectContext+Setup.swift b/HardcoreData/NSManagedObjectContext+Setup.swift index 4cafca3..3e38ccb 100644 --- a/HardcoreData/NSManagedObjectContext+Setup.swift +++ b/HardcoreData/NSManagedObjectContext+Setup.swift @@ -42,7 +42,7 @@ internal extension NSManagedObjectContext { return parentContext.parentStack } - return self.getAssociatedObjectForKey(&PropertyKeys.parentStack) + return getAssociatedObjectForKey(&PropertyKeys.parentStack, inObject: self) } set { @@ -51,9 +51,11 @@ internal extension NSManagedObjectContext { return } - self.setAssociatedWeakObject( + setAssociatedWeakObject( newValue, - forKey: &PropertyKeys.parentStack) + forKey: &PropertyKeys.parentStack, + inObject: self + ) } } @@ -72,9 +74,9 @@ internal extension NSManagedObjectContext { let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) context.parentContext = rootContext - context.setupForHardcoreDataWithContextName("com.hardcoredata.maincontext") context.shouldCascadeSavesToParent = true context.undoManager = nil + context.setupForHardcoreDataWithContextName("com.hardcoredata.maincontext") context.observerForDidSaveNotification = NotificationObserver( notificationName: NSManagedObjectContextDidSaveNotification, object: rootContext, @@ -104,13 +106,18 @@ internal extension NSManagedObjectContext { get { - return self.getAssociatedObjectForKey(&PropertyKeys.observerForDidSaveNotification) + return getAssociatedObjectForKey( + &PropertyKeys.observerForDidSaveNotification, + inObject: self + ) } set { - self.setAssociatedRetainedObject( + setAssociatedRetainedObject( newValue, - forKey: &PropertyKeys.observerForDidSaveNotification) + forKey: &PropertyKeys.observerForDidSaveNotification, + inObject: self + ) } } } diff --git a/HardcoreData/NSManagedObjectContext+Transaction.swift b/HardcoreData/NSManagedObjectContext+Transaction.swift index 15f6beb..8012a2f 100644 --- a/HardcoreData/NSManagedObjectContext+Transaction.swift +++ b/HardcoreData/NSManagedObjectContext+Transaction.swift @@ -38,13 +38,18 @@ internal extension NSManagedObjectContext { get { - return self.getAssociatedObjectForKey(&PropertyKeys.parentTransaction) + return getAssociatedObjectForKey( + &PropertyKeys.parentTransaction, + inObject: self + ) } set { - self.setAssociatedWeakObject( + setAssociatedWeakObject( newValue, - forKey: &PropertyKeys.parentTransaction) + forKey: &PropertyKeys.parentTransaction, + inObject: self + ) } } diff --git a/HardcoreData/NSObject+HardcoreData.swift b/HardcoreData/NSObject+HardcoreData.swift deleted file mode 100644 index ba20013..0000000 --- a/HardcoreData/NSObject+HardcoreData.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// NSObject+HardcoreData.swift -// HardcoreData -// -// Copyright (c) 2014 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 - - -// MARK: - NSObject - -internal extension NSObject { - - // MARK: Internal - - internal func getAssociatedObjectForKey(key: UnsafePointer) -> T? { - - switch objc_getAssociatedObject(self, key) { - - case let object as T: - return object - - case let object as WeakObject: - return object.object as? T - - default: - return nil - } - } - - internal func setAssociatedRetainedObject(object: T?, forKey key: UnsafePointer) { - - objc_setAssociatedObject(self, key, object, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) - } - - internal func setAssociatedCopiedObject(object: T?, forKey key: UnsafePointer) { - - objc_setAssociatedObject(self, key, object, UInt(OBJC_ASSOCIATION_COPY_NONATOMIC)) - } - - internal func setAssociatedAssignedObject(object: T?, forKey key: UnsafePointer) { - - objc_setAssociatedObject(self, key, object, UInt(OBJC_ASSOCIATION_ASSIGN)) - } - - internal func setAssociatedWeakObject(object: T?, forKey key: UnsafePointer) { - - if let object = object { - - objc_setAssociatedObject(self, key, WeakObject(object), UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) - } - else { - - objc_setAssociatedObject(self, key, nil, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) - } - } -} \ No newline at end of file diff --git a/HardcoreData/NotificationObserver.swift b/HardcoreData/NotificationObserver.swift index b74435e..62c7771 100644 --- a/HardcoreData/NotificationObserver.swift +++ b/HardcoreData/NotificationObserver.swift @@ -44,7 +44,8 @@ internal final class NotificationObserver { notificationName, object: object, queue: nil, - usingBlock: closure) + usingBlock: closure + ) } deinit { @@ -52,6 +53,7 @@ internal final class NotificationObserver { NSNotificationCenter.defaultCenter().removeObserver( self.observer, name: self.notificationName, - object: self.object) + object: self.object + ) } } diff --git a/HardcoreData/Select.swift b/HardcoreData/Select.swift index 9bc8225..02cfdbb 100644 --- a/HardcoreData/Select.swift +++ b/HardcoreData/Select.swift @@ -155,7 +155,7 @@ public struct Select { if fetchRequest.propertiesToFetch != nil { - HardcoreData.log(.Warning, message: "An existing \"propertiesToFetch\" for the <\(NSFetchRequest.self)> was overwritten by <\(self.dynamicType)> query clause.") + HardcoreData.log(.Warning, message: "An existing \"propertiesToFetch\" for the <\(NSFetchRequest.self)> was overwritten by \(typeName(self)) query clause.") } fetchRequest.includesPendingChanges = false @@ -177,7 +177,7 @@ public struct Select { } else { - HardcoreData.log(.Warning, message: "The property \"\(keyPath)\" does not exist in entity <\(entityDescription.managedObjectClassName)> and will be ignored by <\(self.dynamicType)> query clause.") + HardcoreData.log(.Warning, message: "The property \"\(keyPath)\" does not exist in entity <\(entityDescription.managedObjectClassName)> and will be ignored by \(typeName(self)) query clause.") } case .Aggregate(let function, let keyPath, let alias): @@ -195,7 +195,7 @@ public struct Select { } else { - HardcoreData.log(.Warning, message: "The attribute \"\(keyPath)\" does not exist in entity <\(entityDescription.managedObjectClassName)> and will be ignored by <\(self.dynamicType)> query clause.") + HardcoreData.log(.Warning, message: "The attribute \"\(keyPath)\" does not exist in entity <\(entityDescription.managedObjectClassName)> and will be ignored by \(typeName(self)) query clause.") } } } diff --git a/HardcoreData/SortedBy.swift b/HardcoreData/SortedBy.swift index 3abd804..b594e0b 100644 --- a/HardcoreData/SortedBy.swift +++ b/HardcoreData/SortedBy.swift @@ -98,7 +98,7 @@ public struct SortedBy: FetchClause { if fetchRequest.sortDescriptors != nil { - HardcoreData.log(.Warning, message: "Existing sortDescriptors for the <\(NSFetchRequest.self)> was overwritten by <\(self.dynamicType)> query clause.") + HardcoreData.log(.Warning, message: "Existing sortDescriptors for the <\(NSFetchRequest.self)> was overwritten by \(typeName(self)) query clause.") } fetchRequest.sortDescriptors = self.sortDescriptors diff --git a/HardcoreData/SynchronousDataTransaction.swift b/HardcoreData/SynchronousDataTransaction.swift index c293f9e..a080b4c 100644 --- a/HardcoreData/SynchronousDataTransaction.swift +++ b/HardcoreData/SynchronousDataTransaction.swift @@ -20,8 +20,8 @@ public final class SynchronousDataTransaction: BaseDataTransaction { */ public func commitAndWait() { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a <\(self.dynamicType)> outside its designated queue.") - HardcoreData.assert(!self.isCommitted, "Attempted to commit a <\(self.dynamicType)> more than once.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to commit a \(typeName(self)) outside its designated queue.") + HardcoreData.assert(!self.isCommitted, "Attempted to commit a \(typeName(self)) more than once.") self.isCommitted = true self.result = self.context.saveSynchronously() @@ -35,8 +35,8 @@ public final class SynchronousDataTransaction: BaseDataTransaction { */ public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? { - HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to begin a child transaction from a <\(self.dynamicType)> outside its designated queue.") - HardcoreData.assert(!self.isCommitted, "Attempted to begin a child transaction from an already committed <\(self.dynamicType)>.") + HardcoreData.assert(self.transactionQueue.isCurrentExecutionContext(), "Attempted to begin a child transaction from a \(typeName(self)) outside its designated queue.") + HardcoreData.assert(!self.isCommitted, "Attempted to begin a child transaction from an already committed \(typeName(self)).") return SynchronousDataTransaction( mainContext: self.context, @@ -55,7 +55,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction { */ public override func create(entity: T.Type) -> T { - HardcoreData.assert(!self.isCommitted, "Attempted to create an entity of type <\(entity)> from an already committed <\(self.dynamicType)>.") + HardcoreData.assert(!self.isCommitted, "Attempted to create an entity of type <\(entity)> from an already committed \(typeName(self)).") return super.create(entity) } @@ -68,7 +68,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction { */ public override func fetch(object: T) -> T? { - HardcoreData.assert(!self.isCommitted, "Attempted to update an entity of type <\(object.dynamicType)> from an already committed <\(self.dynamicType)>.") + HardcoreData.assert(!self.isCommitted, "Attempted to update an entity of type \(typeName(object)) from an already committed \(typeName(self)).") return super.fetch(object) } @@ -80,7 +80,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction { */ public override func delete(object: NSManagedObject) { - HardcoreData.assert(!self.isCommitted, "Attempted to delete an entity of type <\(object.dynamicType)> from an already committed <\(self.dynamicType)>.") + HardcoreData.assert(!self.isCommitted, "Attempted to delete an entity of type \(typeName(object)) from an already committed \(typeName(self)).") super.delete(object) } @@ -90,7 +90,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction { */ public override func rollback() { - HardcoreData.assert(!self.isCommitted, "Attempted to rollback an already committed <\(self.dynamicType)>.") + HardcoreData.assert(!self.isCommitted, "Attempted to rollback an already committed \(typeName(self)).") super.rollback() } @@ -105,7 +105,7 @@ public final class SynchronousDataTransaction: BaseDataTransaction { self.closure(transaction: self) if !self.isCommitted && self.hasChanges { - HardcoreData.log(.Warning, message: "The closure for the <\(self.dynamicType)> completed without being committed. All changes made within the transaction were discarded.") + HardcoreData.log(.Warning, message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.") } } return self.result diff --git a/HardcoreData/Where.swift b/HardcoreData/Where.swift index aa8d2b8..73f31f3 100644 --- a/HardcoreData/Where.swift +++ b/HardcoreData/Where.swift @@ -89,7 +89,7 @@ public struct Where: FetchClause { if fetchRequest.predicate != nil { - HardcoreData.log(.Warning, message: "An existing predicate for the <\(NSFetchRequest.self)> was overwritten by <\(self.dynamicType)> query clause.") + HardcoreData.log(.Warning, message: "An existing predicate for the <\(NSFetchRequest.self)> was overwritten by \(typeName(self)) query clause.") } fetchRequest.predicate = self.predicate diff --git a/HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.pbxproj b/HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f13caf5 --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.pbxproj @@ -0,0 +1,553 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54AAD4E1AF4D26E00848AE0 /* AppDelegate.swift */; }; + B54AAD521AF4D26E00848AE0 /* HardcoreDataDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B54AAD501AF4D26E00848AE0 /* HardcoreDataDemo.xcdatamodeld */; }; + B54AAD541AF4D26E00848AE0 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54AAD531AF4D26E00848AE0 /* MasterViewController.swift */; }; + B54AAD561AF4D26E00848AE0 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54AAD551AF4D26E00848AE0 /* DetailViewController.swift */; }; + B54AAD591AF4D26E00848AE0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD571AF4D26E00848AE0 /* Main.storyboard */; }; + B54AAD5B1AF4D26E00848AE0 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */; }; + B54AAD5E1AF4D26E00848AE0 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */; }; + B54AAD6A1AF4D26E00848AE0 /* HardcoreDataDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54AAD691AF4D26E00848AE0 /* HardcoreDataDemoTests.swift */; }; + B583A9201AF5F542001F76AF /* HardcoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B583A91B1AF5F4F4001F76AF /* HardcoreData.framework */; }; + B583A9211AF5F542001F76AF /* HardcoreData.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B583A91B1AF5F4F4001F76AF /* HardcoreData.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + B583A92B1AF5FCE6001F76AF /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = B583A92A1AF5FCE6001F76AF /* Event.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + B54AAD641AF4D26E00848AE0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B54AAD411AF4D26E00848AE0 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B54AAD481AF4D26E00848AE0; + remoteInfo = HardcoreDataDemo; + }; + B583A91A1AF5F4F4001F76AF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B583A9141AF5F4F3001F76AF /* HardcoreData.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2F03A53019C5C6DA005002A5; + remoteInfo = HardcoreData; + }; + B583A91C1AF5F4F4001F76AF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B583A9141AF5F4F3001F76AF /* HardcoreData.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2F03A53B19C5C6DA005002A5; + remoteInfo = HardcoreDataTests; + }; + B583A91E1AF5F512001F76AF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B583A9141AF5F4F3001F76AF /* HardcoreData.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 2F03A52F19C5C6DA005002A5; + remoteInfo = HardcoreData; + }; + B583A9221AF5F542001F76AF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B583A9141AF5F4F3001F76AF /* HardcoreData.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 2F03A52F19C5C6DA005002A5; + remoteInfo = HardcoreData; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + B583A9241AF5F542001F76AF /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + B583A9211AF5F542001F76AF /* HardcoreData.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + B54AAD491AF4D26E00848AE0 /* HardcoreDataDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HardcoreDataDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B54AAD4D1AF4D26E00848AE0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B54AAD4E1AF4D26E00848AE0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + B54AAD511AF4D26E00848AE0 /* HardcoreDataDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = HardcoreDataDemo.xcdatamodel; sourceTree = ""; }; + B54AAD531AF4D26E00848AE0 /* MasterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = ""; }; + B54AAD551AF4D26E00848AE0 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; + B54AAD581AF4D26E00848AE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + B54AAD5D1AF4D26E00848AE0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + B54AAD631AF4D26E00848AE0 /* HardcoreDataDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HardcoreDataDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + B54AAD681AF4D26E00848AE0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + B54AAD691AF4D26E00848AE0 /* HardcoreDataDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HardcoreDataDemoTests.swift; sourceTree = ""; }; + B583A9141AF5F4F3001F76AF /* HardcoreData.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = HardcoreData.xcodeproj; path = ../HardcoreData.xcodeproj; sourceTree = ""; }; + B583A9251AF5F547001F76AF /* GCDKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = GCDKit.framework; path = "/Users/johnestropia/Library/Developer/Xcode/DerivedData/HardcoreDataDemo-ftknhsqfpsthfogvisxisgpbbhsj/Build/Products/Debug-iphoneos/GCDKit.framework"; sourceTree = ""; }; + B583A92A1AF5FCE6001F76AF /* Event.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B54AAD461AF4D26E00848AE0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B583A9201AF5F542001F76AF /* HardcoreData.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B54AAD601AF4D26E00848AE0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B54AAD401AF4D26E00848AE0 = { + isa = PBXGroup; + children = ( + B583A9251AF5F547001F76AF /* GCDKit.framework */, + B583A9141AF5F4F3001F76AF /* HardcoreData.xcodeproj */, + B54AAD4B1AF4D26E00848AE0 /* HardcoreDataDemo */, + B54AAD661AF4D26E00848AE0 /* HardcoreDataDemoTests */, + B54AAD4A1AF4D26E00848AE0 /* Products */, + ); + sourceTree = ""; + }; + B54AAD4A1AF4D26E00848AE0 /* Products */ = { + isa = PBXGroup; + children = ( + B54AAD491AF4D26E00848AE0 /* HardcoreDataDemo.app */, + B54AAD631AF4D26E00848AE0 /* HardcoreDataDemoTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + B54AAD4B1AF4D26E00848AE0 /* HardcoreDataDemo */ = { + isa = PBXGroup; + children = ( + B54AAD4E1AF4D26E00848AE0 /* AppDelegate.swift */, + B54AAD531AF4D26E00848AE0 /* MasterViewController.swift */, + B54AAD551AF4D26E00848AE0 /* DetailViewController.swift */, + B54AAD571AF4D26E00848AE0 /* Main.storyboard */, + B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */, + B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */, + B583A92A1AF5FCE6001F76AF /* Event.swift */, + B54AAD501AF4D26E00848AE0 /* HardcoreDataDemo.xcdatamodeld */, + B54AAD4C1AF4D26E00848AE0 /* Supporting Files */, + ); + path = HardcoreDataDemo; + sourceTree = ""; + }; + B54AAD4C1AF4D26E00848AE0 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + B54AAD4D1AF4D26E00848AE0 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + B54AAD661AF4D26E00848AE0 /* HardcoreDataDemoTests */ = { + isa = PBXGroup; + children = ( + B54AAD691AF4D26E00848AE0 /* HardcoreDataDemoTests.swift */, + B54AAD671AF4D26E00848AE0 /* Supporting Files */, + ); + path = HardcoreDataDemoTests; + sourceTree = ""; + }; + B54AAD671AF4D26E00848AE0 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + B54AAD681AF4D26E00848AE0 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + B583A9151AF5F4F3001F76AF /* Products */ = { + isa = PBXGroup; + children = ( + B583A91B1AF5F4F4001F76AF /* HardcoreData.framework */, + B583A91D1AF5F4F4001F76AF /* HardcoreDataTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B54AAD481AF4D26E00848AE0 /* HardcoreDataDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = B54AAD6D1AF4D26E00848AE0 /* Build configuration list for PBXNativeTarget "HardcoreDataDemo" */; + buildPhases = ( + B54AAD451AF4D26E00848AE0 /* Sources */, + B54AAD461AF4D26E00848AE0 /* Frameworks */, + B54AAD471AF4D26E00848AE0 /* Resources */, + B583A9241AF5F542001F76AF /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B583A91F1AF5F512001F76AF /* PBXTargetDependency */, + B583A9231AF5F542001F76AF /* PBXTargetDependency */, + ); + name = HardcoreDataDemo; + productName = HardcoreDataDemo; + productReference = B54AAD491AF4D26E00848AE0 /* HardcoreDataDemo.app */; + productType = "com.apple.product-type.application"; + }; + B54AAD621AF4D26E00848AE0 /* HardcoreDataDemoTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = B54AAD701AF4D26E00848AE0 /* Build configuration list for PBXNativeTarget "HardcoreDataDemoTests" */; + buildPhases = ( + B54AAD5F1AF4D26E00848AE0 /* Sources */, + B54AAD601AF4D26E00848AE0 /* Frameworks */, + B54AAD611AF4D26E00848AE0 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + B54AAD651AF4D26E00848AE0 /* PBXTargetDependency */, + ); + name = HardcoreDataDemoTests; + productName = HardcoreDataDemoTests; + productReference = B54AAD631AF4D26E00848AE0 /* HardcoreDataDemoTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B54AAD411AF4D26E00848AE0 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0630; + ORGANIZATIONNAME = "John Rommel Estropia"; + TargetAttributes = { + B54AAD481AF4D26E00848AE0 = { + CreatedOnToolsVersion = 6.3; + }; + B54AAD621AF4D26E00848AE0 = { + CreatedOnToolsVersion = 6.3; + TestTargetID = B54AAD481AF4D26E00848AE0; + }; + }; + }; + buildConfigurationList = B54AAD441AF4D26E00848AE0 /* Build configuration list for PBXProject "HardcoreDataDemo" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B54AAD401AF4D26E00848AE0; + productRefGroup = B54AAD4A1AF4D26E00848AE0 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = B583A9151AF5F4F3001F76AF /* Products */; + ProjectRef = B583A9141AF5F4F3001F76AF /* HardcoreData.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + B54AAD481AF4D26E00848AE0 /* HardcoreDataDemo */, + B54AAD621AF4D26E00848AE0 /* HardcoreDataDemoTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + B583A91B1AF5F4F4001F76AF /* HardcoreData.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = HardcoreData.framework; + remoteRef = B583A91A1AF5F4F4001F76AF /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + B583A91D1AF5F4F4001F76AF /* HardcoreDataTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = HardcoreDataTests.xctest; + remoteRef = B583A91C1AF5F4F4001F76AF /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + B54AAD471AF4D26E00848AE0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B54AAD591AF4D26E00848AE0 /* Main.storyboard in Resources */, + B54AAD5E1AF4D26E00848AE0 /* LaunchScreen.xib in Resources */, + B54AAD5B1AF4D26E00848AE0 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B54AAD611AF4D26E00848AE0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B54AAD451AF4D26E00848AE0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B54AAD521AF4D26E00848AE0 /* HardcoreDataDemo.xcdatamodeld in Sources */, + B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */, + B54AAD541AF4D26E00848AE0 /* MasterViewController.swift in Sources */, + B54AAD561AF4D26E00848AE0 /* DetailViewController.swift in Sources */, + B583A92B1AF5FCE6001F76AF /* Event.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B54AAD5F1AF4D26E00848AE0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B54AAD6A1AF4D26E00848AE0 /* HardcoreDataDemoTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + B54AAD651AF4D26E00848AE0 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B54AAD481AF4D26E00848AE0 /* HardcoreDataDemo */; + targetProxy = B54AAD641AF4D26E00848AE0 /* PBXContainerItemProxy */; + }; + B583A91F1AF5F512001F76AF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = HardcoreData; + targetProxy = B583A91E1AF5F512001F76AF /* PBXContainerItemProxy */; + }; + B583A9231AF5F542001F76AF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = HardcoreData; + targetProxy = B583A9221AF5F542001F76AF /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + B54AAD571AF4D26E00848AE0 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + B54AAD581AF4D26E00848AE0 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + B54AAD5D1AF4D26E00848AE0 /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + B54AAD6B1AF4D26E00848AE0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + B54AAD6C1AF4D26E00848AE0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B54AAD6E1AF4D26E00848AE0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/HardcoreDataDemo-ftknhsqfpsthfogvisxisgpbbhsj/Build/Products/Debug-iphoneos", + ); + INFOPLIST_FILE = HardcoreDataDemo/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B54AAD6F1AF4D26E00848AE0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/HardcoreDataDemo-ftknhsqfpsthfogvisxisgpbbhsj/Build/Products/Debug-iphoneos", + ); + INFOPLIST_FILE = HardcoreDataDemo/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + B54AAD711AF4D26E00848AE0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = HardcoreDataDemoTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HardcoreDataDemo.app/HardcoreDataDemo"; + }; + name = Debug; + }; + B54AAD721AF4D26E00848AE0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = HardcoreDataDemoTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HardcoreDataDemo.app/HardcoreDataDemo"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B54AAD441AF4D26E00848AE0 /* Build configuration list for PBXProject "HardcoreDataDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B54AAD6B1AF4D26E00848AE0 /* Debug */, + B54AAD6C1AF4D26E00848AE0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B54AAD6D1AF4D26E00848AE0 /* Build configuration list for PBXNativeTarget "HardcoreDataDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B54AAD6E1AF4D26E00848AE0 /* Debug */, + B54AAD6F1AF4D26E00848AE0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B54AAD701AF4D26E00848AE0 /* Build configuration list for PBXNativeTarget "HardcoreDataDemoTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B54AAD711AF4D26E00848AE0 /* Debug */, + B54AAD721AF4D26E00848AE0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCVersionGroup section */ + B54AAD501AF4D26E00848AE0 /* HardcoreDataDemo.xcdatamodeld */ = { + isa = XCVersionGroup; + children = ( + B54AAD511AF4D26E00848AE0 /* HardcoreDataDemo.xcdatamodel */, + ); + currentVersion = B54AAD511AF4D26E00848AE0 /* HardcoreDataDemo.xcdatamodel */; + path = HardcoreDataDemo.xcdatamodeld; + sourceTree = ""; + versionGroupType = wrapper.xcdatamodel; + }; +/* End XCVersionGroup section */ + }; + rootObject = B54AAD411AF4D26E00848AE0 /* Project object */; +} diff --git a/HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..8443451 --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace/xcshareddata/HardcoreDataDemo.xccheckout b/HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace/xcshareddata/HardcoreDataDemo.xccheckout new file mode 100644 index 0000000..b520449 --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace/xcshareddata/HardcoreDataDemo.xccheckout @@ -0,0 +1,53 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 7C5E31AC-5DD0-43DA-A5C6-AF73B4532D86 + IDESourceControlProjectName + project + IDESourceControlProjectOriginsDictionary + + 4B60F1BCB491FF717C56441AE7783C74F417BE48 + github.com:JohnEstropia/HardcoreData.git + 8B2E522D57154DFA93A06982C36315ECBEA4FA97 + github.com:JohnEstropia/GCDKit.git + + IDESourceControlProjectPath + HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace + IDESourceControlProjectRelativeInstallPathDictionary + + 4B60F1BCB491FF717C56441AE7783C74F417BE48 + ../../.. + 8B2E522D57154DFA93A06982C36315ECBEA4FA97 + ../../../Libraries/GCDKit + + IDESourceControlProjectURL + github.com:JohnEstropia/HardcoreData.git + IDESourceControlProjectVersion + 111 + IDESourceControlProjectWCCIdentifier + 4B60F1BCB491FF717C56441AE7783C74F417BE48 + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 8B2E522D57154DFA93A06982C36315ECBEA4FA97 + IDESourceControlWCCName + GCDKit + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 4B60F1BCB491FF717C56441AE7783C74F417BE48 + IDESourceControlWCCName + HardcoreData + + + + diff --git a/HardcoreDataDemo/HardcoreDataDemo/AppDelegate.swift b/HardcoreDataDemo/HardcoreDataDemo/AppDelegate.swift new file mode 100644 index 0000000..c36a14e --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo/AppDelegate.swift @@ -0,0 +1,27 @@ +// +// AppDelegate.swift +// HardcoreDataDemo +// +// Created by John Rommel Estropia on 2015/05/02. +// Copyright (c) 2015 John Rommel Estropia. All rights reserved. +// + +import UIKit +import HardcoreData + + +// MARK: - AppDelegate + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + // MARK: UIApplicationDelegate + + var window: UIWindow? + + func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + + return true + } +} + diff --git a/HardcoreDataDemo/HardcoreDataDemo/Base.lproj/LaunchScreen.xib b/HardcoreDataDemo/HardcoreDataDemo/Base.lproj/LaunchScreen.xib new file mode 100644 index 0000000..0855330 --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo/Base.lproj/LaunchScreen.xib @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HardcoreDataDemo/HardcoreDataDemo/Base.lproj/Main.storyboard b/HardcoreDataDemo/HardcoreDataDemo/Base.lproj/Main.storyboard new file mode 100644 index 0000000..c223371 --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo/Base.lproj/Main.storyboard @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HardcoreDataDemo/HardcoreDataDemo/DetailViewController.swift b/HardcoreDataDemo/HardcoreDataDemo/DetailViewController.swift new file mode 100644 index 0000000..1271414 --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo/DetailViewController.swift @@ -0,0 +1,45 @@ +// +// DetailViewController.swift +// HardcoreDataDemo +// +// Created by John Rommel Estropia on 2015/05/02. +// Copyright (c) 2015 John Rommel Estropia. All rights reserved. +// + +import UIKit + +class DetailViewController: UIViewController { + + @IBOutlet weak var detailDescriptionLabel: UILabel! + + + var detailItem: AnyObject? { + didSet { + // Update the view. + self.configureView() + } + } + + func configureView() { + // Update the user interface for the detail item. + if let detail: AnyObject = self.detailItem { + if let label = self.detailDescriptionLabel { + label.text = detail.valueForKey("timeStamp")!.description + } + } + } + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view, typically from a nib. + self.configureView() + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + +} + diff --git a/HardcoreDataDemo/HardcoreDataDemo/Event.swift b/HardcoreDataDemo/HardcoreDataDemo/Event.swift new file mode 100644 index 0000000..23ff52c --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo/Event.swift @@ -0,0 +1,16 @@ +// +// Event.swift +// HardcoreDataDemo +// +// Created by John Rommel Estropia on 2015/05/03. +// Copyright (c) 2015 John Rommel Estropia. All rights reserved. +// + +import Foundation +import CoreData + +class Event: NSManagedObject { + + @NSManaged var timeStamp: NSDate + +} diff --git a/HardcoreDataDemo/HardcoreDataDemo/HardcoreDataDemo.xcdatamodeld/.xccurrentversion b/HardcoreDataDemo/HardcoreDataDemo/HardcoreDataDemo.xcdatamodeld/.xccurrentversion new file mode 100644 index 0000000..e548f2e --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo/HardcoreDataDemo.xcdatamodeld/.xccurrentversion @@ -0,0 +1,8 @@ + + + + + _XCCurrentVersionName + HardcoreDataDemo.xcdatamodel + + diff --git a/HardcoreDataDemo/HardcoreDataDemo/HardcoreDataDemo.xcdatamodeld/HardcoreDataDemo.xcdatamodel/contents b/HardcoreDataDemo/HardcoreDataDemo/HardcoreDataDemo.xcdatamodeld/HardcoreDataDemo.xcdatamodel/contents new file mode 100644 index 0000000..44419ea --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo/HardcoreDataDemo.xcdatamodeld/HardcoreDataDemo.xcdatamodel/contents @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/HardcoreDataDemo/HardcoreDataDemo/Images.xcassets/AppIcon.appiconset/Contents.json b/HardcoreDataDemo/HardcoreDataDemo/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/HardcoreDataDemo/HardcoreDataDemo/Info.plist b/HardcoreDataDemo/HardcoreDataDemo/Info.plist new file mode 100644 index 0000000..9bbdb32 --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo/Info.plist @@ -0,0 +1,50 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + com.johnestropia.HardcoreDataDemo + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/HardcoreDataDemo/HardcoreDataDemo/MasterViewController.swift b/HardcoreDataDemo/HardcoreDataDemo/MasterViewController.swift new file mode 100644 index 0000000..5a553e8 --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemo/MasterViewController.swift @@ -0,0 +1,137 @@ +// +// MasterViewController.swift +// HardcoreDataDemo +// +// Created by John Rommel Estropia on 2015/05/02. +// Copyright (c) 2015 John Rommel Estropia. All rights reserved. +// + +import UIKit +import HardcoreData + + +// MARK: - MasterViewController + +class MasterViewController: UITableViewController, ManagedObjectListObserver { + + // MARK: UIViewController + + override func viewDidLoad() { + + super.viewDidLoad() + + self.navigationItem.leftBarButtonItem = self.editButtonItem() + self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "addBarButtonItemTouched:") + + self.list.addObserver(self) + } + + + // MARK: UITableViewController + + required init!(coder aDecoder: NSCoder!) { + + HardcoreData.defaultStack.addSQLiteStore() + self.list = HardcoreData.defaultStack.observeObjectList( + From(Event), + SortedBy(.Ascending("timeStamp")) + ) + super.init(coder: aDecoder) + } + + + // MARK: UITableViewDataSource + + override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + + return self.list.numberOfSections() + } + + override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + + return self.list.numberOfItemsInSection(section) + } + + override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + + let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell") as! UITableViewCell + cell.textLabel?.text = "\(self.list[indexPath].timeStamp)" + return cell + } + + + // MARK: UITableViewDelegate + +// override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { +// +// super.tableView(tableView, didSelectRowAtIndexPath: indexPath) +// } + + override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { + + switch editingStyle { + + case .Delete: + let event = self.list[indexPath] + HardcoreData.beginAsynchronous{ (transaction) -> Void in + + transaction.delete(transaction.fetch(event)!) + transaction.commit { (result) -> Void in } + } + + default: + break + } + } + +// optional func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) + + + // MARK: ManagedObjectListObserver + + func managedObjectListWillChange(listController: ManagedObjectListController) { + + self.tableView.beginUpdates() + } + + func managedObjectList(listController: ManagedObjectListController, didInsertObject object: Event, toIndexPath indexPath: NSIndexPath) { + + self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) + } + + func managedObjectList(listController: ManagedObjectListController, didDeleteObject object: Event, fromIndexPath indexPath: NSIndexPath) { + + self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) + } + + func managedObjectList(listController: ManagedObjectListController, didUpdateObject object: Event, atIndexPath indexPath: NSIndexPath) { + + self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic) + } + + func managedObjectList(listController: ManagedObjectListController, didMoveObject object: Event, fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) { + + self.tableView.moveRowAtIndexPath(fromIndexPath, toIndexPath: toIndexPath) + } + + func managedObjectListDidChange(listController: ManagedObjectListController) { + + self.tableView.endUpdates() + } + + // MARK: Private + + let list: ManagedObjectListController + + @objc dynamic func addBarButtonItemTouched(sender: AnyObject!) { + + HardcoreData.beginAsynchronous { (transaction) -> Void in + + let event = transaction.create(Event) + event.timeStamp = NSDate() + + transaction.commit { (result) -> Void in } + } + } +} + diff --git a/HardcoreDataDemo/HardcoreDataDemoTests/HardcoreDataDemoTests.swift b/HardcoreDataDemo/HardcoreDataDemoTests/HardcoreDataDemoTests.swift new file mode 100644 index 0000000..d506eb4 --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemoTests/HardcoreDataDemoTests.swift @@ -0,0 +1,36 @@ +// +// HardcoreDataDemoTests.swift +// HardcoreDataDemoTests +// +// Created by John Rommel Estropia on 2015/05/02. +// Copyright (c) 2015 John Rommel Estropia. All rights reserved. +// + +import UIKit +import XCTest + +class HardcoreDataDemoTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + XCTAssert(true, "Pass") + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measureBlock() { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/HardcoreDataDemo/HardcoreDataDemoTests/Info.plist b/HardcoreDataDemo/HardcoreDataDemoTests/Info.plist new file mode 100644 index 0000000..e047843 --- /dev/null +++ b/HardcoreDataDemo/HardcoreDataDemoTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + com.johnestropia.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/HardcoreDataTests/HardcoreDataTests.swift b/HardcoreDataTests/HardcoreDataTests.swift index 94de683..0ac7eb2 100644 --- a/HardcoreDataTests/HardcoreDataTests.swift +++ b/HardcoreDataTests/HardcoreDataTests.swift @@ -47,7 +47,7 @@ class HardcoreDataTests: XCTestCase { HardcoreData.defaultStack = stack XCTAssert(HardcoreData.defaultStack === stack, "HardcoreData.defaultStack === stack") - switch stack.addSQLiteStore("Config1Store.sqlite", configuration: "Config1", resetStoreOnMigrationFailure: true){ + switch stack.addSQLiteStore("ConfigStore1.sqlite", configuration: "Config1", resetStoreOnMigrationFailure: true){ case .Failure(let error): XCTFail(error.description) @@ -56,7 +56,7 @@ class HardcoreDataTests: XCTestCase { break } - switch stack.addSQLiteStore("Config2Store.sqlite", configuration: "Config2", resetStoreOnMigrationFailure: true){ + switch stack.addSQLiteStore("ConfigStore2.sqlite", configuration: "Config2", resetStoreOnMigrationFailure: true){ case .Failure(let error): XCTFail(error.description)