diff --git a/DTModelStorage/Core/DTBaseStorage.h b/DTModelStorage/Core/DTBaseStorage.h new file mode 100644 index 00000000..8e31b648 --- /dev/null +++ b/DTModelStorage/Core/DTBaseStorage.h @@ -0,0 +1,33 @@ +// +// DTBaseStorage.h +// DTModelStorageTests +// +// Created by Denys Telezhkin on 12.10.14. +// Copyright (c) 2014 Denys Telezhkin. All rights reserved. +// + +#import +#import "DTStorageProtocol.h" + +/** + DTBaseStorage is a base class for storage classes. + */ + +@interface DTBaseStorage : NSObject + +/** + Supplementary header kind, that is used for registration and mapping. For example, for UICollectionView this should be UICollectionElementKindHeader. + */ +@property (nonatomic, strong) NSString * supplementaryHeaderKind; + +/** + Supplementary footer kind, that is used for registration and mapping. For example, for UICollectionView this should be UICollectionElementKindFooter. + */ +@property (nonatomic, strong) NSString * supplementaryFooterKind; + +/** + Delegate property used to transfer current data storage changes. + */ +@property (nonatomic, weak) id delegate; + +@end diff --git a/DTModelStorage/Core/DTBaseStorage.m b/DTModelStorage/Core/DTBaseStorage.m new file mode 100644 index 00000000..0a5f98d9 --- /dev/null +++ b/DTModelStorage/Core/DTBaseStorage.m @@ -0,0 +1,13 @@ +// +// DTBaseStorage.m +// DTModelStorageTests +// +// Created by Denys Telezhkin on 12.10.14. +// Copyright (c) 2014 Denys Telezhkin. All rights reserved. +// + +#import "DTBaseStorage.h" + +@implementation DTBaseStorage + +@end diff --git a/DTModelStorage/Core/DTSection.h b/DTModelStorage/Core/DTSection.h index 45b90ddd..3a7b0c7c 100644 --- a/DTModelStorage/Core/DTSection.h +++ b/DTModelStorage/Core/DTSection.h @@ -24,7 +24,7 @@ // THE SOFTWARE. /** - `DTSection` protocol defines an interface for sections returned by DTModelStorage object. For `DTMemoryStorage`, `DTSectionModel` is the object, conforming to current protocol. For `DTCoreDataStorage` NSFetchedResultsController returns `NSFetchedResultsSectionInfo` object, that also conform to current protocol. + `DTSection` protocol defines an interface for sections returned by DTModelStorage object. For `DTMemoryStorage`, `DTSectionModel` is the object, conforming to current protocol. For `DTCoreDataStorage` NSFetchedResultsController returns `NSFetchedResultsSectionInfo` object, that also conforms to current protocol. */ @protocol DTSection diff --git a/DTModelStorage/Core/DTStorage.h b/DTModelStorage/Core/DTStorageProtocol.h similarity index 77% rename from DTModelStorage/Core/DTStorage.h rename to DTModelStorage/Core/DTStorageProtocol.h index b02564c9..dbd3ee2b 100644 --- a/DTModelStorage/Core/DTStorage.h +++ b/DTModelStorage/Core/DTStorageProtocol.h @@ -24,29 +24,13 @@ // THE SOFTWARE. #import "DTStorageUpdate.h" - -/** - `DTStorageUpdating` protocol is used to transfer data storage updates. - */ - -@protocol DTStorageUpdating - -@optional - -/** - This method transfers data storage updates. Controller, that implements this method, may react to received update by updating it's UI. - - @param update `DTStorageUpdate` instance, that incapsulates all changes, happened in data storage. - */ -- (void)storageDidPerformUpdate:(DTStorageUpdate *)update; - -@end +#import "DTStorageUpdating.h" /** `DTStorage` protocol is used to define common interface for storage classes. */ -@protocol DTStorage +@protocol DTStorageProtocol /** Array of sections, conforming to `DTSection` protocol. Depending on data storage used, section objects may be different. @@ -57,7 +41,7 @@ - (NSArray*)sections; /** - Returns item at concrete indexPath. This method is used for perfomance reasons. For example, when DTCoreDataStorage is used, calling objects method will fetch all the objects from fetchRequest, bu we want to fetch only one. + Returns item at concrete indexPath. This method is used for perfomance reasons. For example, when DTCoreDataStorage is used, calling objects method will fetch all the objects from fetchRequest, but we want to fetch only one. @param indexPath indexPath of desired item @@ -72,6 +56,28 @@ @optional +///----------------------------------------------------------- +/// @name Setting and getting supplementary models +///----------------------------------------------------------- + +/** + Getter method for header model for current section. + + @param index Number of section. + + @return Header model for section at index. + */ +- (id)headerModelForSectionIndex:(NSInteger)index; + +/** + Getter method for footer model for current section. + + @param index Number of section. + + @return Footer model for section at index. + */ +- (id)footerModelForSectionIndex:(NSInteger)index; + /** Storage class may implement this method to define supplementary models for section. @@ -85,6 +91,10 @@ - (id)supplementaryModelOfKind:(NSString *)kind forSectionIndex:(NSUInteger)sectionNumber; +///----------------------------------------------------------- +/// @name Searching +///----------------------------------------------------------- + /** Method to create filtered data storage, based on current data storage and passed searchString and searchScope. diff --git a/DTModelStorage/Core/DTStorageUpdating.h b/DTModelStorage/Core/DTStorageUpdating.h new file mode 100644 index 00000000..2df09cec --- /dev/null +++ b/DTModelStorage/Core/DTStorageUpdating.h @@ -0,0 +1,30 @@ +// +// DTStorageUpdating.h +// DTModelStorageTests +// +// Created by Denys Telezhkin on 12.10.14. +// Copyright (c) 2014 Denys Telezhkin. All rights reserved. +// + +#import +#import "DTStorageUpdate.h" + +/** + `DTStorageUpdating` protocol is used to transfer data storage updates. + */ + +@protocol DTStorageUpdating + +/** + Transfers data storage updates. Controller, that implements this method, may react to received update by updating it's UI. + + @param update `DTStorageUpdate` instance, that incapsulates all changes, happened in data storage. + */ +- (void)storageDidPerformUpdate:(DTStorageUpdate *)update; + +/** + Method is called when UI needs to be fully updated for data storage changes. + */ +- (void)storageNeedsReload; + +@end diff --git a/DTModelStorage/CoreData/DTCoreDataStorage.h b/DTModelStorage/CoreData/DTCoreDataStorage.h index 1f4a3f49..08902ad9 100644 --- a/DTModelStorage/CoreData/DTCoreDataStorage.h +++ b/DTModelStorage/CoreData/DTCoreDataStorage.h @@ -23,14 +23,14 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#import "DTStorage.h" +#import "DTBaseStorage.h" #import /** This class is used to provide CoreData storage. Storage object will automatically react to NSFetchResultsController changes and will call delegate with appropriate DTStorageUpdate object. */ -@interface DTCoreDataStorage : NSObject +@interface DTCoreDataStorage : DTBaseStorage /** Use this method to create `DTCoreDataStorage` object with your NSFetchedResultsController. @@ -42,11 +42,6 @@ +(instancetype)storageWithFetchResultsController:(NSFetchedResultsController *)controller; -/** - Delegate object, that gets notified about data storage updates, in this scenario - NSFetchedResultsController updates. If delegate does not implement `DTStorageUpdating` protocol, it will not get called. - */ -@property (nonatomic, weak) id delegate; - /** NSFetchedResultsController of current `DTCoreDataStorage` object. */ diff --git a/DTModelStorage/CoreData/DTCoreDataStorage.m b/DTModelStorage/CoreData/DTCoreDataStorage.m index 75c56e98..e367747f 100644 --- a/DTModelStorage/CoreData/DTCoreDataStorage.m +++ b/DTModelStorage/CoreData/DTCoreDataStorage.m @@ -52,6 +52,12 @@ - (id)objectAtIndexPath:(NSIndexPath *)indexPath return [self.fetchedResultsController objectAtIndexPath:indexPath]; } +-(id)headerModelForSectionIndex:(NSInteger)index +{ + id section = [self.fetchedResultsController sections][index]; + return section.name; +} + #pragma mark - NSFetchedResultsControllerDelegate methods - (void)startUpdate diff --git a/DTModelStorage/Memory/DTMemoryStorage.h b/DTModelStorage/Memory/DTMemoryStorage.h index c0c6c256..ebd69dfc 100644 --- a/DTModelStorage/Memory/DTMemoryStorage.h +++ b/DTModelStorage/Memory/DTMemoryStorage.h @@ -23,7 +23,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#import "DTStorage.h" +#import "DTBaseStorage.h" #import "DTSectionModel.h" /** @@ -32,7 +32,7 @@ `DTMemoryStorage` stores data models like array of `DTSectionModel` instances. So it's basically array of sections, where each section has an array of objects, and any supplementary models, that further describe current section, and can be used, for example, like section headers and footers. */ -@interface DTMemoryStorage : NSObject +@interface DTMemoryStorage : DTBaseStorage /** Creates `DTMemoryStorage` with default configuration. @@ -49,10 +49,9 @@ @property (nonatomic, strong) NSMutableArray * sections; /** - Delegate object, that gets notified about data storage updates. If delegate does not respond to optional `DTStorageUpdating` methods, it will not get called. + Property to enable/disable logging. Logging is on by default, and will print out any critical messages, that DTMemoryStorage is encountering. */ -@property (nonatomic, weak) id delegate; - +@property (nonatomic, assign) BOOL loggingEnabled; ///--------------------------------------- /// @name Add items ///--------------------------------------- @@ -171,7 +170,30 @@ @param kind Kind of supplementary models */ --(void)setSupplementaries:(NSArray *)supplementaryModels forKind:(NSString *)kind; +- (void)setSupplementaries:(NSArray *)supplementaryModels forKind:(NSString *)kind; + +/** + Set header models for UITableView sections. `DTSectionModel` objects are created automatically, if they don't exist already. Pass nil or empty array to this method to clear all section header models. + + @param headerModels Section header models to use. + */ +- (void)setSectionHeaderModels:(NSArray *)headerModels; + +/** + Set footer models for sections. `headerKind` property is used to define kind of header supplementary. `DTSectionModel` objects are created automatically, if they don't exist already. Pass nil or empty array to this method to clear all section footer models. + + @param footerModels Section footer models to use. + */ +- (void)setSectionFooterModels:(NSArray *)footerModels; + +/** + Remove all items in section and replace them with array of items. After replacement is done, storageNeedsReload delegate method is called. + + @param items Array of models to replace current section contents + + @param sectionNumber number of section + */ +- (void)setItems:(NSArray *)items forSectionIndex:(NSUInteger)sectionIndex; ///--------------------------------------- /// @name Search @@ -217,10 +239,4 @@ typedef BOOL (^DTModelSearchingBlock)(id model, NSString * searchString, NSInteg */ -(NSIndexPath *)indexPathForItem:(id)item; -/** - Property to enable/disable logging. Logging is on by default, and will print out any critical messages, that DTMemoryStorage is encountering. - */ - -@property (nonatomic, assign) BOOL loggingEnabled; - @end diff --git a/DTModelStorage/Memory/DTMemoryStorage.m b/DTModelStorage/Memory/DTMemoryStorage.m index c0c9745d..c7ca47e7 100644 --- a/DTModelStorage/Memory/DTMemoryStorage.m +++ b/DTModelStorage/Memory/DTMemoryStorage.m @@ -89,6 +89,22 @@ - (id)supplementaryModelOfKind:(NSString *)kind forSectionIndex:(NSUInteger)sect return [sectionModel supplementaryModelOfKind:kind]; } +-(id)headerModelForSectionIndex:(NSInteger)index +{ + NSAssert(self.supplementaryHeaderKind, @"supplementaryHeaderKind property was not set before calling headerModelForSectionIndex: method"); + + return [self supplementaryModelOfKind:self.supplementaryHeaderKind + forSectionIndex:index]; +} + +-(id)footerModelForSectionIndex:(NSInteger)index +{ + NSAssert(self.supplementaryFooterKind, @"supplementaryFooterKind property was not set before calling footerModelForSectionIndex: method"); + + return [self supplementaryModelOfKind:self.supplementaryFooterKind + forSectionIndex:index]; +} + - (void)setSupplementaries:(NSArray *)supplementaryModels forKind:(NSString *)kind { [self startUpdate]; @@ -110,6 +126,28 @@ - (void)setSupplementaries:(NSArray *)supplementaryModels forKind:(NSString *)ki [self finishUpdate]; } +- (void)setItems:(NSArray *)items forSectionIndex:(NSUInteger)sectionIndex +{ + DTSectionModel * section = [self sectionAtIndex:sectionIndex]; + [section.objects removeAllObjects]; + [section.objects addObjectsFromArray:items]; + [self.delegate storageNeedsReload]; +} + +-(void)setSectionHeaderModels:(NSArray *)headerModels +{ + NSAssert(self.supplementaryHeaderKind, @"Please set supplementaryHeaderKind property before setting section header models"); + + [self setSupplementaries:headerModels forKind:self.supplementaryHeaderKind]; +} + +-(void)setSectionFooterModels:(NSArray *)footerModels +{ + NSAssert(self.supplementaryFooterKind, @"Please set supplementaryFooterKind property before setting section header models"); + + [self setSupplementaries:footerModels forKind:self.supplementaryFooterKind]; +} + #pragma mark - search - (void)setSearchingBlock:(DTModelSearchingBlock)searchingBlock diff --git a/DTModelStorageTests/DTModelStorageTests.xcodeproj/project.pbxproj b/DTModelStorageTests/DTModelStorageTests.xcodeproj/project.pbxproj index ac50c537..1a503b6c 100644 --- a/DTModelStorageTests/DTModelStorageTests.xcodeproj/project.pbxproj +++ b/DTModelStorageTests/DTModelStorageTests.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 9A7D5BC419D8A0DA0083673D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A7D5BC319D8A0DA0083673D /* UIKit.framework */; }; 9A7D5BC619D8A16E0083673D /* MemoryStorageAddTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A7D5BC519D8A16E0083673D /* MemoryStorageAddTests.m */; }; 9A7D5BC819D8A22C0083673D /* MemoryStorageEditTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A7D5BC719D8A22C0083673D /* MemoryStorageEditTests.m */; }; + 9A88F5A419EAAEFE008436C9 /* DTBaseStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A88F5A319EAAEFE008436C9 /* DTBaseStorage.m */; }; C22A88696901596441D3AB3D /* libPods-XCTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E3B33D6FFCD9F4C66024650B /* libPods-XCTests.a */; }; /* End PBXBuildFile section */ @@ -32,7 +33,7 @@ 95B30BAC1861E6E300AB82AC /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 9A222BBD18670B88004481BA /* DTModelStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTModelStorage.h; sourceTree = ""; }; 9A222BC1186732E0004481BA /* DTSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTSection.h; sourceTree = ""; }; - 9A222BC2186732E0004481BA /* DTStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTStorage.h; sourceTree = ""; }; + 9A222BC2186732E0004481BA /* DTStorageProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTStorageProtocol.h; sourceTree = ""; }; 9A222BC3186732E0004481BA /* DTStorageUpdate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTStorageUpdate.h; sourceTree = ""; }; 9A222BC4186732E0004481BA /* DTStorageUpdate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTStorageUpdate.m; sourceTree = ""; }; 9A222BC6186732E0004481BA /* DTCoreDataStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTCoreDataStorage.h; sourceTree = ""; }; @@ -57,6 +58,9 @@ 9A7D5BC319D8A0DA0083673D /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 9A7D5BC519D8A16E0083673D /* MemoryStorageAddTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MemoryStorageAddTests.m; path = Specs/MemoryStorageAddTests.m; sourceTree = ""; }; 9A7D5BC719D8A22C0083673D /* MemoryStorageEditTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MemoryStorageEditTests.m; path = Specs/MemoryStorageEditTests.m; sourceTree = ""; }; + 9A88F5A119EAA4AF008436C9 /* DTStorageUpdating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTStorageUpdating.h; sourceTree = ""; }; + 9A88F5A219EAAEFE008436C9 /* DTBaseStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTBaseStorage.h; sourceTree = ""; }; + 9A88F5A319EAAEFE008436C9 /* DTBaseStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTBaseStorage.m; sourceTree = ""; }; AA35CA2E18C483B3003858F8 /* DTMemoryStorage+UpdateWithoutAnimations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "DTMemoryStorage+UpdateWithoutAnimations.h"; path = "Utilities/DTMemoryStorage+UpdateWithoutAnimations.h"; sourceTree = ""; }; AA35CA2F18C483B3003858F8 /* DTMemoryStorage+UpdateWithoutAnimations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "DTMemoryStorage+UpdateWithoutAnimations.m"; path = "Utilities/DTMemoryStorage+UpdateWithoutAnimations.m"; sourceTree = ""; }; AA478957187FEFB900E51667 /* DTModelTransfer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DTModelTransfer.h; path = Utilities/DTModelTransfer.h; sourceTree = ""; }; @@ -101,10 +105,13 @@ 9A222BC0186732E0004481BA /* Core */ = { isa = PBXGroup; children = ( - 9A222BC2186732E0004481BA /* DTStorage.h */, + 9A88F5A119EAA4AF008436C9 /* DTStorageUpdating.h */, + 9A222BC2186732E0004481BA /* DTStorageProtocol.h */, 9A222BC1186732E0004481BA /* DTSection.h */, 9A222BC3186732E0004481BA /* DTStorageUpdate.h */, 9A222BC4186732E0004481BA /* DTStorageUpdate.m */, + 9A88F5A219EAAEFE008436C9 /* DTBaseStorage.h */, + 9A88F5A319EAAEFE008436C9 /* DTBaseStorage.m */, ); path = Core; sourceTree = ""; @@ -334,6 +341,7 @@ 9A7D5BB519D860830083673D /* DTRuntimeHelper.m in Sources */, 9A7D5BC619D8A16E0083673D /* MemoryStorageAddTests.m in Sources */, 9A24F69919D949A4009DE5D4 /* SwiftClass.swift in Sources */, + 9A88F5A419EAAEFE008436C9 /* DTBaseStorage.m in Sources */, 9A7D5BB419D860830083673D /* DTMemoryStorage+UpdateWithoutAnimations.m in Sources */, 9A24F69B19D94AFD009DE5D4 /* SwiftProvider.swift in Sources */, 9A24F69219D9405E009DE5D4 /* RuntimeHelperObjectiveCTests.m in Sources */, diff --git a/DTModelStorageTests/XCTests/Specs/MemoryStorageSearchTests.m b/DTModelStorageTests/XCTests/Specs/MemoryStorageSearchTests.m index fabf3523..e01fb55f 100644 --- a/DTModelStorageTests/XCTests/Specs/MemoryStorageSearchTests.m +++ b/DTModelStorageTests/XCTests/Specs/MemoryStorageSearchTests.m @@ -9,7 +9,7 @@ #import "DTMemoryStorage.h" #import "OCMock.h" #import "DTSectionModel.h" -#import "DTStorage.h" +#import "DTBaseStorage.h" @interface MemoryStorageTests : XCTestCase {