From 55e9a0c848ee9d68693de6be54156c248645ea0e Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Sun, 17 Jul 2016 11:02:46 -0700 Subject: [PATCH 01/24] update to swift 2.3, #53 --- Example/Example.xcodeproj/project.pbxproj | 22 +++++++++++-- .../xcshareddata/xcschemes/Example.xcscheme | 2 +- .../ExampleModel.xcodeproj/project.pbxproj | 12 ++++++- .../xcschemes/ExampleModel.xcscheme | 2 +- .../ExampleModel/Sources/CoreDataStack.swift | 8 ++--- Example/ExampleModel/Sources/Thing.swift | 2 +- Example/Sources/Extensions.swift | 32 ++++++++++++------- .../FetchedCollectionViewController.swift | 7 ++-- .../Sources/FetchedTableViewController.swift | 8 +++-- Example/Sources/Helpers.swift | 4 +-- .../UITests/FetchedResultsViewsUITests.swift | 4 +-- Example/UITests/StaticViewsUITests.swift | 4 +-- Example/UITests/XCTestCaseExtensions.swift | 9 +++--- JSQDataSourcesKit.xcodeproj/project.pbxproj | 20 ++++++++++-- .../xcschemes/JSQDataSourcesKit-iOS.xcscheme | 2 +- .../xcschemes/JSQDataSourcesKit-tvOS.xcscheme | 2 +- .../xcschemes/JSQDataSourcesKitTests.xcscheme | 2 +- Tests/DataSourceTests.swift | 6 ++-- Tests/FetchedResultsDelegateTests.swift | 4 +-- 19 files changed, 101 insertions(+), 51 deletions(-) diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index 181f0ba..4a5921f 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -317,19 +317,24 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Hexed Bits"; TargetAttributes = { 886EC7801CFF2C8400BDE6FA = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 0800; TestTargetID = 88DB89C01A86D1A900DED153; }; 887863331B3699C800E2F51C = { CreatedOnToolsVersion = 7.0; + LastSwiftMigration = 0800; TestTargetID = 88DB89C01A86D1A900DED153; }; 88DB89C01A86D1A900DED153 = { CreatedOnToolsVersion = 6.1.1; + DevelopmentTeam = 5VRJU68BZ5; + DevelopmentTeamName = "Jesse Squires"; + LastSwiftMigration = 0800; }; }; }; @@ -521,6 +526,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 2.3; TEST_TARGET_NAME = Example; }; name = Debug; @@ -537,6 +543,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; TEST_TARGET_NAME = Example; }; name = Release; @@ -552,6 +560,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 2.3; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DataSources.app/DataSources"; }; name = Debug; @@ -568,6 +577,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DataSources.app/DataSources"; }; name = Release; @@ -595,6 +606,7 @@ ENABLE_TESTABILITY = 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", @@ -639,6 +651,7 @@ 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; @@ -657,28 +670,31 @@ 88DB89E11A86D1A900DED153 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.hexedbits.$(PRODUCT_NAME)"; PRODUCT_MODULE_NAME = Example; PRODUCT_NAME = "$(PRODUCT_NAME)"; + SWIFT_VERSION = 2.3; }; name = Debug; }; 88DB89E21A86D1A900DED153 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.hexedbits.$(PRODUCT_NAME)"; PRODUCT_MODULE_NAME = Example; PRODUCT_NAME = "$(PRODUCT_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; }; name = Release; }; diff --git a/Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme b/Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme index 9104278..5446067 100644 --- a/Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme +++ b/Example/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme @@ -1,6 +1,6 @@ Bool { var success = true - if !context.hasChanges { - return success - } - context.performBlockAndWait { + if !self.context.hasChanges { + success = true + } do { try self.context.save() } catch { @@ -59,7 +58,6 @@ public class CoreDataStack { success = false } } - return success } diff --git a/Example/ExampleModel/Sources/Thing.swift b/Example/ExampleModel/Sources/Thing.swift index 78f4df6..0af39f9 100644 --- a/Example/ExampleModel/Sources/Thing.swift +++ b/Example/ExampleModel/Sources/Thing.swift @@ -104,7 +104,7 @@ public class Thing: NSManagedObject { return t } - public class func fetchRequest() -> NSFetchRequest { + public class func newFetchRequest() -> NSFetchRequest { let request = NSFetchRequest(entityName: "Thing") request.sortDescriptors = [ NSSortDescriptor(key: "colorName", ascending: true), diff --git a/Example/Sources/Extensions.swift b/Example/Sources/Extensions.swift index e04f482..7e9d5b6 100644 --- a/Example/Sources/Extensions.swift +++ b/Example/Sources/Extensions.swift @@ -90,9 +90,11 @@ extension NSFetchedResultsController { return } - for i in indexPaths { - let thingToDelete = objectAtIndexPath(i) as! Thing - managedObjectContext.deleteObject(thingToDelete) + managedObjectContext.performBlock { + for i in indexPaths { + let thingToDelete = self.objectAtIndexPath(i) as! Thing + self.managedObjectContext.deleteObject(thingToDelete) + } } } @@ -101,9 +103,11 @@ extension NSFetchedResultsController { return } - for i in indexPaths { - let thingToChange = objectAtIndexPath(i) as! Thing - thingToChange.changeNameRandomly() + managedObjectContext.performBlock { + for i in indexPaths { + let thingToChange = self.objectAtIndexPath(i) as! Thing + thingToChange.changeNameRandomly() + } } } @@ -112,9 +116,11 @@ extension NSFetchedResultsController { return } - for i in indexPaths { - let thingToChange = objectAtIndexPath(i) as! Thing - thingToChange.changeColorRandomly() + managedObjectContext.performBlock { + for i in indexPaths { + let thingToChange = self.objectAtIndexPath(i) as! Thing + thingToChange.changeColorRandomly() + } } } @@ -123,9 +129,11 @@ extension NSFetchedResultsController { return } - for i in indexPaths { - let thingToChange = objectAtIndexPath(i) as! Thing - thingToChange.changeRandomly() + managedObjectContext.performBlock { + for i in indexPaths { + let thingToChange = self.objectAtIndexPath(i) as! Thing + thingToChange.changeRandomly() + } } } } diff --git a/Example/Sources/FetchedCollectionViewController.swift b/Example/Sources/FetchedCollectionViewController.swift index 8d6913b..837ba17 100644 --- a/Example/Sources/FetchedCollectionViewController.swift +++ b/Example/Sources/FetchedCollectionViewController.swift @@ -127,11 +127,14 @@ class FetchedCollectionViewController: UICollectionViewController { func addNewThing() { collectionView!.deselectAllItems() - let newThing = Thing.newThing(stack.context) + var newThing: Thing? + stack.context.performBlockAndWait { + newThing = Thing.newThing(self.stack.context) + } stack.saveAndWait() fetchData() - if let indexPath = frc.indexPathForObject(newThing) { + if let indexPath = frc.indexPathForObject(newThing!) { collectionView!.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: .CenteredVertically) } } diff --git a/Example/Sources/FetchedTableViewController.swift b/Example/Sources/FetchedTableViewController.swift index 7b676a8..208af36 100644 --- a/Example/Sources/FetchedTableViewController.swift +++ b/Example/Sources/FetchedTableViewController.swift @@ -102,12 +102,14 @@ class FetchedTableViewController: UITableViewController { func addNewThing() { tableView.deselectAllRows() - let newThing = Thing.newThing(stack.context) + var newThing: Thing? + stack.context.performBlockAndWait { + newThing = Thing.newThing(self.stack.context) + } stack.saveAndWait() - fetchData() - if let indexPath = frc.indexPathForObject(newThing) { + if let indexPath = frc.indexPathForObject(newThing!) { tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: .Middle) } } diff --git a/Example/Sources/Helpers.swift b/Example/Sources/Helpers.swift index f9af292..e0ebbb2 100644 --- a/Example/Sources/Helpers.swift +++ b/Example/Sources/Helpers.swift @@ -41,7 +41,7 @@ func addThingsInStack(stack: CoreDataStack, count: Int) { func removeAllThingsInStack(stack: CoreDataStack) { do { - let results = try stack.context.executeFetchRequest(Thing.fetchRequest()) + let results = try stack.context.executeFetchRequest(Thing.newFetchRequest()) for thing in results { stack.context.deleteObject(thing as! Thing) } @@ -54,7 +54,7 @@ func removeAllThingsInStack(stack: CoreDataStack) { func fetchedResultsController(inContext context: NSManagedObjectContext) -> FetchedResultsController { - return FetchedResultsController(fetchRequest: Thing.fetchRequest(), + return FetchedResultsController(fetchRequest: Thing.newFetchRequest(), managedObjectContext: context, sectionNameKeyPath: "colorName", cacheName: nil) diff --git a/Example/UITests/FetchedResultsViewsUITests.swift b/Example/UITests/FetchedResultsViewsUITests.swift index 685991c..50c853d 100644 --- a/Example/UITests/FetchedResultsViewsUITests.swift +++ b/Example/UITests/FetchedResultsViewsUITests.swift @@ -22,8 +22,8 @@ final class FetchedResultsViewsUITests: XCTestCase { private let numberOfItemsAdded = 5 - private let fetchedResultsTableViewMenuItem = XCUIApplication().tables.element.cells.elementBoundByIndex(2) - private let fetchedResultsCollectionViewMenuItem = XCUIApplication().tables.element.cells.elementBoundByIndex(3) + private let fetchedResultsTableViewMenuItem = XCUIApplication().tables.element.cells.element(boundBy: 2) + private let fetchedResultsCollectionViewMenuItem = XCUIApplication().tables.element.cells.element(boundBy: 3) override func setUp() { super.setUp() diff --git a/Example/UITests/StaticViewsUITests.swift b/Example/UITests/StaticViewsUITests.swift index 5d9d136..1b8c397 100644 --- a/Example/UITests/StaticViewsUITests.swift +++ b/Example/UITests/StaticViewsUITests.swift @@ -23,8 +23,8 @@ final class StaticViewsUITests: XCTestCase { private let numberOfCellsInStaticTableView: Int = 9 private let numberOfCellsInStaticCollectionView: Int = 10 - private let staticTableViewMenuItem = XCUIApplication().tables.element.cells.elementBoundByIndex(0) - private let staticCollectionViewMenuItem = XCUIApplication().tables.element.cells.elementBoundByIndex(1) + private let staticTableViewMenuItem = XCUIApplication().tables.element.cells.element(boundBy: 0) + private let staticCollectionViewMenuItem = XCUIApplication().tables.element.cells.element(boundBy: 1) override func setUp() { super.setUp() diff --git a/Example/UITests/XCTestCaseExtensions.swift b/Example/UITests/XCTestCaseExtensions.swift index 523f467..9bb496a 100644 --- a/Example/UITests/XCTestCaseExtensions.swift +++ b/Example/UITests/XCTestCaseExtensions.swift @@ -24,8 +24,7 @@ extension XCTestCase { Returns to the previous screen in navigation stack if Back button is availible */ func returnBackIfPossible() { - - let backButton = XCUIApplication().navigationBars.buttons.matchingIdentifier("Back").elementBoundByIndex(0) + let backButton = XCUIApplication().navigationBars.buttons.matching(identifier: "Back").element(boundBy: 0) if backButton.exists && backButton.hittable { backButton.tap() @@ -36,14 +35,14 @@ extension XCTestCase { Scrolls down the current view halfscreen. */ func scrollHalfScreenDown() { - scrollScreenVerticallyWithOffset(-0.8 * XCUIApplication().windows.elementBoundByIndex(0).frame.height / 2) + scrollScreenVerticallyWithOffset(-0.8 * XCUIApplication().windows.element(boundBy: 0).frame.height / 2) } /** Scrolls down the current view halfscreen. */ func scrollHalfScreenUp() { - scrollScreenVerticallyWithOffset(0.8 * XCUIApplication().windows.elementBoundByIndex(0).frame.height / 2) + scrollScreenVerticallyWithOffset(0.8 * XCUIApplication().windows.element(boundBy: 0).frame.height / 2) } /** @@ -52,7 +51,7 @@ extension XCTestCase { - parameter offset: Number of points that a view should be scrolled by. */ func scrollScreenVerticallyWithOffset(offset: CGFloat) { - let mainWindow = XCUIApplication().windows.elementBoundByIndex(0) + let mainWindow = XCUIApplication().windows.element(boundBy: 0) // `start` is exactly the center of the main window let start = mainWindow.coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.5)) diff --git a/JSQDataSourcesKit.xcodeproj/project.pbxproj b/JSQDataSourcesKit.xcodeproj/project.pbxproj index 46e5b4e..49d04da 100644 --- a/JSQDataSourcesKit.xcodeproj/project.pbxproj +++ b/JSQDataSourcesKit.xcodeproj/project.pbxproj @@ -290,17 +290,22 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Hexed Bits"; TargetAttributes = { 881A92CB1CB881270080BC5C = { CreatedOnToolsVersion = 7.3; + LastSwiftMigration = 0800; }; 887DD0831B3BAC6C00FC4BF1 = { CreatedOnToolsVersion = 7.0; + DevelopmentTeam = 5VRJU68BZ5; + DevelopmentTeamName = "Jesse Squires"; + LastSwiftMigration = 0800; }; 887DD08D1B3BAC6C00FC4BF1 = { CreatedOnToolsVersion = 7.0; + LastSwiftMigration = 0800; }; }; }; @@ -448,6 +453,7 @@ PRODUCT_NAME = JSQDataSourcesKit; SDKROOT = appletvos; SKIP_INSTALL = YES; + SWIFT_VERSION = 2.3; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.2; }; @@ -469,6 +475,8 @@ PRODUCT_NAME = JSQDataSourcesKit; SDKROOT = appletvos; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.2; }; @@ -580,6 +588,7 @@ PRODUCT_NAME = JSQDataSourcesKit; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 2.3; }; name = Debug; }; @@ -599,31 +608,36 @@ PRODUCT_MODULE_NAME = "$(PRODUCT_NAME)"; PRODUCT_NAME = JSQDataSourcesKit; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; }; name = Release; }; 887DD09C1B3BAC6C00FC4BF1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.JSQDataSourcesKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 2.3; }; name = Debug; }; 887DD09D1B3BAC6C00FC4BF1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CLANG_ENABLE_MODULES = YES; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.JSQDataSourcesKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 2.3; }; name = Release; }; diff --git a/JSQDataSourcesKit.xcodeproj/xcshareddata/xcschemes/JSQDataSourcesKit-iOS.xcscheme b/JSQDataSourcesKit.xcodeproj/xcshareddata/xcschemes/JSQDataSourcesKit-iOS.xcscheme index ae3cf11..979f4a2 100644 --- a/JSQDataSourcesKit.xcodeproj/xcshareddata/xcschemes/JSQDataSourcesKit-iOS.xcscheme +++ b/JSQDataSourcesKit.xcodeproj/xcshareddata/xcschemes/JSQDataSourcesKit-iOS.xcscheme @@ -1,6 +1,6 @@ (fetchRequest: Thing.fetchRequest(), + let frc = FetchedResultsController(fetchRequest: Thing.newFetchRequest(), managedObjectContext: context, sectionNameKeyPath: "colorName", cacheName: nil) @@ -109,7 +109,7 @@ final class DataSourceTests: XCTestCase { let context = CoreDataStack(inMemory: true).context // GIVEN: a fetched results controller - let frc = FetchedResultsController(fetchRequest: Thing.fetchRequest(), + let frc = FetchedResultsController(fetchRequest: Thing.newFetchRequest(), managedObjectContext: context, sectionNameKeyPath: "colorName", cacheName: nil) @@ -143,7 +143,7 @@ final class DataSourceTests: XCTestCase { let redThings = generateThings(context, color: .Red) // GIVEN: a fetched results controller - let frc = FetchedResultsController(fetchRequest: Thing.fetchRequest(), + let frc = FetchedResultsController(fetchRequest: Thing.newFetchRequest(), managedObjectContext: context, sectionNameKeyPath: "colorName", cacheName: nil) diff --git a/Tests/FetchedResultsDelegateTests.swift b/Tests/FetchedResultsDelegateTests.swift index 3caa39a..5cb1a02 100644 --- a/Tests/FetchedResultsDelegateTests.swift +++ b/Tests/FetchedResultsDelegateTests.swift @@ -37,7 +37,7 @@ final class FetchedResultsDelegateTests: TestCase { stack.saveAndWait() // GIVEN: a fetched results controller - let frc = FetchedResultsController(fetchRequest: Thing.fetchRequest(), + let frc = FetchedResultsController(fetchRequest: Thing.newFetchRequest(), managedObjectContext: context, sectionNameKeyPath: "colorName", cacheName: nil) @@ -93,7 +93,7 @@ final class FetchedResultsDelegateTests: TestCase { stack.saveAndWait() // GIVEN: a fetched results controller - let frc = FetchedResultsController(fetchRequest: Thing.fetchRequest(), + let frc = FetchedResultsController(fetchRequest: Thing.newFetchRequest(), managedObjectContext: context, sectionNameKeyPath: "colorName", cacheName: nil) From 56af816899fdbcb66f69b203fae153655d62736c Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Sun, 17 Jul 2016 11:05:21 -0700 Subject: [PATCH 02/24] update travis for swift 2.3, #53 --- .travis.yml | 54 ++++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4d4195a..778dae1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: objective-c -osx_image: xcode7.3 +osx_image: xcode8 env: global: @@ -10,29 +10,33 @@ env: - IOS_SCHEME="JSQDataSourcesKit-iOS" - TVOS_SCHEME="JSQDataSourcesKit-tvOS" - - IOS_SDK=iphonesimulator9.3 - - TVOS_SDK=appletvsimulator9.2 + - IOS_SDK=iphonesimulator10.0 + - TVOS_SDK=appletvsimulator10.0 matrix: - - DESTINATION="OS=8.1,name=iPhone 4s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="YES" - - DESTINATION="OS=8.2,name=iPhone 5" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" - - DESTINATION="OS=8.3,name=iPhone 5s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" - - DESTINATION="OS=8.4,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" - - - DESTINATION="OS=9.0,name=iPhone 5s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" - - DESTINATION="OS=9.1,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" - - DESTINATION="OS=9.2,name=iPhone 6 Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" - - DESTINATION="OS=9.3,name=iPhone 6s Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" - - - DESTINATION="OS=8.1,name=iPad 2" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" - - DESTINATION="OS=8.4,name=iPad 2" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" - - DESTINATION="OS=9.0,name=iPad Retina" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" - - DESTINATION="OS=9.1,name=iPad Air" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" - - DESTINATION="OS=9.2,name=iPad Air 2" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" - - DESTINATION="OS=9.3,name=iPad Pro" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" - - - DESTINATION="OS=9.0,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO" - - DESTINATION="OS=9.2,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO" + # - DESTINATION="OS=8.1,name=iPhone 4s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="YES" + # - DESTINATION="OS=8.2,name=iPhone 5" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" + # - DESTINATION="OS=8.3,name=iPhone 5s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" + # - DESTINATION="OS=8.4,name=iPhone 6" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" + + # - DESTINATION="OS=9.0,name=iPhone 5s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" + # - DESTINATION="OS=9.1,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" + # - DESTINATION="OS=9.2,name=iPhone 6 Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" + # - DESTINATION="OS=9.3,name=iPhone 6s Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" + + # - DESTINATION="OS=8.1,name=iPad 2" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" + # - DESTINATION="OS=8.4,name=iPad 2" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" + # - DESTINATION="OS=9.0,name=iPad Retina" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" + # - DESTINATION="OS=9.1,name=iPad Air" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" + # - DESTINATION="OS=9.2,name=iPad Air 2" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" + # - DESTINATION="OS=9.3,name=iPad Pro" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" + + - DESTINATION="OS=10.0,name=iPhone 6s Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" + + # - DESTINATION="OS=9.0,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO" + # - DESTINATION="OS=9.2,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO" + + - DESTINATION="OS=10.0,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO" script: - if [ $POD_LINT == "YES" ]; then @@ -54,9 +58,9 @@ script: # Build for reporting test coverage -- if [ $RUN_TESTS == "YES" ]; then - xcodebuild test -project JSQDataSourcesKit.xcodeproj -scheme JSQDataSourcesKit-iOS -sdk iphonesimulator; - fi +# - if [ $RUN_TESTS == "YES" ]; then +# xcodebuild test -project JSQDataSourcesKit.xcodeproj -scheme JSQDataSourcesKit-iOS -sdk iphonesimulator; +# fi after_success: - bash <(curl -s https://codecov.io/bash) From f6029a2e5cca4ab0558ae285a14b3135dd11e261 Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Sun, 17 Jul 2016 17:26:20 -0700 Subject: [PATCH 03/24] initial migration to swift 3.0, #54 --- Example/Example.xcodeproj/project.pbxproj | 12 +-- .../ExampleModel.xcodeproj/project.pbxproj | 8 +- .../ExampleModel/Sources/CoreDataStack.swift | 15 ++-- Example/ExampleModel/Sources/Thing.swift | 27 +++---- Example/Sources/AppDelegate.swift | 2 +- Example/Sources/CollectionViewCell.swift | 2 +- .../Sources/CollectionViewController.swift | 6 +- .../ComposedSupplementaryViewFactory.swift | 6 +- Example/Sources/Extensions.swift | 51 +++++++------ .../FetchedCollectionViewController.swift | 20 ++--- .../Sources/FetchedTableViewController.swift | 10 +-- Example/Sources/Helpers.swift | 26 +++---- Example/Sources/ViewController.swift | 4 +- .../UITests/FetchedResultsViewsUITests.swift | 28 +++---- Example/UITests/StaticViewsUITests.swift | 4 +- Example/UITests/XCTestCaseExtensions.swift | 16 ++-- JSQDataSourcesKit.xcodeproj/project.pbxproj | 12 +-- Source/BridgedDataSource.swift | 28 +++---- Source/BridgedFetchedResultsDelegate.swift | 30 ++++---- Source/DataSource.swift | 46 +++++------ Source/DataSourceProvider.swift | 2 +- Source/FetchedResultsDelegate.swift | 76 +++++++++---------- Source/TitledSupplementaryView.swift | 2 +- Source/TitledSupplementaryViewFactory.swift | 11 ++- Source/ViewFactory.swift | 40 +++++----- Tests/BridgedDataSourceTests.swift | 22 +++--- .../BridgedFetchedResultsDelegateTests.swift | 18 ++--- Tests/DataSourceProviderSubscriptTests.swift | 6 +- Tests/DataSourceProviderTests.swift | 70 ++++++++--------- Tests/DataSourceTests.swift | 12 +-- Tests/FetchedResultsDelegateTests.swift | 30 ++++---- Tests/TestCase.swift | 16 ++-- Tests/TestHelpers.swift | 39 +++++----- .../TitledSupplementaryViewFactoryTests.swift | 30 ++++---- Tests/TitledSupplementaryViewTests.swift | 6 +- 35 files changed, 362 insertions(+), 371 deletions(-) diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index 4a5921f..edc661e 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -526,7 +526,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TEST_TARGET_NAME = Example; }; name = Debug; @@ -544,7 +544,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TEST_TARGET_NAME = Example; }; name = Release; @@ -560,7 +560,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DataSources.app/DataSources"; }; name = Debug; @@ -578,7 +578,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DataSources.app/DataSources"; }; name = Release; @@ -678,7 +678,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.hexedbits.$(PRODUCT_NAME)"; PRODUCT_MODULE_NAME = Example; PRODUCT_NAME = "$(PRODUCT_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -694,7 +694,7 @@ PRODUCT_MODULE_NAME = Example; PRODUCT_NAME = "$(PRODUCT_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Example/ExampleModel/ExampleModel.xcodeproj/project.pbxproj b/Example/ExampleModel/ExampleModel.xcodeproj/project.pbxproj index 033fe8b..badc0c7 100644 --- a/Example/ExampleModel/ExampleModel.xcodeproj/project.pbxproj +++ b/Example/ExampleModel/ExampleModel.xcodeproj/project.pbxproj @@ -339,7 +339,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -359,7 +359,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -370,7 +370,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleModelTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -382,7 +382,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.ExampleModelTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Example/ExampleModel/Sources/CoreDataStack.swift b/Example/ExampleModel/Sources/CoreDataStack.swift index 1ac2086..4d7ad1c 100755 --- a/Example/ExampleModel/Sources/CoreDataStack.swift +++ b/Example/ExampleModel/Sources/CoreDataStack.swift @@ -31,23 +31,24 @@ public class CoreDataStack { public let persistentStoreCoordinator: NSPersistentStoreCoordinator public init(inMemory: Bool = false) { - let modelURL = NSBundle(forClass: CoreDataStack.self).URLForResource("Model", withExtension: "momd")! + let modelURL = Bundle(for: CoreDataStack.self).urlForResource("Model", withExtension: "momd")! - let model = NSManagedObjectModel(contentsOfURL: modelURL)! - let documentsDirectoryURL = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true) - let storeURL = documentsDirectoryURL.URLByAppendingPathComponent("Model.sqlite") + let model = NSManagedObjectModel(contentsOf: modelURL)! + let documentsDirectoryURL = try! FileManager.default().urlForDirectory(.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) + let storeURL = try! documentsDirectoryURL.appendingPathComponent("Model.sqlite") persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model) - try! persistentStoreCoordinator.addPersistentStoreWithType(inMemory ? NSInMemoryStoreType : NSSQLiteStoreType, configuration: nil, URL: inMemory ? nil : storeURL, options: nil) + try! persistentStoreCoordinator.addPersistentStore(ofType: inMemory ? NSInMemoryStoreType : NSSQLiteStoreType, configurationName: nil, at: inMemory ? nil : storeURL, options: nil) - context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) + context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) context.persistentStoreCoordinator = persistentStoreCoordinator } + @discardableResult public func saveAndWait() -> Bool { var success = true - context.performBlockAndWait { + context.performAndWait { if !self.context.hasChanges { success = true } diff --git a/Example/ExampleModel/Sources/Thing.swift b/Example/ExampleModel/Sources/Thing.swift index 0af39f9..e7ba406 100644 --- a/Example/ExampleModel/Sources/Thing.swift +++ b/Example/ExampleModel/Sources/Thing.swift @@ -28,9 +28,9 @@ public enum Color: String { var displayColor: UIColor { switch(self) { - case .Red: return .redColor() - case .Blue: return .blueColor() - case .Green: return .greenColor() + case .Red: return .red() + case .Blue: return .blue() + case .Green: return .green() } } } @@ -70,12 +70,12 @@ public class Thing: NSManagedObject { // MARK: Init public init(context: NSManagedObjectContext) { - let entityDescription = NSEntityDescription.entityForName("Thing", inManagedObjectContext: context)! - super.init(entity: entityDescription, insertIntoManagedObjectContext: context) + let entityDescription = NSEntityDescription.entity(forEntityName: "Thing", in: context)! + super.init(entity: entityDescription, insertInto: context) } - public override init(entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?) { - super.init(entity: entity, insertIntoManagedObjectContext: context) + public override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { + super.init(entity: entity, insertInto: context) } @@ -97,18 +97,19 @@ public class Thing: NSManagedObject { // MARK: Class - public class func newThing(context: NSManagedObjectContext) -> Thing { + @discardableResult + public class func newThing(_ context: NSManagedObjectContext) -> Thing { let t = Thing(context: context) t.color = randomColor(withoutColor: nil) t.name = randomName() return t } - public class func newFetchRequest() -> NSFetchRequest { - let request = NSFetchRequest(entityName: "Thing") + public class func newFetchRequest() -> NSFetchRequest { + let request = NSFetchRequest(entityName: "Thing") request.sortDescriptors = [ - NSSortDescriptor(key: "colorName", ascending: true), - NSSortDescriptor(key: "name", ascending: true) + SortDescriptor(key: "colorName", ascending: true), + SortDescriptor(key: "name", ascending: true) ] return request } @@ -126,5 +127,5 @@ private func randomColor(withoutColor color: Color?) -> Color { private func randomName() -> String { - return NSUUID().UUIDString.componentsSeparatedByString("-").first! + return UUID().uuidString.components(separatedBy: "-").first! } diff --git a/Example/Sources/AppDelegate.swift b/Example/Sources/AppDelegate.swift index 0391d8e..e557929 100644 --- a/Example/Sources/AppDelegate.swift +++ b/Example/Sources/AppDelegate.swift @@ -23,7 +23,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions options: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions options: [NSObject: AnyObject]?) -> Bool { return true } diff --git a/Example/Sources/CollectionViewCell.swift b/Example/Sources/CollectionViewCell.swift index 1e637c4..8ce86fb 100644 --- a/Example/Sources/CollectionViewCell.swift +++ b/Example/Sources/CollectionViewCell.swift @@ -25,6 +25,6 @@ class CollectionViewCell: UICollectionViewCell { override func awakeFromNib() { super.awakeFromNib() selectedBackgroundView = UIView() - selectedBackgroundView?.backgroundColor = .lightGrayColor() + selectedBackgroundView?.backgroundColor = .lightGray() } } diff --git a/Example/Sources/CollectionViewController.swift b/Example/Sources/CollectionViewController.swift index 2f6336d..ba2c710 100644 --- a/Example/Sources/CollectionViewController.swift +++ b/Example/Sources/CollectionViewController.swift @@ -49,8 +49,8 @@ final class CollectionViewController: UICollectionViewController, UICollectionVi // 3. create supplementary view factory let headerFactory = TitledSupplementaryViewFactory { (header, item: CellViewModel?, kind, collectionView, indexPath) -> TitledSupplementaryView in header.label.text = "Section \(indexPath.section)" - header.backgroundColor = .darkGrayColor() - header.label.textColor = .whiteColor() + header.backgroundColor = .darkGray() + header.label.textColor = .white() return header } @@ -63,7 +63,7 @@ final class CollectionViewController: UICollectionViewController, UICollectionVi collectionView?.dataSource = self.dataSourceProvider?.collectionViewDataSource } - func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.size.width, height: 50) } } diff --git a/Example/Sources/ComposedSupplementaryViewFactory.swift b/Example/Sources/ComposedSupplementaryViewFactory.swift index b429e5f..da542c4 100644 --- a/Example/Sources/ComposedSupplementaryViewFactory.swift +++ b/Example/Sources/ComposedSupplementaryViewFactory.swift @@ -36,15 +36,15 @@ public struct ComposedCollectionSupplementaryViewFactory : ReusableViewFac self.footerViewFactory = footerViewFactory } - public func reuseIdentiferFor(item item: Item?, type: ReusableViewType, indexPath: NSIndexPath) -> String { + public func reuseIdentiferFor(item: Item?, type: ReusableViewType, indexPath: IndexPath) -> String { return TitledSupplementaryView.identifier } - public func configure(view view: TitledSupplementaryView, + public func configure(view: TitledSupplementaryView, item: Item?, type: ReusableViewType, parentView: UICollectionView, - indexPath: NSIndexPath) -> TitledSupplementaryView { + indexPath: IndexPath) -> TitledSupplementaryView { switch type { case .supplementaryView(kind: UICollectionElementKindSectionHeader): return headerViewFactory.configure(view: view, item: item, type: type, parentView: parentView, indexPath: indexPath) diff --git a/Example/Sources/Extensions.swift b/Example/Sources/Extensions.swift index 7e9d5b6..da6a6fc 100644 --- a/Example/Sources/Extensions.swift +++ b/Example/Sources/Extensions.swift @@ -21,40 +21,41 @@ import CoreData import Foundation import UIKit import ExampleModel +import JSQDataSourcesKit extension UIAlertController { - class func showActionAlert(presenter: UIViewController, + class func showActionAlert(_ presenter: UIViewController, addNewAction: () -> Void, deleteAction: () -> Void, changeNameAction: () -> Void, changeColorAction: () -> Void, changeAllAction: () -> Void) { - let alert = UIAlertController(title: "You must select items first", message: nil, preferredStyle: .ActionSheet) + let alert = UIAlertController(title: "You must select items first", message: nil, preferredStyle: .actionSheet) - alert.addAction(UIAlertAction(title: "Add new", style: .Default) { action in + alert.addAction(UIAlertAction(title: "Add new", style: .default) { action in addNewAction() }) - alert.addAction(UIAlertAction(title: "Delete selected", style: .Default) { action in + alert.addAction(UIAlertAction(title: "Delete selected", style: .default) { action in deleteAction() }) - alert.addAction(UIAlertAction(title: "Change name selected", style: .Default) { action in + alert.addAction(UIAlertAction(title: "Change name selected", style: .default) { action in changeNameAction() }) - alert.addAction(UIAlertAction(title: "Change color selected", style: .Default) { action in + alert.addAction(UIAlertAction(title: "Change color selected", style: .default) { action in changeColorAction() }) - alert.addAction(UIAlertAction(title: "Change all selected", style: .Default) { action in + alert.addAction(UIAlertAction(title: "Change all selected", style: .default) { action in changeAllAction() }) - alert.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)) + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) - presenter.presentViewController(alert, animated: true, completion: nil) + presenter.present(alert, animated: true, completion: nil) } } @@ -64,7 +65,7 @@ extension UITableView { func deselectAllRows() { if let indexPaths = indexPathsForSelectedRows { for i in indexPaths { - deselectRowAtIndexPath(i, animated: true) + deselectRow(at: i, animated: true) } } } @@ -76,62 +77,62 @@ extension UICollectionView { func deselectAllItems() { if let indexPaths = indexPathsForSelectedItems() { for i in indexPaths { - deselectItemAtIndexPath(i, animated: true) + deselectItem(at: i, animated: true) } } } } -extension NSFetchedResultsController { +extension FetchedResultsController { - func deleteThingsAtIndexPaths(indexPaths: [NSIndexPath]?) { + func deleteThingsAtIndexPaths(_ indexPaths: [IndexPath]?) { guard let indexPaths = indexPaths else { return } - managedObjectContext.performBlock { + managedObjectContext.perform { for i in indexPaths { - let thingToDelete = self.objectAtIndexPath(i) as! Thing - self.managedObjectContext.deleteObject(thingToDelete) + let thingToDelete = self.object(at: i) as! Thing + self.managedObjectContext.delete(thingToDelete) } } } - func changeThingNamesAtIndexPaths(indexPaths: [NSIndexPath]?) { + func changeThingNamesAtIndexPaths(_ indexPaths: [IndexPath]?) { guard let indexPaths = indexPaths else { return } - managedObjectContext.performBlock { + managedObjectContext.perform { for i in indexPaths { - let thingToChange = self.objectAtIndexPath(i) as! Thing + let thingToChange = self.object(at: i) as! Thing thingToChange.changeNameRandomly() } } } - func changeThingColorsAtIndexPaths(indexPaths: [NSIndexPath]?) { + func changeThingColorsAtIndexPaths(_ indexPaths: [IndexPath]?) { guard let indexPaths = indexPaths else { return } - managedObjectContext.performBlock { + managedObjectContext.perform { for i in indexPaths { - let thingToChange = self.objectAtIndexPath(i) as! Thing + let thingToChange = self.object(at: i) as! Thing thingToChange.changeColorRandomly() } } } - func changeThingsAtIndexPaths(indexPaths: [NSIndexPath]?) { + func changeThingsAtIndexPaths(_ indexPaths: [IndexPath]?) { guard let indexPaths = indexPaths else { return } - managedObjectContext.performBlock { + managedObjectContext.perform { for i in indexPaths { - let thingToChange = self.objectAtIndexPath(i) as! Thing + let thingToChange = self.object(at: i) as! Thing thingToChange.changeRandomly() } } diff --git a/Example/Sources/FetchedCollectionViewController.swift b/Example/Sources/FetchedCollectionViewController.swift index 837ba17..8bad0aa 100644 --- a/Example/Sources/FetchedCollectionViewController.swift +++ b/Example/Sources/FetchedCollectionViewController.swift @@ -50,7 +50,7 @@ class FetchedCollectionViewController: UICollectionViewController { // 1. create cell factory let cellFactory = ViewFactory(reuseIdentifier: CellId) { (cell, model: Thing?, type, collectionView, indexPath) -> CollectionViewCell in cell.label.text = model!.displayName - cell.label.textColor = UIColor.whiteColor() + cell.label.textColor = UIColor.white() cell.backgroundColor = model!.displayColor cell.accessibilityIdentifier = "\(cell.label.text)" return cell @@ -60,16 +60,16 @@ class FetchedCollectionViewController: UICollectionViewController { let headerFactory = TitledSupplementaryViewFactory { (header, item: Thing?, kind, collectionView, indexPath) -> TitledSupplementaryView in header.label.text = "\(item!.colorName) header (\(indexPath.section))" header.label.textColor = item?.displayColor - header.backgroundColor = .darkGrayColor() + header.backgroundColor = .darkGray() return header } let footerFactory = TitledSupplementaryViewFactory { (footer, item: Thing?, kind, collectionView, indexPath) -> TitledSupplementaryView in footer.label.text = "\(item!.colorName) footer (\(indexPath.section))" footer.label.textColor = item?.displayColor - footer.backgroundColor = .lightGrayColor() - footer.label.font = .preferredFontForTextStyle(UIFontTextStyleFootnote) - footer.label.textAlignment = .Center + footer.backgroundColor = .lightGray() + footer.label.font = .preferredFont(forTextStyle: UIFontTextStyleFootnote) + footer.label.textAlignment = .center return footer } @@ -91,7 +91,7 @@ class FetchedCollectionViewController: UICollectionViewController { collectionView?.dataSource = dataSourceProvider?.collectionViewDataSource } - override func viewWillAppear(animated: Bool) { + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) fetchData() } @@ -110,7 +110,7 @@ class FetchedCollectionViewController: UICollectionViewController { // MARK: Actions - @IBAction func didTapActionButton(sender: UIBarButtonItem) { + @IBAction func didTapActionButton(_ sender: UIBarButtonItem) { UIAlertController.showActionAlert(self, addNewAction: { self.addNewThing() }, deleteAction: { @@ -128,14 +128,14 @@ class FetchedCollectionViewController: UICollectionViewController { collectionView!.deselectAllItems() var newThing: Thing? - stack.context.performBlockAndWait { + stack.context.performAndWait { newThing = Thing.newThing(self.stack.context) } stack.saveAndWait() fetchData() - if let indexPath = frc.indexPathForObject(newThing!) { - collectionView!.selectItemAtIndexPath(indexPath, animated: true, scrollPosition: .CenteredVertically) + if let indexPath = frc.indexPath(forObject: newThing!) { + collectionView!.selectItem(at: indexPath, animated: true, scrollPosition: .centeredVertically) } } diff --git a/Example/Sources/FetchedTableViewController.swift b/Example/Sources/FetchedTableViewController.swift index 208af36..f2e324d 100644 --- a/Example/Sources/FetchedTableViewController.swift +++ b/Example/Sources/FetchedTableViewController.swift @@ -66,7 +66,7 @@ class FetchedTableViewController: UITableViewController { tableView.dataSource = dataSourceProvider?.tableViewDataSource } - override func viewWillAppear(animated: Bool) { + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) fetchData() } @@ -85,7 +85,7 @@ class FetchedTableViewController: UITableViewController { // MARK: Actions - @IBAction func didTapActionButton(sender: UIBarButtonItem) { + @IBAction func didTapActionButton(_ sender: UIBarButtonItem) { UIAlertController.showActionAlert(self, addNewAction: { self.addNewThing() }, deleteAction: { @@ -103,14 +103,14 @@ class FetchedTableViewController: UITableViewController { tableView.deselectAllRows() var newThing: Thing? - stack.context.performBlockAndWait { + stack.context.performAndWait { newThing = Thing.newThing(self.stack.context) } stack.saveAndWait() fetchData() - if let indexPath = frc.indexPathForObject(newThing!) { - tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: .Middle) + if let indexPath = frc.indexPath(forObject: newThing!) { + tableView.selectRow(at: indexPath, animated: true, scrollPosition: .middle) } } diff --git a/Example/Sources/Helpers.swift b/Example/Sources/Helpers.swift index e0ebbb2..d25dfaf 100644 --- a/Example/Sources/Helpers.swift +++ b/Example/Sources/Helpers.swift @@ -31,7 +31,7 @@ struct CellViewModel { } -func addThingsInStack(stack: CoreDataStack, count: Int) { +func addThingsInStack(_ stack: CoreDataStack, count: Int) { for _ in 0.. Fetc } -func configureCollectionView(collectionView: UICollectionView) { +func configureCollectionView(_ collectionView: UICollectionView) { let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) layout.headerReferenceSize = CGSize(width: collectionView.frame.size.width, height: 50) - collectionView.registerNib(UINib(nibName: "CollectionViewCell", bundle: nil), - forCellWithReuseIdentifier: CellId) + collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), + forCellWithReuseIdentifier: CellId) - collectionView.registerClass(TitledSupplementaryView.self, - forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, - withReuseIdentifier: TitledSupplementaryView.identifier) + collectionView.register(TitledSupplementaryView.self, + forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, + withReuseIdentifier: TitledSupplementaryView.identifier) - collectionView.registerClass(TitledSupplementaryView.self, - forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, - withReuseIdentifier: TitledSupplementaryView.identifier) + collectionView.register(TitledSupplementaryView.self, + forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, + withReuseIdentifier: TitledSupplementaryView.identifier) } diff --git a/Example/Sources/ViewController.swift b/Example/Sources/ViewController.swift index bc2b587..bdf0601 100644 --- a/Example/Sources/ViewController.swift +++ b/Example/Sources/ViewController.swift @@ -24,11 +24,11 @@ final class ViewController: UITableViewController { let stack = CoreDataStack() - @IBAction func didTapDeleteButton(sender: UIBarButtonItem) { + @IBAction func didTapDeleteButton(_ sender: UIBarButtonItem) { removeAllThingsInStack(stack) } - @IBAction func didTapAddButton(sender: UIBarButtonItem) { + @IBAction func didTapAddButton(_ sender: UIBarButtonItem) { addThingsInStack(stack, count: 5) } } diff --git a/Example/UITests/FetchedResultsViewsUITests.swift b/Example/UITests/FetchedResultsViewsUITests.swift index 50c853d..c99bc17 100644 --- a/Example/UITests/FetchedResultsViewsUITests.swift +++ b/Example/UITests/FetchedResultsViewsUITests.swift @@ -61,14 +61,14 @@ final class FetchedResultsViewsUITests: XCTestCase { fetchedResultsTableViewMenuItem.tap() // GIVEN: initial number of cells in the table - var numberOfCellsBeforeInTable = countElements(ofType: .Cell, inView: table, byUniqueIdentifier: { $0.identifier }) + var numberOfCellsBeforeInTable = countElements(ofType: .cell, inView: table, byUniqueIdentifier: { $0.identifier }) returnBackIfPossible() fetchedResultsCollectionViewMenuItem.tap() // GIVEN: initial number of cells in the collection view - var numberOfCellsBeforeInCollectionView = countElements(ofType: .Cell, inView: collectionView, + var numberOfCellsBeforeInCollectionView = countElements(ofType: .cell, inView: collectionView, byUniqueIdentifier: { $0.identifier }) XCTAssertEqual(numberOfCellsBeforeInTable, numberOfCellsBeforeInCollectionView, @@ -86,7 +86,7 @@ final class FetchedResultsViewsUITests: XCTestCase { fetchedResultsTableViewMenuItem.tap() // THEN: new items get added to the table - let numberOfCellsAfterInTable = countElements(ofType: .Cell, inView: table, byUniqueIdentifier: { $0.identifier }) + let numberOfCellsAfterInTable = countElements(ofType: .cell, inView: table, byUniqueIdentifier: { $0.identifier }) XCTAssertEqual(numberOfCellsAfterInTable, numberOfCellsBeforeInTable + numberOfItemsAdded, "\"Add\" button should cause adding new cells") @@ -97,7 +97,7 @@ final class FetchedResultsViewsUITests: XCTestCase { fetchedResultsCollectionViewMenuItem.tap() // THEN: new items get added to the collection view as well - let numberOfCellsAfterInCollectionView = countElements(ofType: .Cell, inView: collectionView, + let numberOfCellsAfterInCollectionView = countElements(ofType: .cell, inView: collectionView, byUniqueIdentifier: { $0.identifier }) XCTAssertEqual(numberOfCellsAfterInCollectionView, numberOfCellsBeforeInCollectionView + numberOfItemsAdded, "\"Add\" button should cause adding new cells") @@ -165,7 +165,7 @@ final class FetchedResultsViewsUITests: XCTestCase { fetchedResultsCollectionViewMenuItem.tap() // GIVEN: initial number of cells in the collection view - let numberOfCellsBeforeInCollectionView = countElements(ofType: .Cell, inView: collectionView, + let numberOfCellsBeforeInCollectionView = countElements(ofType: .cell, inView: collectionView, byUniqueIdentifier: { $0.identifier }) // WHEN: "Add new" option is tapped @@ -174,7 +174,7 @@ final class FetchedResultsViewsUITests: XCTestCase { // THEN: a new cell appears in the collection view scrollOnStatusBarTap() - let numberOfCellsAfterInCollectionView = countElements(ofType: .Cell, inView: collectionView, + let numberOfCellsAfterInCollectionView = countElements(ofType: .cell, inView: collectionView, byUniqueIdentifier: { $0.identifier }) XCTAssertEqual(numberOfCellsAfterInCollectionView, numberOfCellsBeforeInCollectionView + 1, @@ -188,7 +188,7 @@ final class FetchedResultsViewsUITests: XCTestCase { fetchedResultsTableViewMenuItem.tap() // GIVEN: initial number of cells in the table view - let numberOfCellsBeforeInTable = countElements(ofType: .Cell, inView: table, byUniqueIdentifier: { $0.identifier }) + let numberOfCellsBeforeInTable = countElements(ofType: .cell, inView: table, byUniqueIdentifier: { $0.identifier }) // WHEN: "Add new" option is tapped app.toolbars.buttons["Share"].tap() @@ -196,7 +196,7 @@ final class FetchedResultsViewsUITests: XCTestCase { // THEN: a new cell appears in the table view scrollOnStatusBarTap() - let numberOfCellsAfterInTable = countElements(ofType: .Cell, inView: table, byUniqueIdentifier: { $0.identifier }) + let numberOfCellsAfterInTable = countElements(ofType: .cell, inView: table, byUniqueIdentifier: { $0.identifier }) XCTAssertEqual(numberOfCellsAfterInTable, numberOfCellsBeforeInTable + 1, "\"Add new\" should add one new cell") } @@ -220,12 +220,12 @@ final class FetchedResultsViewsUITests: XCTestCase { fetchedResultsTableViewMenuItem.tap() // GIVEN: initial number of cells in the table view - let numberOfCellsBeforeInTable = countElements(ofType: .Cell, inView: table, byUniqueIdentifier: { $0.identifier }) + let numberOfCellsBeforeInTable = countElements(ofType: .cell, inView: table, byUniqueIdentifier: { $0.identifier }) scrollOnStatusBarTap() // WHEN: we select some of them - tapOn(numberOfCellsToDelete, hittableElementsOfType: .Cell, inView: table) + tapOn(numberOfCellsToDelete, hittableElementsOfType: .cell, inView: table) // WHEN: "Delete selected" option is tapped app.toolbars.buttons["Share"].tap() @@ -233,7 +233,7 @@ final class FetchedResultsViewsUITests: XCTestCase { // THEN: Selected cells disappear scrollOnStatusBarTap() - let numberOfCellsAfterInTable = countElements(ofType: .Cell, inView: table, byUniqueIdentifier: { $0.identifier }) + let numberOfCellsAfterInTable = countElements(ofType: .cell, inView: table, byUniqueIdentifier: { $0.identifier }) XCTAssertEqual(numberOfCellsAfterInTable, numberOfCellsBeforeInTable - numberOfCellsToDelete, "\"Delete selected\" should remove \(numberOfCellsToDelete) cells.") @@ -247,12 +247,12 @@ final class FetchedResultsViewsUITests: XCTestCase { fetchedResultsCollectionViewMenuItem.tap() // GIVEN: initial number of cells in the table view - let numberOfCellsBeforeInCollectionView = countElements(ofType: .Cell, inView: collectionView, + let numberOfCellsBeforeInCollectionView = countElements(ofType: .cell, inView: collectionView, byUniqueIdentifier: { $0.identifier }) scrollOnStatusBarTap() // WHEN: we select some of them - tapOn(numberOfCellsToDelete, hittableElementsOfType: .Cell, inView: collectionView) + tapOn(numberOfCellsToDelete, hittableElementsOfType: .cell, inView: collectionView) // WHEN: "Delete selected" option is tapped app.toolbars.buttons["Share"].tap() @@ -260,7 +260,7 @@ final class FetchedResultsViewsUITests: XCTestCase { // THEN: Selected cells disappear scrollOnStatusBarTap() - let numberOfCellsAfterInCollectionView = countElements(ofType: .Cell, inView: collectionView, + let numberOfCellsAfterInCollectionView = countElements(ofType: .cell, inView: collectionView, byUniqueIdentifier: { $0.identifier }) XCTAssertEqual(numberOfCellsAfterInCollectionView, numberOfCellsBeforeInCollectionView - numberOfCellsToDelete, "\"Delete selected\" should remove \(numberOfCellsToDelete) cells.") diff --git a/Example/UITests/StaticViewsUITests.swift b/Example/UITests/StaticViewsUITests.swift index 1b8c397..502a11c 100644 --- a/Example/UITests/StaticViewsUITests.swift +++ b/Example/UITests/StaticViewsUITests.swift @@ -45,7 +45,7 @@ final class StaticViewsUITests: XCTestCase { staticTableViewMenuItem.tap() // THEN: the number of cells loaded matches the number of cells expected - let countTableCells = countElements(ofType: .Cell, + let countTableCells = countElements(ofType: .cell, inView: table, byUniqueIdentifier: { $0.identifier }) @@ -61,7 +61,7 @@ final class StaticViewsUITests: XCTestCase { staticCollectionViewMenuItem.tap() // THEN: the number of cells loaded matches the number of cells expected - let countCollectionViewCells = countElements(ofType: .Cell, + let countCollectionViewCells = countElements(ofType: .cell, inView: collectionView, byUniqueIdentifier: { $0.identifier }) diff --git a/Example/UITests/XCTestCaseExtensions.swift b/Example/UITests/XCTestCaseExtensions.swift index 9bb496a..61a640b 100644 --- a/Example/UITests/XCTestCaseExtensions.swift +++ b/Example/UITests/XCTestCaseExtensions.swift @@ -26,7 +26,7 @@ extension XCTestCase { func returnBackIfPossible() { let backButton = XCUIApplication().navigationBars.buttons.matching(identifier: "Back").element(boundBy: 0) - if backButton.exists && backButton.hittable { + if backButton.exists && backButton.isHittable { backButton.tap() } } @@ -50,15 +50,15 @@ extension XCTestCase { - parameter offset: Number of points that a view should be scrolled by. */ - func scrollScreenVerticallyWithOffset(offset: CGFloat) { + func scrollScreenVerticallyWithOffset(_ offset: CGFloat) { let mainWindow = XCUIApplication().windows.element(boundBy: 0) // `start` is exactly the center of the main window - let start = mainWindow.coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.5)) + let start = mainWindow.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)) - let end = start.coordinateWithOffset(CGVector(dx: 0, dy: offset)) + let end = start.withOffset(CGVector(dx: 0, dy: offset)) - start.pressForDuration(0, thenDragToCoordinate: end) + start.press(forDuration: 0, thenDragTo: end) } /** @@ -102,7 +102,7 @@ extension XCTestCase { setOfVisibleElementsIdentifiersAfterScroll = setOfVisibleElementsIdentifiersBeforeScroll - let currentlyVisibleElements = view.descendantsMatchingType(type).allElementsBoundByIndex.filter{ $0.hittable } + let currentlyVisibleElements = view.descendants(matching: type).allElementsBoundByIndex.filter{ $0.isHittable } setOfVisibleElementsIdentifiersBeforeScroll = Set(currentlyVisibleElements.map { identifier($0) }) @@ -117,9 +117,9 @@ extension XCTestCase { } /// Sends a tap event to hittable elements of specified type. - func tapOn(numberOfElementsToTapOn: Int, hittableElementsOfType type: XCUIElementType, inView view: XCUIElement) { + func tapOn(_ numberOfElementsToTapOn: Int, hittableElementsOfType type: XCUIElementType, inView view: XCUIElement) { - let hittableElements = view.descendantsMatchingType(type).allElementsBoundByIndex.filter { $0.hittable } + let hittableElements = view.descendants(matching: type).allElementsBoundByIndex.filter { $0.isHittable } if hittableElements.count < numberOfElementsToTapOn { return diff --git a/JSQDataSourcesKit.xcodeproj/project.pbxproj b/JSQDataSourcesKit.xcodeproj/project.pbxproj index 49d04da..00ee56d 100644 --- a/JSQDataSourcesKit.xcodeproj/project.pbxproj +++ b/JSQDataSourcesKit.xcodeproj/project.pbxproj @@ -453,7 +453,7 @@ PRODUCT_NAME = JSQDataSourcesKit; SDKROOT = appletvos; SKIP_INSTALL = YES; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.2; }; @@ -476,7 +476,7 @@ SDKROOT = appletvos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.2; }; @@ -588,7 +588,7 @@ PRODUCT_NAME = JSQDataSourcesKit; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -609,7 +609,7 @@ PRODUCT_NAME = JSQDataSourcesKit; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -623,7 +623,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.JSQDataSourcesKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -637,7 +637,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.hexedbits.JSQDataSourcesKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 2.3; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Source/BridgedDataSource.swift b/Source/BridgedDataSource.swift index 88185e7..6960195 100644 --- a/Source/BridgedDataSource.swift +++ b/Source/BridgedDataSource.swift @@ -23,10 +23,10 @@ import UIKit internal typealias NumberOfSectionsHandler = () -> Int internal typealias NumberOfItemsInSectionHandler = (Int) -> Int -internal typealias CollectionCellForItemAtIndexPathHandler = (UICollectionView, NSIndexPath) -> UICollectionViewCell -internal typealias CollectionSupplementaryViewAtIndexPathHandler = (UICollectionView, String, NSIndexPath) -> UICollectionReusableView +internal typealias CollectionCellForItemAtIndexPathHandler = (UICollectionView, IndexPath) -> UICollectionViewCell +internal typealias CollectionSupplementaryViewAtIndexPathHandler = (UICollectionView, String, IndexPath) -> UICollectionReusableView -internal typealias TableCellForRowAtIndexPathHandler = (UITableView, NSIndexPath) -> UITableViewCell +internal typealias TableCellForRowAtIndexPathHandler = (UITableView, IndexPath) -> UITableViewCell internal typealias TableTitleForHeaderInSectionHandler = (Int) -> String? internal typealias TableTitleForFooterInSectionHandler = (Int) -> String? @@ -55,48 +55,48 @@ internal typealias TableTitleForFooterInSectionHandler = (Int) -> String? extension BridgedDataSource: UICollectionViewDataSource { - @objc func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { + @objc func numberOfSections(in collectionView: UICollectionView) -> Int { return numberOfSections() } - @objc func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + @objc func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return numberOfItemsInSection(section) } - @objc func collectionView(collectionView: UICollectionView, - cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { + @objc func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { return collectionCellForItemAtIndexPath!(collectionView, indexPath) } - @objc func collectionView(collectionView: UICollectionView, + @objc func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, - atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView { + at indexPath: IndexPath) -> UICollectionReusableView { return collectionSupplementaryViewAtIndexPath!(collectionView, kind, indexPath) } } extension BridgedDataSource: UITableViewDataSource { - @objc func numberOfSectionsInTableView(tableView: UITableView) -> Int { + @objc func numberOfSections(in tableView: UITableView) -> Int { return numberOfSections() } - @objc func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + @objc func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return numberOfItemsInSection(section) } - @objc func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + @objc func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { return tableCellForRowAtIndexPath!(tableView, indexPath) } - @objc func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + @objc func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { if let closure = tableTitleForHeaderInSection { return closure(section) } return nil } - @objc func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? { + @objc func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { if let closure = tableTitleForFooterInSection { return closure(section) } diff --git a/Source/BridgedFetchedResultsDelegate.swift b/Source/BridgedFetchedResultsDelegate.swift index a87bd69..926b42b 100644 --- a/Source/BridgedFetchedResultsDelegate.swift +++ b/Source/BridgedFetchedResultsDelegate.swift @@ -26,10 +26,10 @@ import Foundation */ @objc internal final class BridgedFetchedResultsDelegate: NSObject { - typealias WillChangeContentHandler = (NSFetchedResultsController) -> Void - typealias DidChangeSectionHandler = (NSFetchedResultsController, NSFetchedResultsSectionInfo, Int, NSFetchedResultsChangeType) -> Void - typealias DidChangeObjectHandler = (NSFetchedResultsController, AnyObject, NSIndexPath?, NSFetchedResultsChangeType, NSIndexPath?) -> Void - typealias DidChangeContentHandler = (NSFetchedResultsController) -> Void + typealias WillChangeContentHandler = (NSFetchedResultsController) -> Void + typealias DidChangeSectionHandler = (NSFetchedResultsController, NSFetchedResultsSectionInfo, Int, NSFetchedResultsChangeType) -> Void + typealias DidChangeObjectHandler = (NSFetchedResultsController, AnyObject, IndexPath?, NSFetchedResultsChangeType, IndexPath?) -> Void + typealias DidChangeContentHandler = (NSFetchedResultsController) -> Void let willChangeContent: WillChangeContentHandler let didChangeSection: DidChangeSectionHandler @@ -51,26 +51,26 @@ import Foundation extension BridgedFetchedResultsDelegate: NSFetchedResultsControllerDelegate { - @objc func controllerWillChangeContent(controller: NSFetchedResultsController) { + @objc func controllerWillChangeContent(_ controller: NSFetchedResultsController) { willChangeContent(controller) } - @objc func controller(controller: NSFetchedResultsController, - didChangeSection sectionInfo: NSFetchedResultsSectionInfo, - atIndex sectionIndex: Int, - forChangeType type: NSFetchedResultsChangeType) { + @objc func controller(_ controller: NSFetchedResultsController, + didChange sectionInfo: NSFetchedResultsSectionInfo, + atSectionIndex sectionIndex: Int, + for type: NSFetchedResultsChangeType) { didChangeSection(controller, sectionInfo, sectionIndex, type) } - @objc func controller(controller: NSFetchedResultsController, - didChangeObject anObject: AnyObject, - atIndexPath indexPath: NSIndexPath?, - forChangeType type: NSFetchedResultsChangeType, - newIndexPath: NSIndexPath?) { + @objc func controller(_ controller: NSFetchedResultsController, + didChange anObject: AnyObject, + at indexPath: IndexPath?, + for type: NSFetchedResultsChangeType, + newIndexPath: IndexPath?) { didChangeObject(controller, anObject, indexPath, type, newIndexPath) } - @objc func controllerDidChangeContent(controller: NSFetchedResultsController) { + @objc func controllerDidChangeContent(_ controller: NSFetchedResultsController) { didChangeContent(controller) } } diff --git a/Source/DataSource.swift b/Source/DataSource.swift index 830f49c..8233789 100644 --- a/Source/DataSource.swift +++ b/Source/DataSource.swift @@ -32,7 +32,7 @@ public protocol DataSourceProtocol { // MARK: Methods - + /** - returns: The number of sections. */ @@ -82,26 +82,12 @@ extension DataSourceProtocol { - returns: The item specified by indexPath, or `nil`. */ - func item(atIndexPath indexPath: NSIndexPath) -> Item? { + func item(atIndexPath indexPath: IndexPath) -> Item? { return item(atRow: indexPath.row, inSection: indexPath.section) } } -extension DataSourceProtocol where Self: NSFetchedResultsController { - /** - - parameter indexPath: An index path specifying a row and section in the data source. - - - returns: The item specified by indexPath, or `nil`. - */ - public func item(atIndexPath indexPath: NSIndexPath) -> Item? { - guard indexPath.section < numberOfSections() else { return nil } - guard let objects = sections?[indexPath.section].objects else { return nil } - guard indexPath.item < objects.count else { return nil } - return (objectAtIndexPath(indexPath) as! Item) - } -} - /** A instance of `DataSource` is a concrete `DataSourceProtocol`. It is a collection of section-based data. @@ -194,7 +180,7 @@ public struct DataSource: DataSourceProtocol { - parameter indexPath: The index path of an item. - returns: The item at `indexPath`. */ - public subscript (indexPath: NSIndexPath) -> S.Item { + public subscript (indexPath: IndexPath) -> S.Item { get { return sections[indexPath.section].items[indexPath.row] } @@ -204,8 +190,9 @@ public struct DataSource: DataSourceProtocol { } } + /// A generic `NSFetchedResultsController`. -public class FetchedResultsController: NSFetchedResultsController { +public class FetchedResultsController: NSFetchedResultsController { /** Returns a fetch request controller initialized using the given arguments. @@ -217,11 +204,11 @@ public class FetchedResultsController: NSFetchedResultsContr - returns: An initialized fetch request controller. */ - public override init(fetchRequest: NSFetchRequest, - managedObjectContext context: NSManagedObjectContext, - sectionNameKeyPath: String?, - cacheName name: String?) { - super.init(fetchRequest: fetchRequest, + public init(fetchRequest: NSFetchRequest, + managedObjectContext context: NSManagedObjectContext, + sectionNameKeyPath: String?, + cacheName name: String?) { + super.init(fetchRequest: fetchRequest as! NSFetchRequest, managedObjectContext: context, sectionNameKeyPath: sectionNameKeyPath, cacheName: name) @@ -231,9 +218,9 @@ public class FetchedResultsController: NSFetchedResultsContr - parameter indexPath: The index path of an object. - returns: The object at `indexPath`. */ - public subscript (indexPath: NSIndexPath) -> T { + public subscript (indexPath: IndexPath) -> T { get { - return objectAtIndexPath(indexPath) as! T + return object(at: indexPath) as! T } } } @@ -257,12 +244,15 @@ extension FetchedResultsController: DataSourceProtocol { /// :nodoc: public func items(inSection section: Int) -> [Item]? { guard section < numberOfSections() else { return nil } - return (sections?[section].objects as! [Item]) + return sections?[section].objects as! [Item]? } /// :nodoc: public func item(atRow row: Int, inSection section: Int) -> Item? { - return item(atIndexPath: NSIndexPath(forRow: row, inSection: section)) + guard section < numberOfSections() else { return nil } + guard let objects = sections?[section].objects else { return nil } + guard row < objects.count else { return nil } + return object(at: IndexPath(row: row, section: section)) as? Item } /// :nodoc: @@ -270,7 +260,7 @@ extension FetchedResultsController: DataSourceProtocol { guard section < numberOfSections() else { return nil } return sections?[section].name } - + /// :nodoc: public func footerTitle(inSection section: Int) -> String? { return nil diff --git a/Source/DataSourceProvider.swift b/Source/DataSourceProvider.swift index 120a8bf..c996181 100644 --- a/Source/DataSourceProvider.swift +++ b/Source/DataSourceProvider.swift @@ -48,7 +48,7 @@ CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSource.Ite - parameter supplementaryFactory: The supplementary view factory. - returns: A new `DataSourceProvider` instance. - + - warning: Table views do not have supplementary views, but this parameter is still required in order to satisfy the generic constraints for Swift. You can simply pass the same `cellFactory` here. The parameter will be ignored. The same applies to collection views that do not have supplementary views. Again, the parameter will be ignored. diff --git a/Source/FetchedResultsDelegate.swift b/Source/FetchedResultsDelegate.swift index ecc876a..394478c 100644 --- a/Source/FetchedResultsDelegate.swift +++ b/Source/FetchedResultsDelegate.swift @@ -56,10 +56,10 @@ public final class FetchedResultsDelegateProvider: ReusableViewFactoryProtocol - returns: The configured `TitledSupplementaryView` instance. */ - public typealias ConfigurationHandler = (view: TitledSupplementaryView, item: Item?, type: ReusableViewType, collectionView: UICollectionView, indexPath: NSIndexPath) -> TitledSupplementaryView + public typealias ConfigurationHandler = (view: TitledSupplementaryView, item: Item?, type: ReusableViewType, collectionView: UICollectionView, indexPath: IndexPath) -> TitledSupplementaryView // MARK: Private Properties @@ -65,17 +65,16 @@ public struct TitledSupplementaryViewFactory : ReusableViewFactoryProtocol // MARK: ReusableViewFactoryProtocol /// :nodoc: - public func reuseIdentiferFor(item item: Item?, type: ReusableViewType, indexPath: NSIndexPath) -> String { + public func reuseIdentiferFor(item: Item?, type: ReusableViewType, indexPath: IndexPath) -> String { return TitledSupplementaryView.identifier } /// :nodoc: - public func configure(view view: TitledSupplementaryView, + public func configure(view: TitledSupplementaryView, item: Item?, type: ReusableViewType, parentView: UICollectionView, - indexPath: NSIndexPath) -> TitledSupplementaryView { - configurator(view: view, item: item, type: type, collectionView: parentView, indexPath: indexPath) - return view + indexPath: IndexPath) -> TitledSupplementaryView { + return configurator(view: view, item: item, type: type, collectionView: parentView, indexPath: indexPath) } } diff --git a/Source/ViewFactory.swift b/Source/ViewFactory.swift index cc20972..7292b7f 100644 --- a/Source/ViewFactory.swift +++ b/Source/ViewFactory.swift @@ -46,7 +46,7 @@ public protocol CellParentViewProtocol { - returns: A valid `CellType` reusable cell. */ - func dequeueReusableCellFor(identifier identifier: String, indexPath: NSIndexPath) -> CellType + func dequeueReusableCellFor(identifier: String, indexPath: IndexPath) -> CellType /** Returns a reusable supplementary view located by its identifier and kind. @@ -57,7 +57,7 @@ public protocol CellParentViewProtocol { - returns: A valid `CellType` reusable view. */ - func dequeueReusableSupplementaryViewFor(kind kind: String, identifier: String, indexPath: NSIndexPath) -> CellType? + func dequeueReusableSupplementaryViewFor(kind: String, identifier: String, indexPath: IndexPath) -> CellType? } extension UICollectionView: CellParentViewProtocol { @@ -65,13 +65,13 @@ extension UICollectionView: CellParentViewProtocol { public typealias CellType = UICollectionReusableView /// :nodoc: - public func dequeueReusableCellFor(identifier identifier: String, indexPath: NSIndexPath) -> CellType { - return dequeueReusableCellWithReuseIdentifier(identifier, forIndexPath: indexPath) + public func dequeueReusableCellFor(identifier: String, indexPath: IndexPath) -> CellType { + return dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) } /// :nodoc: - public func dequeueReusableSupplementaryViewFor(kind kind: String, identifier: String, indexPath: NSIndexPath) -> CellType? { - return dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: identifier, forIndexPath: indexPath) + public func dequeueReusableSupplementaryViewFor(kind: String, identifier: String, indexPath: IndexPath) -> CellType? { + return dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: identifier, for: indexPath) } } @@ -80,12 +80,12 @@ extension UITableView: CellParentViewProtocol { public typealias CellType = UITableViewCell /// :nodoc: - public func dequeueReusableCellFor(identifier identifier: String, indexPath: NSIndexPath) -> CellType { - return dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) + public func dequeueReusableCellFor(identifier: String, indexPath: IndexPath) -> CellType { + return dequeueReusableCell(withIdentifier: identifier, for: indexPath) } /// :nodoc: - public func dequeueReusableSupplementaryViewFor(kind kind: String, identifier: String, indexPath: NSIndexPath) -> CellType? { + public func dequeueReusableSupplementaryViewFor(kind: String, identifier: String, indexPath: IndexPath) -> CellType? { return nil } } @@ -102,8 +102,8 @@ public protocol ReusableViewProtocol { // MARK: Associated types /** - The "parent" view of the cell. - For `UICollectionViewCell` or `UICollectionReusableView` this is `UICollectionView`. + The "parent" view of the cell. + For `UICollectionViewCell` or `UICollectionReusableView` this is `UICollectionView`. For `UITableViewCell` this is `UITableView`. */ associatedtype ParentView: UIView, CellParentViewProtocol @@ -188,7 +188,7 @@ public protocol ReusableViewFactoryProtocol { - returns: An identifier for a reusable view. */ - func reuseIdentiferFor(item item: Item?, type: ReusableViewType, indexPath: NSIndexPath) -> String + func reuseIdentiferFor(item: Item?, type: ReusableViewType, indexPath: IndexPath) -> String /** Configures and returns the specified view. @@ -201,7 +201,7 @@ public protocol ReusableViewFactoryProtocol { - returns: A configured view of type `View`. */ - func configure(view view: View, item: Item?, type: ReusableViewType, parentView: View.ParentView, indexPath: NSIndexPath) -> View + func configure(view: View, item: Item?, type: ReusableViewType, parentView: View.ParentView, indexPath: IndexPath) -> View } @@ -218,7 +218,7 @@ public extension ReusableViewFactoryProtocol where View: UITableViewCell { - returns: An initialized or dequeued, and fully configured table cell. */ - public func tableCellFor(item item: Item, tableView: UITableView, indexPath: NSIndexPath) -> View { + public func tableCellFor(item: Item, tableView: UITableView, indexPath: IndexPath) -> View { let reuseIdentifier = reuseIdentiferFor(item: item, type: .cell, indexPath: indexPath) let cell = tableView.dequeueReusableCellFor(identifier: reuseIdentifier, indexPath: indexPath) as! View return configure(view: cell, item: item, type: .cell, parentView: tableView, indexPath: indexPath) @@ -239,7 +239,7 @@ public extension ReusableViewFactoryProtocol where View: UICollectionViewCell { - returns: An initialized or dequeued, and fully configured collection cell. */ - public func collectionCellFor(item item: Item, collectionView: UICollectionView, indexPath: NSIndexPath) -> View { + public func collectionCellFor(item: Item, collectionView: UICollectionView, indexPath: IndexPath) -> View { let reuseIdentifier = reuseIdentiferFor(item: item, type: .cell, indexPath: indexPath) let cell = collectionView.dequeueReusableCellFor(identifier: reuseIdentifier, indexPath: indexPath) as! View return configure(view: cell, item: item, type: .cell, parentView: collectionView, indexPath: indexPath) @@ -261,7 +261,7 @@ public extension ReusableViewFactoryProtocol where View: UICollectionReusableVie - returns: An initialized or dequeued, and fully configured supplementary view. */ - public func supplementaryViewFor(item item: Item?, kind: String, collectionView: UICollectionView, indexPath: NSIndexPath) -> View { + public func supplementaryViewFor(item: Item?, kind: String, collectionView: UICollectionView, indexPath: IndexPath) -> View { let reuseIdentifier = reuseIdentiferFor(item: item, type: .supplementaryView(kind: kind), indexPath: indexPath) let view = collectionView.dequeueReusableSupplementaryViewFor(kind: kind, identifier: reuseIdentifier, indexPath: indexPath) as! View return configure(view: view, item: item, type: .supplementaryView(kind: kind), parentView: collectionView, indexPath: indexPath) @@ -289,7 +289,7 @@ public struct ViewFactory: ReusableViewFactory - returns: The configured cell. */ - public typealias ViewConfigurator = (cell: Cell, item: Item?, type: ReusableViewType, parentView: Cell.ParentView, indexPath: NSIndexPath) -> Cell + public typealias ViewConfigurator = (cell: Cell, item: Item?, type: ReusableViewType, parentView: Cell.ParentView, indexPath: IndexPath) -> Cell // MARK: Properties @@ -308,7 +308,7 @@ public struct ViewFactory: ReusableViewFactory /// A closure used to configure the views. public let viewConfigurator: ViewConfigurator - + // MARK: Initialization /** @@ -327,12 +327,12 @@ public struct ViewFactory: ReusableViewFactory } /// :nodoc: - public func reuseIdentiferFor(item item: Item?, type: ReusableViewType, indexPath: NSIndexPath) -> String { + public func reuseIdentiferFor(item: Item?, type: ReusableViewType, indexPath: IndexPath) -> String { return reuseIdentifier } /// :nodoc: - public func configure(view view: Cell, item: Item?, type: ReusableViewType, parentView: Cell.ParentView, indexPath: NSIndexPath) -> Cell { + public func configure(view: Cell, item: Item?, type: ReusableViewType, parentView: Cell.ParentView, indexPath: IndexPath) -> Cell { assert(self.type == type) return viewConfigurator(cell: view, item: item, type: type, parentView: parentView, indexPath: indexPath) } diff --git a/Tests/BridgedDataSourceTests.swift b/Tests/BridgedDataSourceTests.swift index 905bda3..fdda2f7 100644 --- a/Tests/BridgedDataSourceTests.swift +++ b/Tests/BridgedDataSourceTests.swift @@ -45,7 +45,7 @@ final class BridgedDataSourceTests: TestCase { // WHEN: we query the collectionViewDataSource methods // THEN: we receive the expected data - let sections = dataSource.numberOfSectionsInCollectionView(collectionView) + let sections = dataSource.numberOfSections(in: collectionView) XCTAssertEqual(sections, 5) for s in 0..() class FakeSectionInfo: NSObject, NSFetchedResultsSectionInfo { @objc var numberOfObjects: Int = 0 @@ -57,12 +57,12 @@ final class BridgedFetchedResultsDelegateTests: XCTestCase { // WHEN: we call the NSFetchedResultsControllerDelegate methods delegate.controllerWillChangeContent(controller) - delegate.controller(controller, didChangeSection: FakeSectionInfo(), atIndex: 0, forChangeType: .Update) - delegate.controller(controller, didChangeObject: NSObject(), atIndexPath: nil, forChangeType: .Update, newIndexPath: nil) + delegate.controller(controller, didChange: FakeSectionInfo(), atSectionIndex: 0, for: .update) + delegate.controller(controller, didChange: NSObject(), at: nil, for: .update, newIndexPath: nil) delegate.controllerDidChangeContent(controller) // THEN: the delegate executes its closures - waitForExpectationsWithTimeout(defaultTimeout) { (error) in + waitForExpectations(withTimeout: defaultTimeout) { (error) in XCTAssertNil(error, "Expectations should not error") } } diff --git a/Tests/DataSourceProviderSubscriptTests.swift b/Tests/DataSourceProviderSubscriptTests.swift index 4d8449e..23d4220 100644 --- a/Tests/DataSourceProviderSubscriptTests.swift +++ b/Tests/DataSourceProviderSubscriptTests.swift @@ -88,8 +88,8 @@ final class DataSourceProviderSubscriptTests: XCTestCase { let dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory) // WHEN: we ask for an item at a specific index path - let item1 = dataSourceProvider.dataSource[NSIndexPath(forItem: 2, inSection: 0)] - let item2 = dataSourceProvider.dataSource[NSIndexPath(forItem: 0, inSection: 1)] + let item1 = dataSourceProvider.dataSource[IndexPath(item: 2, section: 0)] + let item2 = dataSourceProvider.dataSource[IndexPath(item: 0, section: 1)] // THEN: we receive the expected item XCTAssertEqual(item1, section0[2], "Item returned from subscript should equal expected item") @@ -111,7 +111,7 @@ final class DataSourceProviderSubscriptTests: XCTestCase { let dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory) // WHEN: we set an item at a specific index path - let indexPath = NSIndexPath(forItem: 2, inSection: 0) + let indexPath = IndexPath(item: 2, section: 0) let expectedItem = FakeViewModel() dataSourceProvider.dataSource[indexPath] = expectedItem diff --git a/Tests/DataSourceProviderTests.swift b/Tests/DataSourceProviderTests.swift index 24d88a0..936b0dd 100644 --- a/Tests/DataSourceProviderTests.swift +++ b/Tests/DataSourceProviderTests.swift @@ -49,13 +49,13 @@ final class DataSourceProviderTests: TestCase { func test_thatDataSourceProvider_forCollectionView_returnsExpectedData_forSingleSection() { // GIVEN: a single section with data items let expectedModel = FakeViewModel() - let expectedIndexPath = NSIndexPath(forRow: 3, inSection: 0) + let expectedIndexPath = IndexPath(row: 3, section: 0) let section0 = Section(items: FakeViewModel(), FakeViewModel(), FakeViewModel(), expectedModel, FakeViewModel()) let dataSource = DataSource([section0]) - let cellFactoryExpectation = expectationWithDescription(#function) - collectionView.dequeueCellExpectation = expectationWithDescription(dequeueCellExpectationName + #function) + let cellFactoryExpectation = expectation(withDescription: #function) + collectionView.dequeueCellExpectation = expectation(withDescription: dequeueCellExpectationName + #function) // GIVEN: a cell factory let cellFactory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, collectionView, indexPath) -> FakeCollectionCell in @@ -75,9 +75,9 @@ final class DataSourceProviderTests: TestCase { collectionView.dataSource = collectionViewDataSource // WHEN: we call the collection view data source methods - let numSections = collectionViewDataSource.numberOfSectionsInCollectionView?(collectionView) + let numSections = collectionViewDataSource.numberOfSections?(in: collectionView) let numRows = collectionViewDataSource.collectionView(collectionView, numberOfItemsInSection: 0) - let cell = collectionViewDataSource.collectionView(collectionView, cellForItemAtIndexPath: expectedIndexPath) + let cell = collectionViewDataSource.collectionView(collectionView, cellForItemAt: expectedIndexPath) // THEN: we receive the expected return values XCTAssertNotNil(numSections, "Number of sections should not be nil") @@ -89,7 +89,7 @@ final class DataSourceProviderTests: TestCase { // THEN: the collectionView calls `dequeueReusableCellWithReuseIdentifier` // THEN: the cell factory calls its `ConfigurationHandler` - waitForExpectationsWithTimeout(defaultTimeout, handler: { (error) -> Void in + waitForExpectations(withTimeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expectation should not error") }) } @@ -105,7 +105,7 @@ final class DataSourceProviderTests: TestCase { return cell } - let supplementaryFactoryExpectation = expectationWithDescription("supplementary_factory_\(#function)") + let supplementaryFactoryExpectation = expectation(withDescription: "supplementary_factory_\(#function)") // GIVEN: a supplementary view factory let supplementaryViewFactory = ViewFactory(reuseIdentifier: supplementaryViewReuseId, @@ -125,11 +125,11 @@ final class DataSourceProviderTests: TestCase { collectionView.layoutSubviews() // WHEN: we call the collection view data source methods - let numSections = collectionViewDataSource.numberOfSectionsInCollectionView?(collectionView) + let numSections = collectionViewDataSource.numberOfSections?(in: collectionView) let numRows = collectionViewDataSource.collectionView(collectionView, numberOfItemsInSection: 0) let supplementaryView = collectionViewDataSource.collectionView?(collectionView, viewForSupplementaryElementOfKind: fakeSupplementaryViewKind, - atIndexPath: NSIndexPath(forItem: 0, inSection: 0)) + at: IndexPath(item: 0, section: 0)) // THEN: we receive the expected return values XCTAssertEqual(numSections!, 1, "Data source should return 1 section") @@ -140,7 +140,7 @@ final class DataSourceProviderTests: TestCase { // THEN: the collectionView calls `dequeueReusableSupplementaryViewOfKind` // THEN: the supplementary view factory calls its `ConfigurationHandler` - waitForExpectationsWithTimeout(defaultTimeout, handler: { (error) -> Void in + waitForExpectations(withTimeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expectation should not error") }) } @@ -152,25 +152,25 @@ final class DataSourceProviderTests: TestCase { let section2 = Section(items: FakeViewModel(), FakeViewModel(), FakeViewModel(), FakeViewModel()) let dataSource = DataSource([section0, section1, section2]) - var cellFactoryExpectation = expectationWithDescription("cell_factory_\(#function)") + var cellFactoryExpectation = expectation(withDescription: "cell_factory_\(#function)") // GIVEN: a cell factory let cellFactory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, collectionView, indexPath) -> FakeCollectionCell in XCTAssertEqual(cell.reuseIdentifier!, self.cellReuseId, "Dequeued cell should have expected identifier") - XCTAssertEqual(model, dataSource[indexPath.section][indexPath.item], "Model object should equal expected value") + XCTAssertEqual(model, dataSource[indexPath.section][indexPath.row], "Model object should equal expected value") XCTAssertEqual(collectionView, self.collectionView, "CollectionView should equal the collectionView for the data source") cellFactoryExpectation.fulfill() return cell } - var supplementaryFactoryExpectation = expectationWithDescription("supplementary_factory_\(#function)") + var supplementaryFactoryExpectation = expectation(withDescription: "supplementary_factory_\(#function)") // GIVEN: a supplementary view factory let supplementaryViewFactory = ViewFactory(reuseIdentifier: supplementaryViewReuseId, type: .supplementaryView(kind: fakeSupplementaryViewKind)) { (view, model: FakeViewModel?, type, collectionView, indexPath) -> FakeCollectionSupplementaryView in XCTAssertEqual(view.reuseIdentifier!, self.supplementaryViewReuseId, "Dequeued supplementary view should have expected identifier") - XCTAssertEqual(model, dataSource[indexPath.section][indexPath.item], "Model object should equal expected value") + XCTAssertEqual(model, dataSource[indexPath.section][indexPath.row], "Model object should equal expected value") XCTAssertEqual(type, ReusableViewType.supplementaryView(kind: fakeSupplementaryViewKind), "View type should have expected type") XCTAssertEqual(collectionView, self.collectionView, "CollectionView should equal the collectionView for the data source") @@ -188,7 +188,7 @@ final class DataSourceProviderTests: TestCase { collectionView.dataSource = collectionViewDataSource // WHEN: we call the collection view data source methods - let numSections = collectionViewDataSource.numberOfSectionsInCollectionView?(collectionView) + let numSections = collectionViewDataSource.numberOfSections?(in: collectionView) // THEN: we receive the expected return values XCTAssertNotNil(numSections, "Number of sections should not be nil") @@ -198,15 +198,15 @@ final class DataSourceProviderTests: TestCase { for rowIndex in 0.. Void in + waitForExpectations(withTimeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expections should not error") }) // reset expectation names for next loop, ignore last item if !(sectionIndex == dataSource.sections.count - 1 && rowIndex == dataSource[sectionIndex].count - 1) { - cellFactoryExpectation = expectationWithDescription("cell_factory_" + expectationName) - supplementaryFactoryExpectation = expectationWithDescription("supplementary_factory_" + expectationName) + cellFactoryExpectation = expectation(withDescription: "cell_factory_" + expectationName) + supplementaryFactoryExpectation = expectation(withDescription: "supplementary_factory_" + expectationName) } } } @@ -240,15 +240,15 @@ final class DataSourceProviderTests: TestCase { func test_thatDataSourceProvider_forTableView_returnsExpectedData_forSingleSection() { // GIVEN: a single section with data items let expectedModel = FakeViewModel() - let expectedIndexPath = NSIndexPath(forRow: 2, inSection: 0) + let expectedIndexPath = IndexPath(row: 2, section: 0) let section0 = Section(items: FakeViewModel(), FakeViewModel(), expectedModel, FakeViewModel(), FakeViewModel(), headerTitle: "Header", footerTitle: "Footer") let dataSource = DataSource([section0]) - let factoryExpectation = expectationWithDescription(#function) - tableView.dequeueCellExpectation = expectationWithDescription(dequeueCellExpectationName + #function) + let factoryExpectation = expectation(withDescription: #function) + tableView.dequeueCellExpectation = expectation(withDescription: dequeueCellExpectationName + #function) // GIVEN: a cell factory let factory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, tableView, indexPath) -> FakeTableCell in @@ -269,9 +269,9 @@ final class DataSourceProviderTests: TestCase { tableView.dataSource = tableViewDataSource // WHEN: we call the table view data source methods - let numSections = tableViewDataSource.numberOfSectionsInTableView?(tableView) + let numSections = tableViewDataSource.numberOfSections?(in: tableView) let numRows = tableViewDataSource.tableView(tableView, numberOfRowsInSection: 0) - let cell = tableViewDataSource.tableView(tableView, cellForRowAtIndexPath: expectedIndexPath) + let cell = tableViewDataSource.tableView(tableView, cellForRowAt: expectedIndexPath) let header = tableViewDataSource.tableView?(tableView, titleForHeaderInSection: 0) let footer = tableViewDataSource.tableView?(tableView, titleForFooterInSection: 0) @@ -294,7 +294,7 @@ final class DataSourceProviderTests: TestCase { // THEN: the tableView calls `dequeueReusableCellWithIdentifier` // THEN: the cell factory calls its `ConfigurationHandler` - waitForExpectationsWithTimeout(defaultTimeout, handler: { (error) -> Void in + waitForExpectations(withTimeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expectations should not error") }) } @@ -307,7 +307,7 @@ final class DataSourceProviderTests: TestCase { let section3 = Section(items: FakeViewModel(), FakeViewModel(), FakeViewModel(), FakeViewModel(), FakeViewModel()) let dataSource = DataSource([section0, section1, section2, section3]) - var factoryExpectation = expectationWithDescription("factory_\(#function)") + var factoryExpectation = expectation(withDescription: "factory_\(#function)") // GIVEN: a cell factory let factory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, tableView, indexPath) -> FakeTableCell in @@ -326,7 +326,7 @@ final class DataSourceProviderTests: TestCase { tableView.dataSource = tableViewDataSource // WHEN: we call the table view data source methods - let numSections = tableViewDataSource.numberOfSectionsInTableView?(tableView) + let numSections = tableViewDataSource.numberOfSections?(in: tableView) // THEN: we receive the expected return values XCTAssertNotNil(numSections, "Number of sections should not be nil") @@ -337,14 +337,14 @@ final class DataSourceProviderTests: TestCase { for rowIndex in 0.. Void in + waitForExpectations(withTimeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expectations should not error") }) // reset expectation names for next loop, ignore last item if !(sectionIndex == dataSourceProvider.dataSource.sections.count - 1 && rowIndex == dataSourceProvider.dataSource[sectionIndex].count - 1) { - factoryExpectation = expectationWithDescription("factory_" + expectationName) + factoryExpectation = expectation(withDescription: "factory_" + expectationName) } } } diff --git a/Tests/DataSourceTests.swift b/Tests/DataSourceTests.swift index e18164c..f6875dd 100644 --- a/Tests/DataSourceTests.swift +++ b/Tests/DataSourceTests.swift @@ -151,9 +151,9 @@ final class DataSourceTests: XCTestCase { // WHEN: we ask for an object // THEN: we receive the exepected data - XCTAssertEqual(frc[NSIndexPath(forItem: 1, inSection: 0)], blueThings[1]) - XCTAssertEqual(frc[NSIndexPath(forItem: 2, inSection: 1)], greenThings[2]) - XCTAssertEqual(frc[NSIndexPath(forItem: 0, inSection: 2)], redThings[0]) + XCTAssertEqual(frc[IndexPath(item: 1, section: 0)], blueThings[1]) + XCTAssertEqual(frc[IndexPath(item: 2, section: 1)], greenThings[2]) + XCTAssertEqual(frc[IndexPath(item: 0, section: 2)], redThings[0]) } func test_thatDataSource_returnsExpectedData_fromIntSubscript() { @@ -198,7 +198,7 @@ final class DataSourceTests: XCTestCase { let dataSource = DataSource(sections: sectionA, sectionB, sectionC) // WHEN: we ask for an item - let ip = NSIndexPath(forItem: 2, inSection: 2) + let ip = IndexPath(item: 2, section: 2) let item = dataSource[ip] // THEN: we receive the exepected data @@ -212,10 +212,10 @@ final class DataSourceTests: XCTestCase { var dataSource = DataSource(sections: sectionA, sectionB) // WHEN: we set an item at a specific index path - let ip = NSIndexPath(forItem: 1, inSection: 0) + let ip = IndexPath(item: 1, section: 0) let item = FakeViewModel() dataSource[ip] = item - + // THEN: the item is replaced XCTAssertEqual(dataSource[ip], item) } diff --git a/Tests/FetchedResultsDelegateTests.swift b/Tests/FetchedResultsDelegateTests.swift index 5cb1a02..7f2f87e 100644 --- a/Tests/FetchedResultsDelegateTests.swift +++ b/Tests/FetchedResultsDelegateTests.swift @@ -61,26 +61,26 @@ final class FetchedResultsDelegateTests: TestCase { // THEN: the table view reports the expected state XCTAssertEqual(tableView.numberOfSections, 3) - XCTAssertEqual(tableView.numberOfRowsInSection(0), blueThings.count) - XCTAssertEqual(tableView.numberOfRowsInSection(1), greenThings.count) - XCTAssertEqual(tableView.numberOfRowsInSection(2), redThings.count) + XCTAssertEqual(tableView.numberOfRows(inSection: 0), blueThings.count) + XCTAssertEqual(tableView.numberOfRows(inSection: 1), greenThings.count) + XCTAssertEqual(tableView.numberOfRows(inSection: 2), redThings.count) // WHEN: we modify data, and re-fetch for obj in greenThings { - context.deleteObject(obj) + context.delete(obj) } generateThings(context, color: .Red) blueThings[0].color = .Red redThings[0].changeNameRandomly() - + stack.saveAndWait() _ = try? frc.performFetch() // THEN: the table view reports the expected state XCTAssertEqual(tableView.numberOfSections, 2) - XCTAssertEqual(tableView.numberOfRowsInSection(0), 2) - XCTAssertEqual(tableView.numberOfRowsInSection(1), 7) + XCTAssertEqual(tableView.numberOfRows(inSection: 0), 2) + XCTAssertEqual(tableView.numberOfRows(inSection: 1), 7) } func test_fetchedResultsDelegate_integration_withCollectionView() { @@ -123,15 +123,15 @@ final class FetchedResultsDelegateTests: TestCase { // THEN: the table view reports the expected state XCTAssertEqual(collectionView.numberOfSections(), 3) - XCTAssertEqual(collectionView.numberOfItemsInSection(0), blueThings.count) - XCTAssertEqual(collectionView.numberOfItemsInSection(1), greenThings.count) - XCTAssertEqual(collectionView.numberOfItemsInSection(2), redThings.count) + XCTAssertEqual(collectionView.numberOfItems(inSection: 0), blueThings.count) + XCTAssertEqual(collectionView.numberOfItems(inSection: 1), greenThings.count) + XCTAssertEqual(collectionView.numberOfItems(inSection: 2), redThings.count) collectionView.layoutSubviews() // WHEN: we modify data, and re-fetch for obj in greenThings { - context.deleteObject(obj) + context.delete(obj) } generateThings(context, color: .Red) blueThings[0].color = .Red @@ -142,9 +142,9 @@ final class FetchedResultsDelegateTests: TestCase { // THEN: the table view reports the expected state XCTAssertEqual(collectionView.numberOfSections(), 2) - - XCTAssertEqual(collectionView.numberOfItemsInSection(0), 2) - XCTAssertEqual(collectionView.numberOfItemsInSection(1), 7) + + XCTAssertEqual(collectionView.numberOfItems(inSection: 0), 2) + XCTAssertEqual(collectionView.numberOfItems(inSection: 1), 7) } - + } diff --git a/Tests/TestCase.swift b/Tests/TestCase.swift index 496c896..48ee9ca 100644 --- a/Tests/TestCase.swift +++ b/Tests/TestCase.swift @@ -24,20 +24,20 @@ class TestCase: XCTestCase { let supplementaryViewReuseId = "fakeSupplementaryId" let collectionView = FakeCollectionView(frame: CGRect(x: 0, y: 0, width: 320, height: 600), - collectionViewLayout: FakeFlowLayout()) + collectionViewLayout: FakeFlowLayout()) - let tableView = FakeTableView(frame: CGRect(x: 0, y: 0, width: 320, height: 600), style: .Plain) + let tableView = FakeTableView(frame: CGRect(x: 0, y: 0, width: 320, height: 600), style: .plain) override func setUp() { super.setUp() - collectionView.registerClass(FakeCollectionCell.self, - forCellWithReuseIdentifier: cellReuseId) + collectionView.register(FakeCollectionCell.self, + forCellWithReuseIdentifier: cellReuseId) - collectionView.registerClass(FakeCollectionSupplementaryView.self, - forSupplementaryViewOfKind: fakeSupplementaryViewKind, - withReuseIdentifier: supplementaryViewReuseId) + collectionView.register(FakeCollectionSupplementaryView.self, + forSupplementaryViewOfKind: fakeSupplementaryViewKind, + withReuseIdentifier: supplementaryViewReuseId) - tableView.registerClass(FakeTableCell.self, forCellReuseIdentifier: cellReuseId) + tableView.register(FakeTableCell.self, forCellReuseIdentifier: cellReuseId) } } diff --git a/Tests/TestHelpers.swift b/Tests/TestHelpers.swift index 53e95d4..9680c74 100644 --- a/Tests/TestHelpers.swift +++ b/Tests/TestHelpers.swift @@ -23,13 +23,13 @@ import XCTest import ExampleModel -let defaultTimeout = NSTimeInterval(5) +let defaultTimeout = TimeInterval(5) // MARK: model struct FakeViewModel: Equatable, CustomStringConvertible { - let name = NSUUID().UUIDString + let name = UUID().uuidString var description: String { get { @@ -42,7 +42,8 @@ func ==(lhs: FakeViewModel, rhs: FakeViewModel) -> Bool { return lhs.name == rhs.name } -func generateThings(context: NSManagedObjectContext, color: Color) -> [Thing] { +@discardableResult +func generateThings(_ context: NSManagedObjectContext, color: Color) -> [Thing] { var all = [Thing]() for _ in 0..<3 { let thing = Thing.newThing(context) @@ -50,9 +51,9 @@ func generateThings(context: NSManagedObjectContext, color: Color) -> [Thing] { all.append(thing) } - all.sortInPlace { (t1, t2) -> Bool in + all.sort(isOrderedBefore: { (t1, t2) -> Bool in return t1.name <= t2.name - } + }) return all } @@ -64,10 +65,10 @@ class FakeTableCell: UITableViewCell { } class FakeTableView: UITableView { var dequeueCellExpectation: XCTestExpectation? - override func dequeueReusableCellWithIdentifier(identifier: String, - forIndexPath indexPath: NSIndexPath) -> UITableViewCell { + override func dequeueReusableCell(withIdentifier identifier: String, + for indexPath: IndexPath) -> UITableViewCell { dequeueCellExpectation?.fulfill() - return super.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) + return super.dequeueReusableCell(withIdentifier: identifier, for: indexPath) } } @@ -86,27 +87,27 @@ class FakeCollectionView: UICollectionView { var dequeueSupplementaryViewExpectation: XCTestExpectation? - override func dequeueReusableCellWithReuseIdentifier(identifier: String, - forIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { + override func dequeueReusableCell(withReuseIdentifier identifier: String, + for indexPath: IndexPath) -> UICollectionViewCell { dequeueCellExpectation?.fulfill() - return super.dequeueReusableCellWithReuseIdentifier(identifier, forIndexPath: indexPath) + return super.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) } - override func dequeueReusableSupplementaryViewOfKind(elementKind: String, - withReuseIdentifier identifier: String, - forIndexPath indexPath: NSIndexPath) -> UICollectionReusableView { + override func dequeueReusableSupplementaryView(ofKind elementKind: String, + withReuseIdentifier identifier: String, + for indexPath: IndexPath) -> UICollectionReusableView { dequeueSupplementaryViewExpectation?.fulfill() - return super.dequeueReusableSupplementaryViewOfKind(elementKind, withReuseIdentifier: identifier, forIndexPath: indexPath) + return super.dequeueReusableSupplementaryView(ofKind: elementKind, withReuseIdentifier: identifier, for: indexPath) } } class FakeFlowLayout: UICollectionViewFlowLayout { - override func layoutAttributesForSupplementaryViewOfKind(elementKind: String, - atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? { + override func layoutAttributesForSupplementaryView(ofKind elementKind: String, + at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { if elementKind == fakeSupplementaryViewKind { - return UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, withIndexPath: indexPath) + return UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, with: indexPath) } - return super.layoutAttributesForSupplementaryViewOfKind(elementKind, atIndexPath: indexPath) + return super.layoutAttributesForSupplementaryView(ofKind: elementKind, at: indexPath) } } diff --git a/Tests/TitledSupplementaryViewFactoryTests.swift b/Tests/TitledSupplementaryViewFactoryTests.swift index 8864e39..0a1908d 100644 --- a/Tests/TitledSupplementaryViewFactoryTests.swift +++ b/Tests/TitledSupplementaryViewFactoryTests.swift @@ -30,9 +30,9 @@ class TitledSupplementaryViewFactoryTests: TestCase { override func setUp() { super.setUp() - collectionView.registerClass(TitledSupplementaryView.self, - forSupplementaryViewOfKind: fakeSupplementaryViewKind, - withReuseIdentifier: TitledSupplementaryView.identifier) + collectionView.register(TitledSupplementaryView.self, + forSupplementaryViewOfKind: fakeSupplementaryViewKind, + withReuseIdentifier: TitledSupplementaryView.identifier) } func test_dataSource_returnsExpectedData_withTitledSupplementaryView() { @@ -42,7 +42,7 @@ class TitledSupplementaryViewFactoryTests: TestCase { let section2 = Section(items: FakeViewModel(), FakeViewModel(), FakeViewModel(), FakeViewModel()) let dataSource = DataSource([section0, section1, section2]) - var cellFactoryExpectation = expectationWithDescription("cell_factory") + var cellFactoryExpectation = expectation(withDescription: "cell_factory") // GIVEN: a cell factory let cellFactory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, collectionView, indexPath) -> FakeCollectionCell in @@ -50,12 +50,12 @@ class TitledSupplementaryViewFactoryTests: TestCase { return cell } - var titledViewDataConfigExpectation = expectationWithDescription("titledViewDataConfigExpectation") + var titledViewDataConfigExpectation = expectation(withDescription: "titledViewDataConfigExpectation") let supplementaryViewFactory = TitledSupplementaryViewFactory { (view, item: FakeViewModel?, type, collectionView, indexPath) -> TitledSupplementaryView in XCTAssertEqual(view.reuseIdentifier!, TitledSupplementaryView.identifier, "Dequeued supplementary view should have expected identifier") XCTAssertEqual(type, ReusableViewType.supplementaryView(kind: fakeSupplementaryViewKind), "View type should have expected type") - XCTAssertEqual(item, dataSource[indexPath.section][indexPath.item], "Model object should equal expected value") + XCTAssertEqual(item, dataSource[indexPath.section][indexPath.row], "Model object should equal expected value") XCTAssertEqual(collectionView, self.collectionView, "CollectionView should equal the collectionView for the data source") titledViewDataConfigExpectation.fulfill() @@ -72,7 +72,7 @@ class TitledSupplementaryViewFactoryTests: TestCase { collectionView.dataSource = collectionViewDataSource // WHEN: we call the collection view data source methods - let numSections = collectionViewDataSource.numberOfSectionsInCollectionView?(collectionView) + let numSections = collectionViewDataSource.numberOfSections?(in: collectionView) // THEN: we receive the expected return values XCTAssertNotNil(numSections, "Number of sections should not be nil") @@ -82,15 +82,15 @@ class TitledSupplementaryViewFactoryTests: TestCase { for rowIndex in 0.. Void in + waitForExpectations(withTimeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expections should not error") }) // reset expectation names for next loop, ignore last item if !(sectionIndex == dataSource.sections.count - 1 && rowIndex == dataSource[sectionIndex].count - 1) { - cellFactoryExpectation = expectationWithDescription("cell_factory_" + expectationName) - titledViewDataConfigExpectation = expectationWithDescription("titledViewDataConfigExpectation_" + expectationName) + cellFactoryExpectation = expectation(withDescription: "cell_factory_" + expectationName) + titledViewDataConfigExpectation = expectation(withDescription: "titledViewDataConfigExpectation_" + expectationName) } } } diff --git a/Tests/TitledSupplementaryViewTests.swift b/Tests/TitledSupplementaryViewTests.swift index 02db9fc..dafcdde 100644 --- a/Tests/TitledSupplementaryViewTests.swift +++ b/Tests/TitledSupplementaryViewTests.swift @@ -64,7 +64,7 @@ final class TitledSupplementaryViewTests: XCTestCase { func test_thatView_preparesForReuse_ForAttributedText() { let view = TitledSupplementaryView(frame: CGRect(x: 0, y: 0, width: 320, height: 100)) view.layoutIfNeeded() - view.label.attributedText = NSAttributedString(string:"title text") + view.label.attributedText = AttributedString(string:"title text") XCTAssertNotNil(view.label.attributedText) @@ -76,9 +76,9 @@ final class TitledSupplementaryViewTests: XCTestCase { func test_thatView_setsBackgoundColor() { let view = TitledSupplementaryView(frame: CGRect(x: 0, y: 0, width: 320, height: 100)) view.layoutIfNeeded() - view.backgroundColor = .redColor() + view.backgroundColor = .red() XCTAssertEqual(view.label.backgroundColor, view.backgroundColor) - XCTAssertEqual(view.label.backgroundColor, .redColor()) + XCTAssertEqual(view.label.backgroundColor, .red()) } } From 2f442d491e3d7fcb00e3fe019a1b1a0648d27f1f Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Tue, 19 Jul 2016 10:23:13 -0700 Subject: [PATCH 04/24] update xcode 8 beta 3, #54 --- Example/Example.xcodeproj/project.pbxproj | 2 + .../ExampleModel.xcodeproj/project.pbxproj | 2 + .../ExampleModel/Sources/CoreDataStack.swift | 2 +- JSQDataSourcesKit.xcodeproj/project.pbxproj | 2 + Source/FetchedResultsDelegate.swift | 16 ++++---- Source/ViewFactory.swift | 1 + .../BridgedFetchedResultsDelegateTests.swift | 10 ++--- Tests/DataSourceProviderTests.swift | 38 +++++++++---------- .../TitledSupplementaryViewFactoryTests.swift | 14 +++---- 9 files changed, 47 insertions(+), 40 deletions(-) diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index edc661e..ebce1f3 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -625,6 +625,7 @@ PRODUCT_NAME = DataSources; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -662,6 +663,7 @@ MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = DataSources; SDKROOT = iphoneos; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; diff --git a/Example/ExampleModel/ExampleModel.xcodeproj/project.pbxproj b/Example/ExampleModel/ExampleModel.xcodeproj/project.pbxproj index badc0c7..b0feec9 100644 --- a/Example/ExampleModel/ExampleModel.xcodeproj/project.pbxproj +++ b/Example/ExampleModel/ExampleModel.xcodeproj/project.pbxproj @@ -275,6 +275,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -316,6 +317,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; diff --git a/Example/ExampleModel/Sources/CoreDataStack.swift b/Example/ExampleModel/Sources/CoreDataStack.swift index 4d7ad1c..74a22f1 100755 --- a/Example/ExampleModel/Sources/CoreDataStack.swift +++ b/Example/ExampleModel/Sources/CoreDataStack.swift @@ -34,7 +34,7 @@ public class CoreDataStack { let modelURL = Bundle(for: CoreDataStack.self).urlForResource("Model", withExtension: "momd")! let model = NSManagedObjectModel(contentsOf: modelURL)! - let documentsDirectoryURL = try! FileManager.default().urlForDirectory(.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) + let documentsDirectoryURL = try! FileManager.default.urlForDirectory(.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) let storeURL = try! documentsDirectoryURL.appendingPathComponent("Model.sqlite") persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model) diff --git a/JSQDataSourcesKit.xcodeproj/project.pbxproj b/JSQDataSourcesKit.xcodeproj/project.pbxproj index 00ee56d..c6b1f52 100644 --- a/JSQDataSourcesKit.xcodeproj/project.pbxproj +++ b/JSQDataSourcesKit.xcodeproj/project.pbxproj @@ -524,6 +524,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -564,6 +565,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_VERSION = 3.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; diff --git a/Source/FetchedResultsDelegate.swift b/Source/FetchedResultsDelegate.swift index 394478c..79c3dec 100644 --- a/Source/FetchedResultsDelegate.swift +++ b/Source/FetchedResultsDelegate.swift @@ -115,7 +115,7 @@ extension FetchedResultsDelegateProvider where CellFactory.View.ParentView == UI self.updatedObjects[indexPath] = anyObject as? Item } case .move: - if let old = indexPath, new = newIndexPath { + if let old = indexPath, let new = newIndexPath { self.objectChanges.append((changeType, [old, new])) } } @@ -142,10 +142,10 @@ extension FetchedResultsDelegateProvider where CellFactory.View.ParentView == UI collectionView?.deleteItems(at: indexPaths) case .update: if let indexPath = indexPaths.first, - item = updatedObjects[indexPath], - cell = collectionView?.cellForItem(at: indexPath) as? CellFactory.View, - collectionView = collectionView { - _ = cellFactory.configure(view: cell, item: item, type: .cell, parentView: collectionView, indexPath: indexPath) + let item = updatedObjects[indexPath], + let collectionView = collectionView, + let cell = collectionView.cellForItem(at: indexPath) as? CellFactory.View { + cellFactory.configure(view: cell, item: item, type: .cell, parentView: collectionView, indexPath: indexPath) } case .move: if let deleteIndexPath = indexPaths.first { @@ -235,9 +235,9 @@ extension FetchedResultsDelegateProvider where CellFactory.View.ParentView == UI } case .update: if let indexPath = indexPath, - cell = self.tableView?.cellForRow(at: indexPath) as? CellFactory.View, - tableView = self.tableView { - _ = self.cellFactory.configure(view: cell, item: anyObject as? Item, type: .cell, parentView: tableView, indexPath: indexPath) + let tableView = self.tableView, + let cell = tableView.cellForRow(at: indexPath) as? CellFactory.View { + self.cellFactory.configure(view: cell, item: anyObject as? Item, type: .cell, parentView: tableView, indexPath: indexPath) } case .move: if let deleteIndexPath = indexPath { diff --git a/Source/ViewFactory.swift b/Source/ViewFactory.swift index 7292b7f..560de0d 100644 --- a/Source/ViewFactory.swift +++ b/Source/ViewFactory.swift @@ -201,6 +201,7 @@ public protocol ReusableViewFactoryProtocol { - returns: A configured view of type `View`. */ + @discardableResult func configure(view: View, item: Item?, type: ReusableViewType, parentView: View.ParentView, indexPath: IndexPath) -> View } diff --git a/Tests/BridgedFetchedResultsDelegateTests.swift b/Tests/BridgedFetchedResultsDelegateTests.swift index e9938e1..014554c 100644 --- a/Tests/BridgedFetchedResultsDelegateTests.swift +++ b/Tests/BridgedFetchedResultsDelegateTests.swift @@ -26,10 +26,10 @@ import XCTest final class BridgedFetchedResultsDelegateTests: XCTestCase { func test_thatFetchedResultsDelegate_callsClosures_whenDelegateMethodsAreCalled() { - let willChangeContentExpectation = self.expectation(withDescription: "will change content") - let didChangeSectionExpectation = self.expectation(withDescription: "will change content") - let didChangeObjectExpectation = self.expectation(withDescription: "will change content") - let didChangeContentExpectation = self.expectation(withDescription: "will change content") + let willChangeContentExpectation = self.expectation(description: "will change content") + let didChangeSectionExpectation = self.expectation(description: "will change content") + let didChangeObjectExpectation = self.expectation(description: "will change content") + let didChangeContentExpectation = self.expectation(description: "will change content") // GIVEN: a fetched results delegate let delegate = BridgedFetchedResultsDelegate( @@ -62,7 +62,7 @@ final class BridgedFetchedResultsDelegateTests: XCTestCase { delegate.controllerDidChangeContent(controller) // THEN: the delegate executes its closures - waitForExpectations(withTimeout: defaultTimeout) { (error) in + waitForExpectations(timeout: defaultTimeout) { (error) in XCTAssertNil(error, "Expectations should not error") } } diff --git a/Tests/DataSourceProviderTests.swift b/Tests/DataSourceProviderTests.swift index 936b0dd..2d1e861 100644 --- a/Tests/DataSourceProviderTests.swift +++ b/Tests/DataSourceProviderTests.swift @@ -54,8 +54,8 @@ final class DataSourceProviderTests: TestCase { let section0 = Section(items: FakeViewModel(), FakeViewModel(), FakeViewModel(), expectedModel, FakeViewModel()) let dataSource = DataSource([section0]) - let cellFactoryExpectation = expectation(withDescription: #function) - collectionView.dequeueCellExpectation = expectation(withDescription: dequeueCellExpectationName + #function) + let cellFactoryExpectation = expectation(description: #function) + collectionView.dequeueCellExpectation = expectation(description: dequeueCellExpectationName + #function) // GIVEN: a cell factory let cellFactory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, collectionView, indexPath) -> FakeCollectionCell in @@ -89,7 +89,7 @@ final class DataSourceProviderTests: TestCase { // THEN: the collectionView calls `dequeueReusableCellWithReuseIdentifier` // THEN: the cell factory calls its `ConfigurationHandler` - waitForExpectations(withTimeout: defaultTimeout, handler: { (error) -> Void in + waitForExpectations(timeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expectation should not error") }) } @@ -105,7 +105,7 @@ final class DataSourceProviderTests: TestCase { return cell } - let supplementaryFactoryExpectation = expectation(withDescription: "supplementary_factory_\(#function)") + let supplementaryFactoryExpectation = expectation(description: "supplementary_factory_\(#function)") // GIVEN: a supplementary view factory let supplementaryViewFactory = ViewFactory(reuseIdentifier: supplementaryViewReuseId, @@ -140,7 +140,7 @@ final class DataSourceProviderTests: TestCase { // THEN: the collectionView calls `dequeueReusableSupplementaryViewOfKind` // THEN: the supplementary view factory calls its `ConfigurationHandler` - waitForExpectations(withTimeout: defaultTimeout, handler: { (error) -> Void in + waitForExpectations(timeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expectation should not error") }) } @@ -152,7 +152,7 @@ final class DataSourceProviderTests: TestCase { let section2 = Section(items: FakeViewModel(), FakeViewModel(), FakeViewModel(), FakeViewModel()) let dataSource = DataSource([section0, section1, section2]) - var cellFactoryExpectation = expectation(withDescription: "cell_factory_\(#function)") + var cellFactoryExpectation = expectation(description: "cell_factory_\(#function)") // GIVEN: a cell factory let cellFactory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, collectionView, indexPath) -> FakeCollectionCell in @@ -164,7 +164,7 @@ final class DataSourceProviderTests: TestCase { return cell } - var supplementaryFactoryExpectation = expectation(withDescription: "supplementary_factory_\(#function)") + var supplementaryFactoryExpectation = expectation(description: "supplementary_factory_\(#function)") // GIVEN: a supplementary view factory let supplementaryViewFactory = ViewFactory(reuseIdentifier: supplementaryViewReuseId, type: .supplementaryView(kind: fakeSupplementaryViewKind)) @@ -198,8 +198,8 @@ final class DataSourceProviderTests: TestCase { for rowIndex in 0.. Void in + waitForExpectations(timeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expections should not error") }) // reset expectation names for next loop, ignore last item if !(sectionIndex == dataSource.sections.count - 1 && rowIndex == dataSource[sectionIndex].count - 1) { - cellFactoryExpectation = expectation(withDescription: "cell_factory_" + expectationName) - supplementaryFactoryExpectation = expectation(withDescription: "supplementary_factory_" + expectationName) + cellFactoryExpectation = expectation(description: "cell_factory_" + expectationName) + supplementaryFactoryExpectation = expectation(description: "supplementary_factory_" + expectationName) } } } @@ -247,8 +247,8 @@ final class DataSourceProviderTests: TestCase { footerTitle: "Footer") let dataSource = DataSource([section0]) - let factoryExpectation = expectation(withDescription: #function) - tableView.dequeueCellExpectation = expectation(withDescription: dequeueCellExpectationName + #function) + let factoryExpectation = expectation(description: #function) + tableView.dequeueCellExpectation = expectation(description: dequeueCellExpectationName + #function) // GIVEN: a cell factory let factory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, tableView, indexPath) -> FakeTableCell in @@ -294,7 +294,7 @@ final class DataSourceProviderTests: TestCase { // THEN: the tableView calls `dequeueReusableCellWithIdentifier` // THEN: the cell factory calls its `ConfigurationHandler` - waitForExpectations(withTimeout: defaultTimeout, handler: { (error) -> Void in + waitForExpectations(timeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expectations should not error") }) } @@ -307,7 +307,7 @@ final class DataSourceProviderTests: TestCase { let section3 = Section(items: FakeViewModel(), FakeViewModel(), FakeViewModel(), FakeViewModel(), FakeViewModel()) let dataSource = DataSource([section0, section1, section2, section3]) - var factoryExpectation = expectation(withDescription: "factory_\(#function)") + var factoryExpectation = expectation(description: "factory_\(#function)") // GIVEN: a cell factory let factory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, tableView, indexPath) -> FakeTableCell in @@ -337,7 +337,7 @@ final class DataSourceProviderTests: TestCase { for rowIndex in 0.. Void in + waitForExpectations(timeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expectations should not error") }) // reset expectation names for next loop, ignore last item if !(sectionIndex == dataSourceProvider.dataSource.sections.count - 1 && rowIndex == dataSourceProvider.dataSource[sectionIndex].count - 1) { - factoryExpectation = expectation(withDescription: "factory_" + expectationName) + factoryExpectation = expectation(description: "factory_" + expectationName) } } } diff --git a/Tests/TitledSupplementaryViewFactoryTests.swift b/Tests/TitledSupplementaryViewFactoryTests.swift index 0a1908d..ff54c91 100644 --- a/Tests/TitledSupplementaryViewFactoryTests.swift +++ b/Tests/TitledSupplementaryViewFactoryTests.swift @@ -42,7 +42,7 @@ class TitledSupplementaryViewFactoryTests: TestCase { let section2 = Section(items: FakeViewModel(), FakeViewModel(), FakeViewModel(), FakeViewModel()) let dataSource = DataSource([section0, section1, section2]) - var cellFactoryExpectation = expectation(withDescription: "cell_factory") + var cellFactoryExpectation = expectation(description: "cell_factory") // GIVEN: a cell factory let cellFactory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, collectionView, indexPath) -> FakeCollectionCell in @@ -50,7 +50,7 @@ class TitledSupplementaryViewFactoryTests: TestCase { return cell } - var titledViewDataConfigExpectation = expectation(withDescription: "titledViewDataConfigExpectation") + var titledViewDataConfigExpectation = expectation(description: "titledViewDataConfigExpectation") let supplementaryViewFactory = TitledSupplementaryViewFactory { (view, item: FakeViewModel?, type, collectionView, indexPath) -> TitledSupplementaryView in XCTAssertEqual(view.reuseIdentifier!, TitledSupplementaryView.identifier, "Dequeued supplementary view should have expected identifier") @@ -82,8 +82,8 @@ class TitledSupplementaryViewFactoryTests: TestCase { for rowIndex in 0.. Void in + waitForExpectations(timeout: defaultTimeout, handler: { (error) -> Void in XCTAssertNil(error, "Expections should not error") }) // reset expectation names for next loop, ignore last item if !(sectionIndex == dataSource.sections.count - 1 && rowIndex == dataSource[sectionIndex].count - 1) { - cellFactoryExpectation = expectation(withDescription: "cell_factory_" + expectationName) - titledViewDataConfigExpectation = expectation(withDescription: "titledViewDataConfigExpectation_" + expectationName) + cellFactoryExpectation = expectation(description: "cell_factory_" + expectationName) + titledViewDataConfigExpectation = expectation(description: "titledViewDataConfigExpectation_" + expectationName) } } } From 63ac07fc499b860c1543046e13ef85cd509744ef Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Wed, 27 Jul 2016 22:40:08 -0700 Subject: [PATCH 05/24] proj settings --- Example/Example.xcodeproj/project.pbxproj | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index b553058..091d841 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -635,12 +635,13 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = DataSources; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 2.3; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -674,10 +675,11 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_NAME = DataSources; SDKROOT = iphoneos; + SWIFT_VERSION = 2.3; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; From 4ee1a400e8bf355f42b3133b468f8a27b4449319 Mon Sep 17 00:00:00 2001 From: Dave Caunt Date: Thu, 28 Jul 2016 17:48:56 +0100 Subject: [PATCH 06/24] Update mixed cell type example for Swift 3.0 --- Example/Sources/ComposedCellViewFactory.swift | 8 ++++---- Example/Sources/FancyCollectionViewCell.swift | 4 ++-- .../MixedCollectionViewController.swift | 20 +++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Example/Sources/ComposedCellViewFactory.swift b/Example/Sources/ComposedCellViewFactory.swift index 712d471..7fc085b 100644 --- a/Example/Sources/ComposedCellViewFactory.swift +++ b/Example/Sources/ComposedCellViewFactory.swift @@ -35,11 +35,11 @@ struct ComposedCellViewFactory: ReusableViewFactoryProtocol { self.fancyCellFactory = fancyCellFactory } - func reuseIdentiferFor(item item: MixedItem?, type: ReusableViewType, indexPath: NSIndexPath) -> String { + func reuseIdentiferFor(item: MixedItem?, type: ReusableViewType, indexPath: IndexPath) -> String { return item!.reuseIdentifier } - func configure(view view: UICollectionViewCell, item: MixedItem?, type: ReusableViewType, parentView: UICollectionView, indexPath: NSIndexPath) -> UICollectionViewCell { + func configure(view: UICollectionViewCell, item: MixedItem?, type: ReusableViewType, parentView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell { view.accessibilityIdentifier = "\(indexPath.section), \(indexPath.item)" guard let model = item else { @@ -47,10 +47,10 @@ struct ComposedCellViewFactory: ReusableViewFactoryProtocol { } switch model { - case let .Standard(standardModel): + case let .standard(standardModel): let cell = view as! CollectionViewCell return standardCellFactory.configure(view: cell, item: standardModel, type: type, parentView: parentView, indexPath: indexPath) - case let .Fancy(fancyModel): + case let .fancy(fancyModel): let cell = view as! FancyCollectionViewCell return fancyCellFactory.configure(view: cell, item: fancyModel, type: type, parentView: parentView, indexPath: indexPath) } diff --git a/Example/Sources/FancyCollectionViewCell.swift b/Example/Sources/FancyCollectionViewCell.swift index 2dc6230..d05eb3c 100644 --- a/Example/Sources/FancyCollectionViewCell.swift +++ b/Example/Sources/FancyCollectionViewCell.swift @@ -25,7 +25,7 @@ class FancyCollectionViewCell: UICollectionViewCell { override func awakeFromNib() { super.awakeFromNib() selectedBackgroundView = UIView() - selectedBackgroundView?.backgroundColor = .orangeColor() - backgroundColor = .greenColor() + selectedBackgroundView?.backgroundColor = .orange() + backgroundColor = .green() } } diff --git a/Example/Sources/MixedCollectionViewController.swift b/Example/Sources/MixedCollectionViewController.swift index 0eab877..cb31d97 100644 --- a/Example/Sources/MixedCollectionViewController.swift +++ b/Example/Sources/MixedCollectionViewController.swift @@ -26,14 +26,14 @@ struct FancyViewModel { } enum MixedItem { - case Standard(CellViewModel) - case Fancy(FancyViewModel) + case standard(CellViewModel) + case fancy(FancyViewModel) var reuseIdentifier: String { switch self { - case .Standard(_): + case .standard(_): return CellId - case .Fancy(_): + case .fancy(_): return FancyCellId } } @@ -50,11 +50,11 @@ final class MixedCollectionViewController: UICollectionViewController, UICollect override func viewDidLoad() { super.viewDidLoad() configureCollectionView(collectionView!) - collectionView!.registerNib(UINib(nibName: "FancyCollectionViewCell", bundle: nil), + collectionView!.register(UINib(nibName: "FancyCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: FancyCellId) - let standardItem = MixedItem.Standard(CellViewModel()) - let fancyItem = MixedItem.Fancy(FancyViewModel()) + let standardItem = MixedItem.standard(CellViewModel()) + let fancyItem = MixedItem.fancy(FancyViewModel()) // 1. create view models let section0 = Section(items: standardItem, fancyItem, fancyItem) @@ -81,8 +81,8 @@ final class MixedCollectionViewController: UICollectionViewController, UICollect // 3. create supplementary view factory let headerFactory = TitledSupplementaryViewFactory { (header, item: MixedItem?, kind, collectionView, indexPath) -> TitledSupplementaryView in header.label.text = "Section \(indexPath.section)" - header.backgroundColor = .darkGrayColor() - header.label.textColor = .whiteColor() + header.backgroundColor = .darkGray() + header.label.textColor = .white() return header } @@ -95,7 +95,7 @@ final class MixedCollectionViewController: UICollectionViewController, UICollect collectionView?.dataSource = self.dataSourceProvider?.collectionViewDataSource } - func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.size.width, height: 50) } } From 5be49cf8401fe2009551f09944dbf46f64563d1f Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Thu, 28 Jul 2016 18:54:43 -0700 Subject: [PATCH 07/24] minor demo updates --- Example/Sources/FancyCollectionViewCell.swift | 2 +- Example/Sources/MixedCollectionViewController.swift | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Example/Sources/FancyCollectionViewCell.swift b/Example/Sources/FancyCollectionViewCell.swift index d05eb3c..730f021 100644 --- a/Example/Sources/FancyCollectionViewCell.swift +++ b/Example/Sources/FancyCollectionViewCell.swift @@ -18,7 +18,7 @@ import UIKit -class FancyCollectionViewCell: UICollectionViewCell { +final class FancyCollectionViewCell: UICollectionViewCell { @IBOutlet weak var label: UILabel! diff --git a/Example/Sources/MixedCollectionViewController.swift b/Example/Sources/MixedCollectionViewController.swift index cb31d97..1b1f1a8 100644 --- a/Example/Sources/MixedCollectionViewController.swift +++ b/Example/Sources/MixedCollectionViewController.swift @@ -95,7 +95,9 @@ final class MixedCollectionViewController: UICollectionViewController, UICollect collectionView?.dataSource = self.dataSourceProvider?.collectionViewDataSource } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + referenceSizeForHeaderInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.size.width, height: 50) } } From 04cb5dea5e8772b6d4e6bfd1fbd02e6aa6b255ca Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Wed, 3 Aug 2016 09:15:57 -0700 Subject: [PATCH 08/24] update Xcode 8 beta 4, #54 --- Example/ExampleModel/Sources/CoreDataStack.swift | 6 +++--- Example/ExampleModel/Sources/Thing.swift | 10 +++++----- Example/Sources/CollectionViewCell.swift | 2 +- Example/Sources/CollectionViewController.swift | 8 +++++--- Example/Sources/Extensions.swift | 2 +- Example/Sources/FancyCollectionViewCell.swift | 4 ++-- .../Sources/FetchedCollectionViewController.swift | 14 +++++++------- .../Sources/MixedCollectionViewController.swift | 4 ++-- Tests/FetchedResultsDelegateTests.swift | 4 ++-- Tests/TestHelpers.swift | 2 +- Tests/TitledSupplementaryViewTests.swift | 6 +++--- 11 files changed, 32 insertions(+), 30 deletions(-) diff --git a/Example/ExampleModel/Sources/CoreDataStack.swift b/Example/ExampleModel/Sources/CoreDataStack.swift index 74a22f1..44f9b64 100755 --- a/Example/ExampleModel/Sources/CoreDataStack.swift +++ b/Example/ExampleModel/Sources/CoreDataStack.swift @@ -31,11 +31,11 @@ public class CoreDataStack { public let persistentStoreCoordinator: NSPersistentStoreCoordinator public init(inMemory: Bool = false) { - let modelURL = Bundle(for: CoreDataStack.self).urlForResource("Model", withExtension: "momd")! + let modelURL = Bundle(for: CoreDataStack.self).url(forResource: "Model", withExtension: "momd")! let model = NSManagedObjectModel(contentsOf: modelURL)! - let documentsDirectoryURL = try! FileManager.default.urlForDirectory(.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) - let storeURL = try! documentsDirectoryURL.appendingPathComponent("Model.sqlite") + let documentsDirectoryURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) + let storeURL = documentsDirectoryURL.appendingPathComponent("Model.sqlite") persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model) try! persistentStoreCoordinator.addPersistentStore(ofType: inMemory ? NSInMemoryStoreType : NSSQLiteStoreType, configurationName: nil, at: inMemory ? nil : storeURL, options: nil) diff --git a/Example/ExampleModel/Sources/Thing.swift b/Example/ExampleModel/Sources/Thing.swift index e7ba406..12ef5d9 100644 --- a/Example/ExampleModel/Sources/Thing.swift +++ b/Example/ExampleModel/Sources/Thing.swift @@ -28,9 +28,9 @@ public enum Color: String { var displayColor: UIColor { switch(self) { - case .Red: return .red() - case .Blue: return .blue() - case .Green: return .green() + case .Red: return .red + case .Blue: return .blue + case .Green: return .green } } } @@ -108,8 +108,8 @@ public class Thing: NSManagedObject { public class func newFetchRequest() -> NSFetchRequest { let request = NSFetchRequest(entityName: "Thing") request.sortDescriptors = [ - SortDescriptor(key: "colorName", ascending: true), - SortDescriptor(key: "name", ascending: true) + NSSortDescriptor(key: "colorName", ascending: true), + NSSortDescriptor(key: "name", ascending: true) ] return request } diff --git a/Example/Sources/CollectionViewCell.swift b/Example/Sources/CollectionViewCell.swift index 8ce86fb..bd877e4 100644 --- a/Example/Sources/CollectionViewCell.swift +++ b/Example/Sources/CollectionViewCell.swift @@ -25,6 +25,6 @@ class CollectionViewCell: UICollectionViewCell { override func awakeFromNib() { super.awakeFromNib() selectedBackgroundView = UIView() - selectedBackgroundView?.backgroundColor = .lightGray() + selectedBackgroundView?.backgroundColor = .lightGray } } diff --git a/Example/Sources/CollectionViewController.swift b/Example/Sources/CollectionViewController.swift index ba2c710..0f11410 100644 --- a/Example/Sources/CollectionViewController.swift +++ b/Example/Sources/CollectionViewController.swift @@ -49,8 +49,8 @@ final class CollectionViewController: UICollectionViewController, UICollectionVi // 3. create supplementary view factory let headerFactory = TitledSupplementaryViewFactory { (header, item: CellViewModel?, kind, collectionView, indexPath) -> TitledSupplementaryView in header.label.text = "Section \(indexPath.section)" - header.backgroundColor = .darkGray() - header.label.textColor = .white() + header.backgroundColor = .darkGray + header.label.textColor = .white return header } @@ -63,7 +63,9 @@ final class CollectionViewController: UICollectionViewController, UICollectionVi collectionView?.dataSource = self.dataSourceProvider?.collectionViewDataSource } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + referenceSizeForHeaderInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.size.width, height: 50) } } diff --git a/Example/Sources/Extensions.swift b/Example/Sources/Extensions.swift index da6a6fc..d41f482 100644 --- a/Example/Sources/Extensions.swift +++ b/Example/Sources/Extensions.swift @@ -75,7 +75,7 @@ extension UITableView { extension UICollectionView { func deselectAllItems() { - if let indexPaths = indexPathsForSelectedItems() { + if let indexPaths = indexPathsForSelectedItems { for i in indexPaths { deselectItem(at: i, animated: true) } diff --git a/Example/Sources/FancyCollectionViewCell.swift b/Example/Sources/FancyCollectionViewCell.swift index 730f021..a7d4e70 100644 --- a/Example/Sources/FancyCollectionViewCell.swift +++ b/Example/Sources/FancyCollectionViewCell.swift @@ -25,7 +25,7 @@ final class FancyCollectionViewCell: UICollectionViewCell { override func awakeFromNib() { super.awakeFromNib() selectedBackgroundView = UIView() - selectedBackgroundView?.backgroundColor = .orange() - backgroundColor = .green() + selectedBackgroundView?.backgroundColor = .orange + backgroundColor = .green } } diff --git a/Example/Sources/FetchedCollectionViewController.swift b/Example/Sources/FetchedCollectionViewController.swift index 8bad0aa..7d2580f 100644 --- a/Example/Sources/FetchedCollectionViewController.swift +++ b/Example/Sources/FetchedCollectionViewController.swift @@ -50,7 +50,7 @@ class FetchedCollectionViewController: UICollectionViewController { // 1. create cell factory let cellFactory = ViewFactory(reuseIdentifier: CellId) { (cell, model: Thing?, type, collectionView, indexPath) -> CollectionViewCell in cell.label.text = model!.displayName - cell.label.textColor = UIColor.white() + cell.label.textColor = UIColor.white cell.backgroundColor = model!.displayColor cell.accessibilityIdentifier = "\(cell.label.text)" return cell @@ -60,14 +60,14 @@ class FetchedCollectionViewController: UICollectionViewController { let headerFactory = TitledSupplementaryViewFactory { (header, item: Thing?, kind, collectionView, indexPath) -> TitledSupplementaryView in header.label.text = "\(item!.colorName) header (\(indexPath.section))" header.label.textColor = item?.displayColor - header.backgroundColor = .darkGray() + header.backgroundColor = .darkGray return header } let footerFactory = TitledSupplementaryViewFactory { (footer, item: Thing?, kind, collectionView, indexPath) -> TitledSupplementaryView in footer.label.text = "\(item!.colorName) footer (\(indexPath.section))" footer.label.textColor = item?.displayColor - footer.backgroundColor = .lightGray() + footer.backgroundColor = .lightGray footer.label.font = .preferredFont(forTextStyle: UIFontTextStyleFootnote) footer.label.textAlignment = .center return footer @@ -140,7 +140,7 @@ class FetchedCollectionViewController: UICollectionViewController { } func deleteSelected() { - let indexPaths = collectionView!.indexPathsForSelectedItems() + let indexPaths = collectionView!.indexPathsForSelectedItems frc.deleteThingsAtIndexPaths(indexPaths) stack.saveAndWait() fetchData() @@ -148,21 +148,21 @@ class FetchedCollectionViewController: UICollectionViewController { } func changeNameSelected() { - let indexPaths = collectionView!.indexPathsForSelectedItems() + let indexPaths = collectionView!.indexPathsForSelectedItems frc.changeThingNamesAtIndexPaths(indexPaths) stack.saveAndWait() fetchData() } func changeColorSelected() { - let indexPaths = collectionView!.indexPathsForSelectedItems() + let indexPaths = collectionView!.indexPathsForSelectedItems frc.changeThingColorsAtIndexPaths(indexPaths) stack.saveAndWait() fetchData() } func changeAllSelected() { - let indexPaths = collectionView!.indexPathsForSelectedItems() + let indexPaths = collectionView!.indexPathsForSelectedItems frc.changeThingsAtIndexPaths(indexPaths) stack.saveAndWait() fetchData() diff --git a/Example/Sources/MixedCollectionViewController.swift b/Example/Sources/MixedCollectionViewController.swift index 1b1f1a8..b2d9769 100644 --- a/Example/Sources/MixedCollectionViewController.swift +++ b/Example/Sources/MixedCollectionViewController.swift @@ -81,8 +81,8 @@ final class MixedCollectionViewController: UICollectionViewController, UICollect // 3. create supplementary view factory let headerFactory = TitledSupplementaryViewFactory { (header, item: MixedItem?, kind, collectionView, indexPath) -> TitledSupplementaryView in header.label.text = "Section \(indexPath.section)" - header.backgroundColor = .darkGray() - header.label.textColor = .white() + header.backgroundColor = .darkGray + header.label.textColor = .white return header } diff --git a/Tests/FetchedResultsDelegateTests.swift b/Tests/FetchedResultsDelegateTests.swift index 7f2f87e..7f6c769 100644 --- a/Tests/FetchedResultsDelegateTests.swift +++ b/Tests/FetchedResultsDelegateTests.swift @@ -121,7 +121,7 @@ final class FetchedResultsDelegateTests: TestCase { _ = try? frc.performFetch() // THEN: the table view reports the expected state - XCTAssertEqual(collectionView.numberOfSections(), 3) + XCTAssertEqual(collectionView.numberOfSections, 3) XCTAssertEqual(collectionView.numberOfItems(inSection: 0), blueThings.count) XCTAssertEqual(collectionView.numberOfItems(inSection: 1), greenThings.count) @@ -141,7 +141,7 @@ final class FetchedResultsDelegateTests: TestCase { _ = try? frc.performFetch() // THEN: the table view reports the expected state - XCTAssertEqual(collectionView.numberOfSections(), 2) + XCTAssertEqual(collectionView.numberOfSections, 2) XCTAssertEqual(collectionView.numberOfItems(inSection: 0), 2) XCTAssertEqual(collectionView.numberOfItems(inSection: 1), 7) diff --git a/Tests/TestHelpers.swift b/Tests/TestHelpers.swift index 9680c74..a0cd052 100644 --- a/Tests/TestHelpers.swift +++ b/Tests/TestHelpers.swift @@ -51,7 +51,7 @@ func generateThings(_ context: NSManagedObjectContext, color: Color) -> [Thing] all.append(thing) } - all.sort(isOrderedBefore: { (t1, t2) -> Bool in + all.sort(by: { (t1, t2) -> Bool in return t1.name <= t2.name }) return all diff --git a/Tests/TitledSupplementaryViewTests.swift b/Tests/TitledSupplementaryViewTests.swift index dafcdde..2dcb922 100644 --- a/Tests/TitledSupplementaryViewTests.swift +++ b/Tests/TitledSupplementaryViewTests.swift @@ -64,7 +64,7 @@ final class TitledSupplementaryViewTests: XCTestCase { func test_thatView_preparesForReuse_ForAttributedText() { let view = TitledSupplementaryView(frame: CGRect(x: 0, y: 0, width: 320, height: 100)) view.layoutIfNeeded() - view.label.attributedText = AttributedString(string:"title text") + view.label.attributedText = NSAttributedString(string:"title text") XCTAssertNotNil(view.label.attributedText) @@ -76,9 +76,9 @@ final class TitledSupplementaryViewTests: XCTestCase { func test_thatView_setsBackgoundColor() { let view = TitledSupplementaryView(frame: CGRect(x: 0, y: 0, width: 320, height: 100)) view.layoutIfNeeded() - view.backgroundColor = .red() + view.backgroundColor = .red XCTAssertEqual(view.label.backgroundColor, view.backgroundColor) - XCTAssertEqual(view.label.backgroundColor, .red()) + XCTAssertEqual(view.label.backgroundColor, .red) } } From 96c97c5f3202543e6705aefb8e7a2011c87e4f61 Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Tue, 16 Aug 2016 09:34:14 -0700 Subject: [PATCH 09/24] update for Xcode8 beta6, #54 --- Example/Sources/AppDelegate.swift | 7 ++++--- Example/Sources/Extensions.swift | 10 +++++----- Example/Sources/FancyCollectionViewCell.xib | 11 +++++------ .../FetchedCollectionViewController.swift | 2 +- .../Sources/MixedCollectionViewController.swift | 2 +- Source/BridgedFetchedResultsDelegate.swift | 4 ++-- Source/DataSourceProvider.swift | 9 +++++---- Source/FetchedResultsDelegate.swift | 16 ++++++++-------- Source/TitledSupplementaryView.swift | 2 +- Source/TitledSupplementaryViewFactory.swift | 4 ++-- Source/ViewFactory.swift | 4 ++-- Tests/BridgedFetchedResultsDelegateTests.swift | 8 ++++---- Tests/TitledSupplementaryViewTests.swift | 4 ++-- 13 files changed, 42 insertions(+), 41 deletions(-) diff --git a/Example/Sources/AppDelegate.swift b/Example/Sources/AppDelegate.swift index e557929..667374d 100644 --- a/Example/Sources/AppDelegate.swift +++ b/Example/Sources/AppDelegate.swift @@ -22,10 +22,11 @@ import UIKit class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions options: [NSObject: AnyObject]?) -> Bool { + + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { return true } - + } diff --git a/Example/Sources/Extensions.swift b/Example/Sources/Extensions.swift index d41f482..6e630ee 100644 --- a/Example/Sources/Extensions.swift +++ b/Example/Sources/Extensions.swift @@ -26,11 +26,11 @@ import JSQDataSourcesKit extension UIAlertController { class func showActionAlert(_ presenter: UIViewController, - addNewAction: () -> Void, - deleteAction: () -> Void, - changeNameAction: () -> Void, - changeColorAction: () -> Void, - changeAllAction: () -> Void) { + addNewAction: @escaping () -> Void, + deleteAction: @escaping () -> Void, + changeNameAction: @escaping () -> Void, + changeColorAction: @escaping () -> Void, + changeAllAction: @escaping () -> Void) { let alert = UIAlertController(title: "You must select items first", message: nil, preferredStyle: .actionSheet) alert.addAction(UIAlertAction(title: "Add new", style: .default) { action in diff --git a/Example/Sources/FancyCollectionViewCell.xib b/Example/Sources/FancyCollectionViewCell.xib index b52e6b5..8976720 100644 --- a/Example/Sources/FancyCollectionViewCell.xib +++ b/Example/Sources/FancyCollectionViewCell.xib @@ -1,8 +1,9 @@ - + - + + @@ -15,15 +16,13 @@ - - + diff --git a/Example/Sources/FetchedCollectionViewController.swift b/Example/Sources/FetchedCollectionViewController.swift index 7d2580f..dabe7c0 100644 --- a/Example/Sources/FetchedCollectionViewController.swift +++ b/Example/Sources/FetchedCollectionViewController.swift @@ -68,7 +68,7 @@ class FetchedCollectionViewController: UICollectionViewController { footer.label.text = "\(item!.colorName) footer (\(indexPath.section))" footer.label.textColor = item?.displayColor footer.backgroundColor = .lightGray - footer.label.font = .preferredFont(forTextStyle: UIFontTextStyleFootnote) + footer.label.font = .preferredFont(forTextStyle: .footnote) footer.label.textAlignment = .center return footer } diff --git a/Example/Sources/MixedCollectionViewController.swift b/Example/Sources/MixedCollectionViewController.swift index b2d9769..5945f3a 100644 --- a/Example/Sources/MixedCollectionViewController.swift +++ b/Example/Sources/MixedCollectionViewController.swift @@ -22,7 +22,7 @@ import JSQDataSourcesKit struct FancyViewModel { let text: String = "Fancy Text" - let cornerRadius: CGFloat = 5 + let cornerRadius: CGFloat = 8 } enum MixedItem { diff --git a/Source/BridgedFetchedResultsDelegate.swift b/Source/BridgedFetchedResultsDelegate.swift index 926b42b..f54737e 100644 --- a/Source/BridgedFetchedResultsDelegate.swift +++ b/Source/BridgedFetchedResultsDelegate.swift @@ -28,7 +28,7 @@ import Foundation typealias WillChangeContentHandler = (NSFetchedResultsController) -> Void typealias DidChangeSectionHandler = (NSFetchedResultsController, NSFetchedResultsSectionInfo, Int, NSFetchedResultsChangeType) -> Void - typealias DidChangeObjectHandler = (NSFetchedResultsController, AnyObject, IndexPath?, NSFetchedResultsChangeType, IndexPath?) -> Void + typealias DidChangeObjectHandler = (NSFetchedResultsController, Any, IndexPath?, NSFetchedResultsChangeType, IndexPath?) -> Void typealias DidChangeContentHandler = (NSFetchedResultsController) -> Void let willChangeContent: WillChangeContentHandler @@ -63,7 +63,7 @@ extension BridgedFetchedResultsDelegate: NSFetchedResultsControllerDelegate { } @objc func controller(_ controller: NSFetchedResultsController, - didChange anObject: AnyObject, + didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { diff --git a/Source/DataSourceProvider.swift b/Source/DataSourceProvider.swift index c996181..1622d60 100644 --- a/Source/DataSourceProvider.swift +++ b/Source/DataSourceProvider.swift @@ -20,9 +20,10 @@ import Foundation import UIKit /// A `DataSourceProvider` is responsible for providing a data source object for a table view or collection view. -public final class DataSourceProvider { +public final class DataSourceProvider +where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSource.Item { // MARK: Properties @@ -35,7 +36,7 @@ CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSource.Ite /// The supplementary view factory. public let supplementaryFactory: SupplementaryFactory - private var bridgedDataSource: BridgedDataSource? + fileprivate var bridgedDataSource: BridgedDataSource? // MARK: Initialization diff --git a/Source/FetchedResultsDelegate.swift b/Source/FetchedResultsDelegate.swift index 79c3dec..2ff46ce 100644 --- a/Source/FetchedResultsDelegate.swift +++ b/Source/FetchedResultsDelegate.swift @@ -41,11 +41,11 @@ public final class FetchedResultsDelegateProvider: ReusableViewFactoryProtocol - returns: The configured `TitledSupplementaryView` instance. */ - public typealias ConfigurationHandler = (view: TitledSupplementaryView, item: Item?, type: ReusableViewType, collectionView: UICollectionView, indexPath: IndexPath) -> TitledSupplementaryView + public typealias ConfigurationHandler = (TitledSupplementaryView, Item?, ReusableViewType, UICollectionView, IndexPath) -> TitledSupplementaryView // MARK: Private Properties @@ -75,6 +75,6 @@ public struct TitledSupplementaryViewFactory : ReusableViewFactoryProtocol type: ReusableViewType, parentView: UICollectionView, indexPath: IndexPath) -> TitledSupplementaryView { - return configurator(view: view, item: item, type: type, collectionView: parentView, indexPath: indexPath) + return configurator(view, item, type, parentView, indexPath) } } diff --git a/Source/ViewFactory.swift b/Source/ViewFactory.swift index 560de0d..ed0ab12 100644 --- a/Source/ViewFactory.swift +++ b/Source/ViewFactory.swift @@ -290,7 +290,7 @@ public struct ViewFactory: ReusableViewFactory - returns: The configured cell. */ - public typealias ViewConfigurator = (cell: Cell, item: Item?, type: ReusableViewType, parentView: Cell.ParentView, indexPath: IndexPath) -> Cell + public typealias ViewConfigurator = (Cell, Item?, ReusableViewType, Cell.ParentView, IndexPath) -> Cell // MARK: Properties @@ -335,6 +335,6 @@ public struct ViewFactory: ReusableViewFactory /// :nodoc: public func configure(view: Cell, item: Item?, type: ReusableViewType, parentView: Cell.ParentView, indexPath: IndexPath) -> Cell { assert(self.type == type) - return viewConfigurator(cell: view, item: item, type: type, parentView: parentView, indexPath: indexPath) + return viewConfigurator(view, item, type, parentView, indexPath) } } diff --git a/Tests/BridgedFetchedResultsDelegateTests.swift b/Tests/BridgedFetchedResultsDelegateTests.swift index 014554c..12c9914 100644 --- a/Tests/BridgedFetchedResultsDelegateTests.swift +++ b/Tests/BridgedFetchedResultsDelegateTests.swift @@ -49,10 +49,10 @@ final class BridgedFetchedResultsDelegateTests: XCTestCase { let controller = NSFetchedResultsController() class FakeSectionInfo: NSObject, NSFetchedResultsSectionInfo { - @objc var numberOfObjects: Int = 0 - @objc var objects: [AnyObject]? - @objc var name: String = "name" - @objc var indexTitle: String? + @objc public var numberOfObjects: Int = 0 + @objc public var objects: [Any]? + @objc public var name: String = "name" + @objc public var indexTitle: String? } // WHEN: we call the NSFetchedResultsControllerDelegate methods diff --git a/Tests/TitledSupplementaryViewTests.swift b/Tests/TitledSupplementaryViewTests.swift index 2dcb922..996bb53 100644 --- a/Tests/TitledSupplementaryViewTests.swift +++ b/Tests/TitledSupplementaryViewTests.swift @@ -27,7 +27,7 @@ final class TitledSupplementaryViewTests: XCTestCase { func test_thatView_initializesWithFrame() { let identifier = TitledSupplementaryView.identifier - XCTAssertEqual(identifier, String(TitledSupplementaryView.self)) + XCTAssertEqual(identifier, String(describing: TitledSupplementaryView.self)) let view = TitledSupplementaryView(frame: CGRect(x: 0, y: 0, width: 320, height: 100)) view.layoutIfNeeded() @@ -39,7 +39,7 @@ final class TitledSupplementaryViewTests: XCTestCase { func test_thatView_adjustsLabelFrameForInsets() { let identifier = TitledSupplementaryView.identifier - XCTAssertEqual(identifier, String(TitledSupplementaryView.self)) + XCTAssertEqual(identifier, String(describing: TitledSupplementaryView.self)) let view = TitledSupplementaryView(frame: CGRect(x: 0, y: 0, width: 320, height: 100)) view.verticalInset = 10 From 5e12e272d9b9d725282dc183039b1493107533c8 Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Wed, 7 Sep 2016 23:10:17 -0700 Subject: [PATCH 10/24] update for xcode8 GM, #54 --- Source/BridgedDataSource.swift | 3 ++- Source/BridgedFetchedResultsDelegate.swift | 8 ++++---- Source/TitledSupplementaryViewFactory.swift | 2 +- Source/ViewFactory.swift | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Source/BridgedDataSource.swift b/Source/BridgedDataSource.swift index 6960195..0a24696 100644 --- a/Source/BridgedDataSource.swift +++ b/Source/BridgedDataSource.swift @@ -47,7 +47,8 @@ internal typealias TableTitleForFooterInSectionHandler = (Int) -> String? var tableTitleForHeaderInSection: TableTitleForHeaderInSectionHandler? var tableTitleForFooterInSection: TableTitleForFooterInSectionHandler? - init(numberOfSections: NumberOfSectionsHandler, numberOfItemsInSection: NumberOfItemsInSectionHandler) { + init(numberOfSections: @escaping NumberOfSectionsHandler, + numberOfItemsInSection: @escaping NumberOfItemsInSectionHandler) { self.numberOfSections = numberOfSections self.numberOfItemsInSection = numberOfItemsInSection } diff --git a/Source/BridgedFetchedResultsDelegate.swift b/Source/BridgedFetchedResultsDelegate.swift index f54737e..a416773 100644 --- a/Source/BridgedFetchedResultsDelegate.swift +++ b/Source/BridgedFetchedResultsDelegate.swift @@ -36,10 +36,10 @@ import Foundation let didChangeObject: DidChangeObjectHandler let didChangeContent: DidChangeContentHandler - init(willChangeContent: WillChangeContentHandler, - didChangeSection: DidChangeSectionHandler, - didChangeObject: DidChangeObjectHandler, - didChangeContent: DidChangeContentHandler) { + init(willChangeContent: @escaping WillChangeContentHandler, + didChangeSection: @escaping DidChangeSectionHandler, + didChangeObject: @escaping DidChangeObjectHandler, + didChangeContent: @escaping DidChangeContentHandler) { self.willChangeContent = willChangeContent self.didChangeSection = didChangeSection diff --git a/Source/TitledSupplementaryViewFactory.swift b/Source/TitledSupplementaryViewFactory.swift index ab343ca..aa5c85a 100644 --- a/Source/TitledSupplementaryViewFactory.swift +++ b/Source/TitledSupplementaryViewFactory.swift @@ -57,7 +57,7 @@ public struct TitledSupplementaryViewFactory : ReusableViewFactoryProtocol - returns: A new `TitledSupplementaryView` instance. */ - public init(configurator: ConfigurationHandler) { + public init(configurator: @escaping ConfigurationHandler) { self.configurator = configurator } diff --git a/Source/ViewFactory.swift b/Source/ViewFactory.swift index ed0ab12..eddb4fb 100644 --- a/Source/ViewFactory.swift +++ b/Source/ViewFactory.swift @@ -321,7 +321,7 @@ public struct ViewFactory: ReusableViewFactory - returns: A new `CellFactory` instance. */ - public init(reuseIdentifier: String, type: ReusableViewType = .cell, viewConfigurator: ViewConfigurator) { + public init(reuseIdentifier: String, type: ReusableViewType = .cell, viewConfigurator: @escaping ViewConfigurator) { self.reuseIdentifier = reuseIdentifier self.type = type self.viewConfigurator = viewConfigurator From a51bfe636b34ae50a310b73a02af5a622f4efeff Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Thu, 8 Sep 2016 23:08:11 -0700 Subject: [PATCH 11/24] name closure params --- Source/TitledSupplementaryViewFactory.swift | 2 +- Source/ViewFactory.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/TitledSupplementaryViewFactory.swift b/Source/TitledSupplementaryViewFactory.swift index aa5c85a..4dc59c4 100644 --- a/Source/TitledSupplementaryViewFactory.swift +++ b/Source/TitledSupplementaryViewFactory.swift @@ -40,7 +40,7 @@ public struct TitledSupplementaryViewFactory : ReusableViewFactoryProtocol - returns: The configured `TitledSupplementaryView` instance. */ - public typealias ConfigurationHandler = (TitledSupplementaryView, Item?, ReusableViewType, UICollectionView, IndexPath) -> TitledSupplementaryView + public typealias ConfigurationHandler = (_ view: TitledSupplementaryView, _ item: Item?, _ type: ReusableViewType, _ collectionView: UICollectionView, _ indexPath: IndexPath) -> TitledSupplementaryView // MARK: Private Properties diff --git a/Source/ViewFactory.swift b/Source/ViewFactory.swift index eddb4fb..026c3a8 100644 --- a/Source/ViewFactory.swift +++ b/Source/ViewFactory.swift @@ -290,7 +290,7 @@ public struct ViewFactory: ReusableViewFactory - returns: The configured cell. */ - public typealias ViewConfigurator = (Cell, Item?, ReusableViewType, Cell.ParentView, IndexPath) -> Cell + public typealias ViewConfigurator = (_ cell: Cell, _ item: Item?, _ type: ReusableViewType, _ parentView: Cell.ParentView, _ indexPath: IndexPath) -> Cell // MARK: Properties From 386e5dcf564ffc59329dbb2d6a88c6b0bc989532 Mon Sep 17 00:00:00 2001 From: Panos Date: Wed, 14 Sep 2016 09:32:18 +0100 Subject: [PATCH 12/24] edit functionality support for UITableViewDataSource --- Example/Sources/TableViewController.swift | 18 +++++- JSQDataSourcesKit.xcodeproj/project.pbxproj | 4 ++ Source/BridgedDataSource.swift | 19 ++++++- Source/BridgedFetchedResultsDelegate.swift | 8 +-- Source/DataSource.swift | 14 ++++- Source/DataSourceProvider.swift | 19 ++++++- Source/OptionalDataSource.swift | 62 +++++++++++++++++++++ Source/TitledSupplementaryViewFactory.swift | 2 +- Source/ViewFactory.swift | 2 +- Tests/DataSourceTests.swift | 17 +++++- 10 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 Source/OptionalDataSource.swift diff --git a/Example/Sources/TableViewController.swift b/Example/Sources/TableViewController.swift index 285271e..28dc5ed 100644 --- a/Example/Sources/TableViewController.swift +++ b/Example/Sources/TableViewController.swift @@ -42,11 +42,23 @@ final class TableViewController: UITableViewController { cell.accessibilityIdentifier = "\(indexPath.section), \(indexPath.row)" return cell } + + //3. Optional - create if neccessary a datasourceEditingController to enable the editing functionality on the tableView + + let tableEditingController = DataSourceEditingController(canEditConfigurator: { (indexPath, tableView) -> Bool in + return indexPath.row % 2 == 0 + }) { (tableView, editingStyle, indexPath) in + if editingStyle == .delete{ + if let _ = self.dataSourceProvider?.dataSource.remove(at: indexPath){ + tableView.deleteRows(at: [indexPath], with: .automatic) + } + } + } - // 3. create data source provider - dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory) + // 4. create data source provider + dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory,dataSourceTableEditing:tableEditingController) - // 4. set data source + // 5. set data source tableView.dataSource = dataSourceProvider?.tableViewDataSource } diff --git a/JSQDataSourcesKit.xcodeproj/project.pbxproj b/JSQDataSourcesKit.xcodeproj/project.pbxproj index c6b1f52..5ae2e86 100644 --- a/JSQDataSourcesKit.xcodeproj/project.pbxproj +++ b/JSQDataSourcesKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 1DD7AC5D1D86C4BC00B676A6 /* OptionalDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD7AC5C1D86C4BC00B676A6 /* OptionalDataSource.swift */; }; 881A92DB1CB881550080BC5C /* FetchedResultsDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DCAD2C1CB87CB400C018AF /* FetchedResultsDelegate.swift */; }; 881A92DD1CB881550080BC5C /* JSQDataSourcesKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 88DCAD2F1CB87CB400C018AF /* JSQDataSourcesKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 881A92E11CB881550080BC5C /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DCAD331CB87CB400C018AF /* Section.swift */; }; @@ -84,6 +85,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 1DD7AC5C1D86C4BC00B676A6 /* OptionalDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionalDataSource.swift; sourceTree = ""; }; 881A92CC1CB881270080BC5C /* JSQDataSourcesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JSQDataSourcesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 882CA4531D1D7D48006112B9 /* BridgedFetchedResultsDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BridgedFetchedResultsDelegate.swift; sourceTree = ""; }; 882CA4571D1D82E1006112B9 /* TestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestCase.swift; sourceTree = ""; }; @@ -178,6 +180,7 @@ 88DCAD2C1CB87CB400C018AF /* FetchedResultsDelegate.swift */, 88DCAD2D1CB87CB400C018AF /* Info.plist */, 88DCAD2F1CB87CB400C018AF /* JSQDataSourcesKit.h */, + 1DD7AC5C1D86C4BC00B676A6 /* OptionalDataSource.swift */, 88DCAD331CB87CB400C018AF /* Section.swift */, 88DCAD351CB87CB400C018AF /* TitledSupplementaryView.swift */, 88DCAD371CB87CB400C018AF /* TitledSupplementaryViewFactory.swift */, @@ -403,6 +406,7 @@ 88DCAD761CB87CC000C018AF /* TitledSupplementaryView.swift in Sources */, 88DCAD741CB87CC000C018AF /* Section.swift in Sources */, 88B80CD81CBBF62A00EDF9D5 /* DataSourceProvider.swift in Sources */, + 1DD7AC5D1D86C4BC00B676A6 /* OptionalDataSource.swift in Sources */, 888799491D0E2D1700BBCCBC /* DataSource.swift in Sources */, 88DCAD781CB87CC000C018AF /* TitledSupplementaryViewFactory.swift in Sources */, ); diff --git a/Source/BridgedDataSource.swift b/Source/BridgedDataSource.swift index 6960195..2790b81 100644 --- a/Source/BridgedDataSource.swift +++ b/Source/BridgedDataSource.swift @@ -30,6 +30,9 @@ internal typealias TableCellForRowAtIndexPathHandler = (UITableView, IndexPath) internal typealias TableTitleForHeaderInSectionHandler = (Int) -> String? internal typealias TableTitleForFooterInSectionHandler = (Int) -> String? +internal typealias TableCanEditRowAtIndexPathHandler = (UITableView, IndexPath) -> Bool +internal typealias TableCommitEditingStyleForRowAtIndexPathHandler = (UITableView , UITableViewCellEditingStyle, IndexPath)->Void + /* This class is responsible for implementing the `UICollectionViewDataSource` and `UITableViewDataSource` protocols. @@ -46,8 +49,11 @@ internal typealias TableTitleForFooterInSectionHandler = (Int) -> String? var tableCellForRowAtIndexPath: TableCellForRowAtIndexPathHandler? var tableTitleForHeaderInSection: TableTitleForHeaderInSectionHandler? var tableTitleForFooterInSection: TableTitleForFooterInSectionHandler? + + var tableCanEditRowAtIndexPath:TableCanEditRowAtIndexPathHandler? + var tableCommitEditingStyleForRowAtIndexPath:TableCommitEditingStyleForRowAtIndexPathHandler? - init(numberOfSections: NumberOfSectionsHandler, numberOfItemsInSection: NumberOfItemsInSectionHandler) { + init(numberOfSections: @escaping NumberOfSectionsHandler, numberOfItemsInSection: @escaping NumberOfItemsInSectionHandler) { self.numberOfSections = numberOfSections self.numberOfItemsInSection = numberOfItemsInSection } @@ -102,4 +108,15 @@ extension BridgedDataSource: UITableViewDataSource { } return nil } + + @objc func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + if let closure = tableCanEditRowAtIndexPath{ + return closure(tableView,indexPath) + } + return false + } + + @objc func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { + tableCommitEditingStyleForRowAtIndexPath?(tableView,editingStyle,indexPath) + } } diff --git a/Source/BridgedFetchedResultsDelegate.swift b/Source/BridgedFetchedResultsDelegate.swift index f54737e..c40fe7d 100644 --- a/Source/BridgedFetchedResultsDelegate.swift +++ b/Source/BridgedFetchedResultsDelegate.swift @@ -36,10 +36,10 @@ import Foundation let didChangeObject: DidChangeObjectHandler let didChangeContent: DidChangeContentHandler - init(willChangeContent: WillChangeContentHandler, - didChangeSection: DidChangeSectionHandler, - didChangeObject: DidChangeObjectHandler, - didChangeContent: DidChangeContentHandler) { + init(willChangeContent: @escaping WillChangeContentHandler, + didChangeSection: @escaping DidChangeSectionHandler, + didChangeObject: @escaping DidChangeObjectHandler, + didChangeContent: @escaping DidChangeContentHandler) { self.willChangeContent = willChangeContent self.didChangeSection = didChangeSection diff --git a/Source/DataSource.swift b/Source/DataSource.swift index 8233789..b35a46b 100644 --- a/Source/DataSource.swift +++ b/Source/DataSource.swift @@ -159,7 +159,19 @@ public struct DataSource: DataSourceProtocol { guard section < sections.count else { return nil } return sections[section].footerTitle } - + + /// Removes an Item at a specific `IndexPath` + /// + /// - parameter indexPath: The index path specifying the location of the cell + /// + /// - returns: The item specified by indexPath, or `nil` + + @discardableResult + public mutating func remove(at indexPath:IndexPath)->S.Item?{ + guard indexPath.section <= numberOfSections() else {return nil} + guard indexPath.row <= numberOfItems(inSection: indexPath.section) else {return nil} + return sections[indexPath.section].items.remove(at: indexPath.row) + } // MARK: Subscripts diff --git a/Source/DataSourceProvider.swift b/Source/DataSourceProvider.swift index 1622d60..a484e18 100644 --- a/Source/DataSourceProvider.swift +++ b/Source/DataSourceProvider.swift @@ -38,7 +38,9 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour fileprivate var bridgedDataSource: BridgedDataSource? - + //The data source that provides the editing functionality on the tableView + public var dataSourceTableEditing:DataSourceTableEditingProtocol? + // MARK: Initialization /** @@ -47,6 +49,8 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour - parameter dataSource: The data source. - parameter cellFactory: The cell factory. - parameter supplementaryFactory: The supplementary view factory. + - parameter dataSourceTableEditing : The datasource that will enable the tableView only + to edit it's cells - returns: A new `DataSourceProvider` instance. @@ -54,14 +58,14 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour the generic constraints for Swift. You can simply pass the same `cellFactory` here. The parameter will be ignored. The same applies to collection views that do not have supplementary views. Again, the parameter will be ignored. */ - public init(dataSource: DataSource, cellFactory: CellFactory, supplementaryFactory: SupplementaryFactory) { + public init(dataSource: DataSource, cellFactory: CellFactory, supplementaryFactory: SupplementaryFactory,dataSourceTableEditing:DataSourceTableEditingProtocol? = nil) { self.dataSource = dataSource self.cellFactory = cellFactory self.supplementaryFactory = supplementaryFactory + self.dataSourceTableEditing = dataSourceTableEditing } } - public extension DataSourceProvider where CellFactory.View: UITableViewCell { // MARK: UITableViewDataSource @@ -95,6 +99,15 @@ public extension DataSourceProvider where CellFactory.View: UITableViewCell { dataSource.tableTitleForFooterInSection = { [unowned self] (section) -> String? in return self.dataSource.footerTitle(inSection: section) } + + dataSource.tableCanEditRowAtIndexPath = { [unowned self] (tableView, indexPath) -> Bool in + guard let editDataSource = self.dataSourceTableEditing else {return false} + return editDataSource.configureCanEditRowAt(indexPath: indexPath, in: tableView) + } + + dataSource.tableCommitEditingStyleForRowAtIndexPath = {[unowned self] (tableView, editingStyle,indexPath) in + self.dataSourceTableEditing?.configureCommitEditStyleForRow(in: tableView, editingStyle: editingStyle, at: indexPath) + } return dataSource } diff --git a/Source/OptionalDataSource.swift b/Source/OptionalDataSource.swift new file mode 100644 index 0000000..3c83adb --- /dev/null +++ b/Source/OptionalDataSource.swift @@ -0,0 +1,62 @@ +// +// DataSourceEditing.swift +// JSQDataSourcesKit +// +// Created by Panagiotis Sartzetakis on 12/09/2016. +// Copyright © 2016 Hexed Bits. All rights reserved. +// + +import Foundation +import UIKit + + +public protocol DataSourceTableEditingProtocol{ + + //MARK: Methods + + /// Returns a `Bool` which indicates if the cell will be available for editing or not + /// + /// - parameter indexPath: The index path specifying the location of the cell. + /// - parameter tableView: The table view requesting this information. + /// + /// - returns: A `Bool` which indicates if the cell will be available for editing or not + + func configureCanEditRowAt(indexPath:IndexPath,in tableView:UITableView)->Bool + + + /// Commit any neccessary action in respect of the `editingStyle` on the current `indexPath` + /// + /// - parameter tableView: The table view requesting this information. + /// - parameter editingStyle: The editingStyle that requested on the current `indexPath` (for example `.delete`) + /// - parameter indexPath: The index path specifying the location of the cell. + + func configureCommitEditStyleForRow(in tableView:UITableView,editingStyle:UITableViewCellEditingStyle,at indexPath:IndexPath) + +} + +public struct DataSourceEditingController:DataSourceTableEditingProtocol{ + + public typealias CanEditRowConfigurator = (IndexPath,UITableView)->Bool + public typealias CommitEditingStyleConfigurator = (UITableView,UITableViewCellEditingStyle,IndexPath)->Void + + public let canEditConfigurator:CanEditRowConfigurator + public let commitEditingStyle:CommitEditingStyleConfigurator + + public init(canEditConfigurator:@escaping CanEditRowConfigurator, + commitEditingStyle:@escaping CommitEditingStyleConfigurator){ + + self.canEditConfigurator = canEditConfigurator + self.commitEditingStyle = commitEditingStyle + } + + + public func configureCanEditRowAt(indexPath: IndexPath, in tableView: UITableView) -> Bool { + return canEditConfigurator(indexPath, tableView) + } + + public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) { + return commitEditingStyle(tableView, editingStyle, indexPath) + } + + +} diff --git a/Source/TitledSupplementaryViewFactory.swift b/Source/TitledSupplementaryViewFactory.swift index ab343ca..aa5c85a 100644 --- a/Source/TitledSupplementaryViewFactory.swift +++ b/Source/TitledSupplementaryViewFactory.swift @@ -57,7 +57,7 @@ public struct TitledSupplementaryViewFactory : ReusableViewFactoryProtocol - returns: A new `TitledSupplementaryView` instance. */ - public init(configurator: ConfigurationHandler) { + public init(configurator: @escaping ConfigurationHandler) { self.configurator = configurator } diff --git a/Source/ViewFactory.swift b/Source/ViewFactory.swift index ed0ab12..eddb4fb 100644 --- a/Source/ViewFactory.swift +++ b/Source/ViewFactory.swift @@ -321,7 +321,7 @@ public struct ViewFactory: ReusableViewFactory - returns: A new `CellFactory` instance. */ - public init(reuseIdentifier: String, type: ReusableViewType = .cell, viewConfigurator: ViewConfigurator) { + public init(reuseIdentifier: String, type: ReusableViewType = .cell, viewConfigurator: @escaping ViewConfigurator) { self.reuseIdentifier = reuseIdentifier self.type = type self.viewConfigurator = viewConfigurator diff --git a/Tests/DataSourceTests.swift b/Tests/DataSourceTests.swift index f6875dd..7d9398e 100644 --- a/Tests/DataSourceTests.swift +++ b/Tests/DataSourceTests.swift @@ -201,7 +201,7 @@ final class DataSourceTests: XCTestCase { let ip = IndexPath(item: 2, section: 2) let item = dataSource[ip] - // THEN: we receive the exepected data + // THEN: we receive the expected data XCTAssertEqual(item, model) } @@ -219,4 +219,19 @@ final class DataSourceTests: XCTestCase { // THEN: the item is replaced XCTAssertEqual(dataSource[ip], item) } + + func test_thatDataSource_removesExpectedData_atIndexPath(){ + // GIVEN: a data source + let sectionA = Section(items: FakeViewModel(), FakeViewModel(), headerTitle: "Header") + let sectionB = Section(items: FakeViewModel(), FakeViewModel(), footerTitle: "Footer") + var dataSource = DataSource(sections: sectionA, sectionB) + + // WHEN: we set an item at a specific index path + let ip = IndexPath(item: 1, section: 0) + let itemToRemove = dataSource.item(atRow: ip.row, inSection: ip.section) + + // THEN: the removedItem is the expected item + let removedItem = dataSource.remove(at: ip) + XCTAssertEqual(removedItem, itemToRemove) + } } From 3e6a9ac86a53337e3f5417c8e9a8d6f9adfac86b Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Wed, 21 Sep 2016 00:04:04 +0100 Subject: [PATCH 13/24] updates to match existing coding style --- Example/Sources/TableViewController.swift | 21 ++++++----- Source/BridgedDataSource.swift | 6 +-- Source/BridgedFetchedResultsDelegate.swift | 1 - Source/DataSource.swift | 18 ++++----- Source/DataSourceProvider.swift | 11 +++--- Source/OptionalDataSource.swift | 44 +++++++++++----------- Tests/DataSourceTests.swift | 2 +- 7 files changed, 50 insertions(+), 53 deletions(-) diff --git a/Example/Sources/TableViewController.swift b/Example/Sources/TableViewController.swift index 28dc5ed..da2fda2 100644 --- a/Example/Sources/TableViewController.swift +++ b/Example/Sources/TableViewController.swift @@ -44,19 +44,20 @@ final class TableViewController: UITableViewController { } //3. Optional - create if neccessary a datasourceEditingController to enable the editing functionality on the tableView - - let tableEditingController = DataSourceEditingController(canEditConfigurator: { (indexPath, tableView) -> Bool in - return indexPath.row % 2 == 0 - }) { (tableView, editingStyle, indexPath) in - if editingStyle == .delete{ - if let _ = self.dataSourceProvider?.dataSource.remove(at: indexPath){ - tableView.deleteRows(at: [indexPath], with: .automatic) + let tableEditingController = DataSourceEditingController( + canEditConfigurator: { (indexPath, tableView) -> Bool in + return indexPath.row % 2 == 0 + }, + commitEditingStyle:{ (tableView, editingStyle, indexPath) in + if editingStyle == .delete{ + if let _ = self.dataSourceProvider?.dataSource.remove(at: indexPath){ + tableView.deleteRows(at: [indexPath], with: .automatic) + } } - } - } + }) // 4. create data source provider - dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory,dataSourceTableEditing:tableEditingController) + dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory, dataSourceTableEditing: tableEditingController) // 5. set data source tableView.dataSource = dataSourceProvider?.tableViewDataSource diff --git a/Source/BridgedDataSource.swift b/Source/BridgedDataSource.swift index e89d3bb..3e7588d 100644 --- a/Source/BridgedDataSource.swift +++ b/Source/BridgedDataSource.swift @@ -31,7 +31,7 @@ internal typealias TableTitleForHeaderInSectionHandler = (Int) -> String? internal typealias TableTitleForFooterInSectionHandler = (Int) -> String? internal typealias TableCanEditRowAtIndexPathHandler = (UITableView, IndexPath) -> Bool -internal typealias TableCommitEditingStyleForRowAtIndexPathHandler = (UITableView , UITableViewCellEditingStyle, IndexPath)->Void +internal typealias TableCommitEditingStyleForRowAtIndexPathHandler = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void /* @@ -50,8 +50,8 @@ internal typealias TableCommitEditingStyleForRowAtIndexPathHandler = (UITableVie var tableTitleForHeaderInSection: TableTitleForHeaderInSectionHandler? var tableTitleForFooterInSection: TableTitleForFooterInSectionHandler? - var tableCanEditRowAtIndexPath:TableCanEditRowAtIndexPathHandler? - var tableCommitEditingStyleForRowAtIndexPath:TableCommitEditingStyleForRowAtIndexPathHandler? + var tableCanEditRowAtIndexPath: TableCanEditRowAtIndexPathHandler? + var tableCommitEditingStyleForRowAtIndexPath: TableCommitEditingStyleForRowAtIndexPathHandler? init(numberOfSections: @escaping NumberOfSectionsHandler, numberOfItemsInSection: @escaping NumberOfItemsInSectionHandler) { diff --git a/Source/BridgedFetchedResultsDelegate.swift b/Source/BridgedFetchedResultsDelegate.swift index 2e2e9fd..a416773 100644 --- a/Source/BridgedFetchedResultsDelegate.swift +++ b/Source/BridgedFetchedResultsDelegate.swift @@ -36,7 +36,6 @@ import Foundation let didChangeObject: DidChangeObjectHandler let didChangeContent: DidChangeContentHandler - init(willChangeContent: @escaping WillChangeContentHandler, didChangeSection: @escaping DidChangeSectionHandler, didChangeObject: @escaping DidChangeObjectHandler, diff --git a/Source/DataSource.swift b/Source/DataSource.swift index b35a46b..e25e3bf 100644 --- a/Source/DataSource.swift +++ b/Source/DataSource.swift @@ -160,16 +160,16 @@ public struct DataSource: DataSourceProtocol { return sections[section].footerTitle } - /// Removes an Item at a specific `IndexPath` - /// - /// - parameter indexPath: The index path specifying the location of the cell - /// - /// - returns: The item specified by indexPath, or `nil` - + /** + Removes an Item at a specific `IndexPath` + + - parameter indexPath: The index path specifying the location of the cell + - returns: The item specified by indexPath, or `nil` + */ @discardableResult - public mutating func remove(at indexPath:IndexPath)->S.Item?{ - guard indexPath.section <= numberOfSections() else {return nil} - guard indexPath.row <= numberOfItems(inSection: indexPath.section) else {return nil} + public mutating func remove(at indexPath: IndexPath) -> S.Item? { + guard indexPath.section <= numberOfSections() else { return nil } + guard indexPath.row <= numberOfItems(inSection: indexPath.section) else { return nil } return sections[indexPath.section].items.remove(at: indexPath.row) } diff --git a/Source/DataSourceProvider.swift b/Source/DataSourceProvider.swift index 4ec7462..28b39a0 100644 --- a/Source/DataSourceProvider.swift +++ b/Source/DataSourceProvider.swift @@ -38,9 +38,8 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour fileprivate var bridgedDataSource: BridgedDataSource? - //The data source that provides the editing functionality on the tableView - public var dataSourceTableEditing:DataSourceTableEditingProtocol? + public var dataSourceTableEditing: DataSourceTableEditingProtocol? // MARK: Initialization @@ -50,7 +49,7 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour - parameter dataSource: The data source. - parameter cellFactory: The cell factory. - parameter supplementaryFactory: The supplementary view factory. - - parameter dataSourceTableEditing : The datasource that will enable the tableView only + - parameter dataSourceTableEditing: The datasource that will enable the tableView only to edit it's cells - returns: A new `DataSourceProvider` instance. @@ -59,7 +58,7 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour the generic constraints for Swift. You can simply pass the same `cellFactory` here. The parameter will be ignored. The same applies to collection views that do not have supplementary views. Again, the parameter will be ignored. */ - public init(dataSource: DataSource, cellFactory: CellFactory, supplementaryFactory: SupplementaryFactory,dataSourceTableEditing:DataSourceTableEditingProtocol? = nil) { + public init(dataSource: DataSource, cellFactory: CellFactory, supplementaryFactory: SupplementaryFactory, dataSourceTableEditing: DataSourceTableEditingProtocol? = nil) { self.dataSource = dataSource self.cellFactory = cellFactory self.supplementaryFactory = supplementaryFactory @@ -102,11 +101,11 @@ public extension DataSourceProvider where CellFactory.View: UITableViewCell { } dataSource.tableCanEditRowAtIndexPath = { [unowned self] (tableView, indexPath) -> Bool in - guard let editDataSource = self.dataSourceTableEditing else {return false} + guard let editDataSource = self.dataSourceTableEditing else { return false } return editDataSource.configureCanEditRowAt(indexPath: indexPath, in: tableView) } - dataSource.tableCommitEditingStyleForRowAtIndexPath = {[unowned self] (tableView, editingStyle,indexPath) in + dataSource.tableCommitEditingStyleForRowAtIndexPath = { [unowned self] (tableView, editingStyle,indexPath) in self.dataSourceTableEditing?.configureCommitEditStyleForRow(in: tableView, editingStyle: editingStyle, at: indexPath) } diff --git a/Source/OptionalDataSource.swift b/Source/OptionalDataSource.swift index 3c83adb..fa4ef45 100644 --- a/Source/OptionalDataSource.swift +++ b/Source/OptionalDataSource.swift @@ -9,47 +9,46 @@ import Foundation import UIKit - public protocol DataSourceTableEditingProtocol{ //MARK: Methods - /// Returns a `Bool` which indicates if the cell will be available for editing or not - /// - /// - parameter indexPath: The index path specifying the location of the cell. - /// - parameter tableView: The table view requesting this information. - /// - /// - returns: A `Bool` which indicates if the cell will be available for editing or not + /** + Returns a `Bool` which indicates if the cell will be available for editing or not - func configureCanEditRowAt(indexPath:IndexPath,in tableView:UITableView)->Bool + - parameter indexPath: The index path specifying the location of the cell. + - parameter tableView: The table view requesting this information. + - returns: A `Bool` which indicates if the cell will be available for editing or not + */ + func configureCanEditRowAt(indexPath: IndexPath, in tableView: UITableView) -> Bool - /// Commit any neccessary action in respect of the `editingStyle` on the current `indexPath` - /// - /// - parameter tableView: The table view requesting this information. - /// - parameter editingStyle: The editingStyle that requested on the current `indexPath` (for example `.delete`) - /// - parameter indexPath: The index path specifying the location of the cell. + /** + Commit any neccessary action in respect of the `editingStyle` on the current `indexPath` - func configureCommitEditStyleForRow(in tableView:UITableView,editingStyle:UITableViewCellEditingStyle,at indexPath:IndexPath) + - parameter tableView: The table view requesting this information. + - parameter editingStyle: The editingStyle that requested on the current `indexPath` (for example `.delete`) + - parameter indexPath: The index path specifying the location of the cell. + */ + func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) } -public struct DataSourceEditingController:DataSourceTableEditingProtocol{ +public struct DataSourceEditingController: DataSourceTableEditingProtocol { - public typealias CanEditRowConfigurator = (IndexPath,UITableView)->Bool - public typealias CommitEditingStyleConfigurator = (UITableView,UITableViewCellEditingStyle,IndexPath)->Void + public typealias CanEditRowConfigurator = (IndexPath, UITableView) -> Bool + public typealias CommitEditingStyleConfigurator = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void - public let canEditConfigurator:CanEditRowConfigurator - public let commitEditingStyle:CommitEditingStyleConfigurator + public let canEditConfigurator: CanEditRowConfigurator + public let commitEditingStyle: CommitEditingStyleConfigurator - public init(canEditConfigurator:@escaping CanEditRowConfigurator, - commitEditingStyle:@escaping CommitEditingStyleConfigurator){ + public init(canEditConfigurator: @escaping CanEditRowConfigurator, + commitEditingStyle: @escaping CommitEditingStyleConfigurator){ self.canEditConfigurator = canEditConfigurator self.commitEditingStyle = commitEditingStyle } - public func configureCanEditRowAt(indexPath: IndexPath, in tableView: UITableView) -> Bool { return canEditConfigurator(indexPath, tableView) } @@ -57,6 +56,5 @@ public struct DataSourceEditingController:DataSourceTableEditingProtocol{ public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) { return commitEditingStyle(tableView, editingStyle, indexPath) } - } diff --git a/Tests/DataSourceTests.swift b/Tests/DataSourceTests.swift index 7d9398e..81249f6 100644 --- a/Tests/DataSourceTests.swift +++ b/Tests/DataSourceTests.swift @@ -220,7 +220,7 @@ final class DataSourceTests: XCTestCase { XCTAssertEqual(dataSource[ip], item) } - func test_thatDataSource_removesExpectedData_atIndexPath(){ + func test_thatDataSource_removesExpectedData_atIndexPath() { // GIVEN: a data source let sectionA = Section(items: FakeViewModel(), FakeViewModel(), headerTitle: "Header") let sectionB = Section(items: FakeViewModel(), FakeViewModel(), footerTitle: "Footer") From a971fa157d66c3286589b0a3c62e3b594b379743 Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Sat, 1 Oct 2016 17:29:45 +0100 Subject: [PATCH 14/24] minor format adjustments, more tests cases added --- Source/OptionalDataSource.swift | 8 +-- Tests/DataSourceProviderTests.swift | 89 +++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/Source/OptionalDataSource.swift b/Source/OptionalDataSource.swift index fa4ef45..acaea10 100644 --- a/Source/OptionalDataSource.swift +++ b/Source/OptionalDataSource.swift @@ -9,7 +9,7 @@ import Foundation import UIKit -public protocol DataSourceTableEditingProtocol{ +public protocol DataSourceTableEditingProtocol { //MARK: Methods @@ -30,7 +30,7 @@ public protocol DataSourceTableEditingProtocol{ - parameter editingStyle: The editingStyle that requested on the current `indexPath` (for example `.delete`) - parameter indexPath: The index path specifying the location of the cell. */ - func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) + func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) -> Void } @@ -43,7 +43,7 @@ public struct DataSourceEditingController: DataSourceTableEditingProtocol { public let commitEditingStyle: CommitEditingStyleConfigurator public init(canEditConfigurator: @escaping CanEditRowConfigurator, - commitEditingStyle: @escaping CommitEditingStyleConfigurator){ + commitEditingStyle: @escaping CommitEditingStyleConfigurator) { self.canEditConfigurator = canEditConfigurator self.commitEditingStyle = commitEditingStyle @@ -53,7 +53,7 @@ public struct DataSourceEditingController: DataSourceTableEditingProtocol { return canEditConfigurator(indexPath, tableView) } - public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) { + public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) -> Void { return commitEditingStyle(tableView, editingStyle, indexPath) } diff --git a/Tests/DataSourceProviderTests.swift b/Tests/DataSourceProviderTests.swift index 2d1e861..72a8908 100644 --- a/Tests/DataSourceProviderTests.swift +++ b/Tests/DataSourceProviderTests.swift @@ -369,4 +369,93 @@ final class DataSourceProviderTests: TestCase { } } + func test_thatDataSourceProvider_forTableView_returnsExpectedData_afterRemovingRowFromTableView() { + // GIVEN: a single section with data items + let expectedModel = FakeViewModel() + let expectedIndexPath = IndexPath(row: 2, section: 0) + + let section0 = Section(items: FakeViewModel(), FakeViewModel(), expectedModel, FakeViewModel(), FakeViewModel(), + headerTitle: "Header", + footerTitle: "Footer") + let dataSource = DataSource([section0]) + + let oldItemForExpectedIndexPath = dataSource.item(atRow: expectedIndexPath.row, inSection: expectedIndexPath.section) + let oldCount = dataSource.numberOfItems(inSection: expectedIndexPath.section) + + let factoryExpectation = expectation(description: #function) + tableView.dequeueCellExpectation = expectation(description: dequeueCellExpectationName + #function) + + typealias TableCellFactory = ViewFactory + var dataSourceProvider: DataSourceProvider>, TableCellFactory, TableCellFactory>! + + + // GIVEN: a cell factory + let factory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, tableView, indexPath) -> FakeTableCell in + + XCTAssertEqual(cell.reuseIdentifier!, self.cellReuseId, "Dequeued cell should have expected identifier") + XCTAssertEqual(tableView, self.tableView, "TableView should equal the tableView for the data source") + + factoryExpectation.fulfill() + return cell + } + + //GIVEN: a data source editing controller + let tableEditingController = DataSourceEditingController( + canEditConfigurator: { (indexPath, tableView) -> Bool in + return indexPath == expectedIndexPath + }, + commitEditingStyle:{ (tableView, editingStyle, indexPath) in + if editingStyle == .delete{ + if let _ = dataSourceProvider.dataSource.remove(at: indexPath){ + tableView.deleteRows(at: [indexPath], with: .automatic) + } + } + }) + + // GIVEN: a data source provider + dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory, dataSourceTableEditing: tableEditingController) + let tableViewDataSource = dataSourceProvider.tableViewDataSource + + tableView.dataSource = tableViewDataSource + + // WHEN: we call the table view data source methods + let canEditRow = tableViewDataSource.tableView?(tableView, canEditRowAt: expectedIndexPath) + tableViewDataSource.tableView?(tableView, commit: .delete, forRowAt: expectedIndexPath) + let newItemForExpectedIndexPath = dataSourceProvider.dataSource.item(atRow: expectedIndexPath.row, inSection: expectedIndexPath.section) + let newCount = dataSourceProvider.dataSource.numberOfItems(inSection: expectedIndexPath.section) + + let numSections = tableViewDataSource.numberOfSections?(in: tableView) + let cell = tableViewDataSource.tableView(tableView, cellForRowAt: expectedIndexPath) + let header = tableViewDataSource.tableView?(tableView, titleForHeaderInSection: 0) + let footer = tableViewDataSource.tableView?(tableView, titleForFooterInSection: 0) + + // THEN: we receive the expected return values + XCTAssertNotNil(canEditRow, "canEditRow should not be nil") + XCTAssert(canEditRow!, "expectedIndexpath should be able to be removed from tableview") + + XCTAssertNotEqual(oldCount, newCount, "Number of items for \(expectedIndexPath.section) should not be equal after removing the expected row") + XCTAssertEqual(newCount, oldCount - 1, "Number of items for \(expectedIndexPath.section) should be less by one") + XCTAssertNotEqual(newItemForExpectedIndexPath, oldItemForExpectedIndexPath, "old item at row \(expectedIndexPath.row), section \(expectedIndexPath.section) shouldn't exist any more") + + XCTAssertNotNil(numSections, "Number of sections should not be nil") + XCTAssertEqual(numSections!, dataSourceProvider.dataSource.sections.count, "Data source should return expected number of sections") + + XCTAssertNotNil(cell.reuseIdentifier, "Cell reuse identifier should not be nil") + XCTAssertEqual(cell.reuseIdentifier!, cellReuseId, "Data source should return cells with the expected identifier") + + XCTAssertNotNil(header, "Header should not be nil") + XCTAssertNotNil(section0.headerTitle, "Section 0 header title should not be nil") + XCTAssertEqual(header!, section0.headerTitle!, "Data source should return expected header title") + + XCTAssertNotNil(footer, "Footer should not be nil") + XCTAssertNotNil(section0.footerTitle, "Section 0 footer title should not be nil") + XCTAssertEqual(footer!, section0.footerTitle!, "Data source should return expected footer title") + + // THEN: the tableView calls `dequeueReusableCellWithIdentifier` + // THEN: the cell factory calls its `ConfigurationHandler` + waitForExpectations(timeout: defaultTimeout, handler: { (error) -> Void in + XCTAssertNil(error, "Expectations should not error") + }) + } + } From 656d4cc16b7a5c5de865174c4bfa296d0c10f817 Mon Sep 17 00:00:00 2001 From: Jesse Squires Date: Sun, 17 Jul 2016 17:26:20 -0700 Subject: [PATCH 15/24] initial migration to swift 3.0, #54 --- Example/ExampleModel/Sources/Thing.swift | 4 ++-- Tests/TitledSupplementaryViewTests.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Example/ExampleModel/Sources/Thing.swift b/Example/ExampleModel/Sources/Thing.swift index 12ef5d9..48d5f4f 100644 --- a/Example/ExampleModel/Sources/Thing.swift +++ b/Example/ExampleModel/Sources/Thing.swift @@ -108,8 +108,8 @@ public class Thing: NSManagedObject { public class func newFetchRequest() -> NSFetchRequest { let request = NSFetchRequest(entityName: "Thing") request.sortDescriptors = [ - NSSortDescriptor(key: "colorName", ascending: true), - NSSortDescriptor(key: "name", ascending: true) + SortDescriptor(key: "colorName", ascending: true), + SortDescriptor(key: "name", ascending: true) ] return request } diff --git a/Tests/TitledSupplementaryViewTests.swift b/Tests/TitledSupplementaryViewTests.swift index 996bb53..892cde0 100644 --- a/Tests/TitledSupplementaryViewTests.swift +++ b/Tests/TitledSupplementaryViewTests.swift @@ -64,7 +64,7 @@ final class TitledSupplementaryViewTests: XCTestCase { func test_thatView_preparesForReuse_ForAttributedText() { let view = TitledSupplementaryView(frame: CGRect(x: 0, y: 0, width: 320, height: 100)) view.layoutIfNeeded() - view.label.attributedText = NSAttributedString(string:"title text") + view.label.attributedText = AttributedString(string:"title text") XCTAssertNotNil(view.label.attributedText) From 0055fd0c90d6b146edd9326f77c61844f9464fe8 Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Sat, 1 Oct 2016 18:51:50 +0100 Subject: [PATCH 16/24] rebase commit 1 --- Example/ExampleModel/Sources/Thing.swift | 4 ++-- Tests/TitledSupplementaryViewTests.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Example/ExampleModel/Sources/Thing.swift b/Example/ExampleModel/Sources/Thing.swift index 48d5f4f..12ef5d9 100644 --- a/Example/ExampleModel/Sources/Thing.swift +++ b/Example/ExampleModel/Sources/Thing.swift @@ -108,8 +108,8 @@ public class Thing: NSManagedObject { public class func newFetchRequest() -> NSFetchRequest { let request = NSFetchRequest(entityName: "Thing") request.sortDescriptors = [ - SortDescriptor(key: "colorName", ascending: true), - SortDescriptor(key: "name", ascending: true) + NSSortDescriptor(key: "colorName", ascending: true), + NSSortDescriptor(key: "name", ascending: true) ] return request } diff --git a/Tests/TitledSupplementaryViewTests.swift b/Tests/TitledSupplementaryViewTests.swift index 892cde0..996bb53 100644 --- a/Tests/TitledSupplementaryViewTests.swift +++ b/Tests/TitledSupplementaryViewTests.swift @@ -64,7 +64,7 @@ final class TitledSupplementaryViewTests: XCTestCase { func test_thatView_preparesForReuse_ForAttributedText() { let view = TitledSupplementaryView(frame: CGRect(x: 0, y: 0, width: 320, height: 100)) view.layoutIfNeeded() - view.label.attributedText = AttributedString(string:"title text") + view.label.attributedText = NSAttributedString(string:"title text") XCTAssertNotNil(view.label.attributedText) From 3a457792b2ba7cc7448519b032703d854813b67b Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Sat, 1 Oct 2016 18:54:27 +0100 Subject: [PATCH 17/24] rebase commit 2 --- Example/Sources/TableViewController.swift | 18 +++++- JSQDataSourcesKit.xcodeproj/project.pbxproj | 4 ++ Source/BridgedDataSource.swift | 17 ++++++ Source/DataSource.swift | 14 ++++- Source/DataSourceProvider.swift | 19 ++++++- Source/OptionalDataSource.swift | 62 +++++++++++++++++++++ Tests/DataSourceTests.swift | 17 +++++- 7 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 Source/OptionalDataSource.swift diff --git a/Example/Sources/TableViewController.swift b/Example/Sources/TableViewController.swift index 285271e..28dc5ed 100644 --- a/Example/Sources/TableViewController.swift +++ b/Example/Sources/TableViewController.swift @@ -42,11 +42,23 @@ final class TableViewController: UITableViewController { cell.accessibilityIdentifier = "\(indexPath.section), \(indexPath.row)" return cell } + + //3. Optional - create if neccessary a datasourceEditingController to enable the editing functionality on the tableView + + let tableEditingController = DataSourceEditingController(canEditConfigurator: { (indexPath, tableView) -> Bool in + return indexPath.row % 2 == 0 + }) { (tableView, editingStyle, indexPath) in + if editingStyle == .delete{ + if let _ = self.dataSourceProvider?.dataSource.remove(at: indexPath){ + tableView.deleteRows(at: [indexPath], with: .automatic) + } + } + } - // 3. create data source provider - dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory) + // 4. create data source provider + dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory,dataSourceTableEditing:tableEditingController) - // 4. set data source + // 5. set data source tableView.dataSource = dataSourceProvider?.tableViewDataSource } diff --git a/JSQDataSourcesKit.xcodeproj/project.pbxproj b/JSQDataSourcesKit.xcodeproj/project.pbxproj index ad95dfe..211fb82 100644 --- a/JSQDataSourcesKit.xcodeproj/project.pbxproj +++ b/JSQDataSourcesKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 1DD7AC5D1D86C4BC00B676A6 /* OptionalDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD7AC5C1D86C4BC00B676A6 /* OptionalDataSource.swift */; }; 881A92DB1CB881550080BC5C /* FetchedResultsDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DCAD2C1CB87CB400C018AF /* FetchedResultsDelegate.swift */; }; 881A92DD1CB881550080BC5C /* JSQDataSourcesKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 88DCAD2F1CB87CB400C018AF /* JSQDataSourcesKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 881A92E11CB881550080BC5C /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DCAD331CB87CB400C018AF /* Section.swift */; }; @@ -84,6 +85,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 1DD7AC5C1D86C4BC00B676A6 /* OptionalDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionalDataSource.swift; sourceTree = ""; }; 881A92CC1CB881270080BC5C /* JSQDataSourcesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JSQDataSourcesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 882CA4531D1D7D48006112B9 /* BridgedFetchedResultsDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BridgedFetchedResultsDelegate.swift; sourceTree = ""; }; 882CA4571D1D82E1006112B9 /* TestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestCase.swift; sourceTree = ""; }; @@ -178,6 +180,7 @@ 88DCAD2C1CB87CB400C018AF /* FetchedResultsDelegate.swift */, 88DCAD2D1CB87CB400C018AF /* Info.plist */, 88DCAD2F1CB87CB400C018AF /* JSQDataSourcesKit.h */, + 1DD7AC5C1D86C4BC00B676A6 /* OptionalDataSource.swift */, 88DCAD331CB87CB400C018AF /* Section.swift */, 88DCAD351CB87CB400C018AF /* TitledSupplementaryView.swift */, 88DCAD371CB87CB400C018AF /* TitledSupplementaryViewFactory.swift */, @@ -403,6 +406,7 @@ 88DCAD761CB87CC000C018AF /* TitledSupplementaryView.swift in Sources */, 88DCAD741CB87CC000C018AF /* Section.swift in Sources */, 88B80CD81CBBF62A00EDF9D5 /* DataSourceProvider.swift in Sources */, + 1DD7AC5D1D86C4BC00B676A6 /* OptionalDataSource.swift in Sources */, 888799491D0E2D1700BBCCBC /* DataSource.swift in Sources */, 88DCAD781CB87CC000C018AF /* TitledSupplementaryViewFactory.swift in Sources */, ); diff --git a/Source/BridgedDataSource.swift b/Source/BridgedDataSource.swift index 0a24696..e89d3bb 100644 --- a/Source/BridgedDataSource.swift +++ b/Source/BridgedDataSource.swift @@ -30,6 +30,9 @@ internal typealias TableCellForRowAtIndexPathHandler = (UITableView, IndexPath) internal typealias TableTitleForHeaderInSectionHandler = (Int) -> String? internal typealias TableTitleForFooterInSectionHandler = (Int) -> String? +internal typealias TableCanEditRowAtIndexPathHandler = (UITableView, IndexPath) -> Bool +internal typealias TableCommitEditingStyleForRowAtIndexPathHandler = (UITableView , UITableViewCellEditingStyle, IndexPath)->Void + /* This class is responsible for implementing the `UICollectionViewDataSource` and `UITableViewDataSource` protocols. @@ -46,6 +49,9 @@ internal typealias TableTitleForFooterInSectionHandler = (Int) -> String? var tableCellForRowAtIndexPath: TableCellForRowAtIndexPathHandler? var tableTitleForHeaderInSection: TableTitleForHeaderInSectionHandler? var tableTitleForFooterInSection: TableTitleForFooterInSectionHandler? + + var tableCanEditRowAtIndexPath:TableCanEditRowAtIndexPathHandler? + var tableCommitEditingStyleForRowAtIndexPath:TableCommitEditingStyleForRowAtIndexPathHandler? init(numberOfSections: @escaping NumberOfSectionsHandler, numberOfItemsInSection: @escaping NumberOfItemsInSectionHandler) { @@ -103,4 +109,15 @@ extension BridgedDataSource: UITableViewDataSource { } return nil } + + @objc func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + if let closure = tableCanEditRowAtIndexPath{ + return closure(tableView,indexPath) + } + return false + } + + @objc func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { + tableCommitEditingStyleForRowAtIndexPath?(tableView,editingStyle,indexPath) + } } diff --git a/Source/DataSource.swift b/Source/DataSource.swift index 8233789..b35a46b 100644 --- a/Source/DataSource.swift +++ b/Source/DataSource.swift @@ -159,7 +159,19 @@ public struct DataSource: DataSourceProtocol { guard section < sections.count else { return nil } return sections[section].footerTitle } - + + /// Removes an Item at a specific `IndexPath` + /// + /// - parameter indexPath: The index path specifying the location of the cell + /// + /// - returns: The item specified by indexPath, or `nil` + + @discardableResult + public mutating func remove(at indexPath:IndexPath)->S.Item?{ + guard indexPath.section <= numberOfSections() else {return nil} + guard indexPath.row <= numberOfItems(inSection: indexPath.section) else {return nil} + return sections[indexPath.section].items.remove(at: indexPath.row) + } // MARK: Subscripts diff --git a/Source/DataSourceProvider.swift b/Source/DataSourceProvider.swift index 1622d60..a484e18 100644 --- a/Source/DataSourceProvider.swift +++ b/Source/DataSourceProvider.swift @@ -38,7 +38,9 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour fileprivate var bridgedDataSource: BridgedDataSource? - + //The data source that provides the editing functionality on the tableView + public var dataSourceTableEditing:DataSourceTableEditingProtocol? + // MARK: Initialization /** @@ -47,6 +49,8 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour - parameter dataSource: The data source. - parameter cellFactory: The cell factory. - parameter supplementaryFactory: The supplementary view factory. + - parameter dataSourceTableEditing : The datasource that will enable the tableView only + to edit it's cells - returns: A new `DataSourceProvider` instance. @@ -54,14 +58,14 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour the generic constraints for Swift. You can simply pass the same `cellFactory` here. The parameter will be ignored. The same applies to collection views that do not have supplementary views. Again, the parameter will be ignored. */ - public init(dataSource: DataSource, cellFactory: CellFactory, supplementaryFactory: SupplementaryFactory) { + public init(dataSource: DataSource, cellFactory: CellFactory, supplementaryFactory: SupplementaryFactory,dataSourceTableEditing:DataSourceTableEditingProtocol? = nil) { self.dataSource = dataSource self.cellFactory = cellFactory self.supplementaryFactory = supplementaryFactory + self.dataSourceTableEditing = dataSourceTableEditing } } - public extension DataSourceProvider where CellFactory.View: UITableViewCell { // MARK: UITableViewDataSource @@ -95,6 +99,15 @@ public extension DataSourceProvider where CellFactory.View: UITableViewCell { dataSource.tableTitleForFooterInSection = { [unowned self] (section) -> String? in return self.dataSource.footerTitle(inSection: section) } + + dataSource.tableCanEditRowAtIndexPath = { [unowned self] (tableView, indexPath) -> Bool in + guard let editDataSource = self.dataSourceTableEditing else {return false} + return editDataSource.configureCanEditRowAt(indexPath: indexPath, in: tableView) + } + + dataSource.tableCommitEditingStyleForRowAtIndexPath = {[unowned self] (tableView, editingStyle,indexPath) in + self.dataSourceTableEditing?.configureCommitEditStyleForRow(in: tableView, editingStyle: editingStyle, at: indexPath) + } return dataSource } diff --git a/Source/OptionalDataSource.swift b/Source/OptionalDataSource.swift new file mode 100644 index 0000000..3c83adb --- /dev/null +++ b/Source/OptionalDataSource.swift @@ -0,0 +1,62 @@ +// +// DataSourceEditing.swift +// JSQDataSourcesKit +// +// Created by Panagiotis Sartzetakis on 12/09/2016. +// Copyright © 2016 Hexed Bits. All rights reserved. +// + +import Foundation +import UIKit + + +public protocol DataSourceTableEditingProtocol{ + + //MARK: Methods + + /// Returns a `Bool` which indicates if the cell will be available for editing or not + /// + /// - parameter indexPath: The index path specifying the location of the cell. + /// - parameter tableView: The table view requesting this information. + /// + /// - returns: A `Bool` which indicates if the cell will be available for editing or not + + func configureCanEditRowAt(indexPath:IndexPath,in tableView:UITableView)->Bool + + + /// Commit any neccessary action in respect of the `editingStyle` on the current `indexPath` + /// + /// - parameter tableView: The table view requesting this information. + /// - parameter editingStyle: The editingStyle that requested on the current `indexPath` (for example `.delete`) + /// - parameter indexPath: The index path specifying the location of the cell. + + func configureCommitEditStyleForRow(in tableView:UITableView,editingStyle:UITableViewCellEditingStyle,at indexPath:IndexPath) + +} + +public struct DataSourceEditingController:DataSourceTableEditingProtocol{ + + public typealias CanEditRowConfigurator = (IndexPath,UITableView)->Bool + public typealias CommitEditingStyleConfigurator = (UITableView,UITableViewCellEditingStyle,IndexPath)->Void + + public let canEditConfigurator:CanEditRowConfigurator + public let commitEditingStyle:CommitEditingStyleConfigurator + + public init(canEditConfigurator:@escaping CanEditRowConfigurator, + commitEditingStyle:@escaping CommitEditingStyleConfigurator){ + + self.canEditConfigurator = canEditConfigurator + self.commitEditingStyle = commitEditingStyle + } + + + public func configureCanEditRowAt(indexPath: IndexPath, in tableView: UITableView) -> Bool { + return canEditConfigurator(indexPath, tableView) + } + + public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) { + return commitEditingStyle(tableView, editingStyle, indexPath) + } + + +} diff --git a/Tests/DataSourceTests.swift b/Tests/DataSourceTests.swift index f6875dd..7d9398e 100644 --- a/Tests/DataSourceTests.swift +++ b/Tests/DataSourceTests.swift @@ -201,7 +201,7 @@ final class DataSourceTests: XCTestCase { let ip = IndexPath(item: 2, section: 2) let item = dataSource[ip] - // THEN: we receive the exepected data + // THEN: we receive the expected data XCTAssertEqual(item, model) } @@ -219,4 +219,19 @@ final class DataSourceTests: XCTestCase { // THEN: the item is replaced XCTAssertEqual(dataSource[ip], item) } + + func test_thatDataSource_removesExpectedData_atIndexPath(){ + // GIVEN: a data source + let sectionA = Section(items: FakeViewModel(), FakeViewModel(), headerTitle: "Header") + let sectionB = Section(items: FakeViewModel(), FakeViewModel(), footerTitle: "Footer") + var dataSource = DataSource(sections: sectionA, sectionB) + + // WHEN: we set an item at a specific index path + let ip = IndexPath(item: 1, section: 0) + let itemToRemove = dataSource.item(atRow: ip.row, inSection: ip.section) + + // THEN: the removedItem is the expected item + let removedItem = dataSource.remove(at: ip) + XCTAssertEqual(removedItem, itemToRemove) + } } From 779aeee6e89a653a4adc5894dc1aab949efb008a Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Wed, 21 Sep 2016 00:04:04 +0100 Subject: [PATCH 18/24] updates to match existing coding style --- Example/Sources/TableViewController.swift | 21 +++++------ Source/BridgedDataSource.swift | 6 ++-- Source/DataSource.swift | 18 +++++----- Source/DataSourceProvider.swift | 10 +++--- Source/OptionalDataSource.swift | 44 +++++++++++------------ Tests/DataSourceTests.swift | 2 +- 6 files changed, 50 insertions(+), 51 deletions(-) diff --git a/Example/Sources/TableViewController.swift b/Example/Sources/TableViewController.swift index 28dc5ed..da2fda2 100644 --- a/Example/Sources/TableViewController.swift +++ b/Example/Sources/TableViewController.swift @@ -44,19 +44,20 @@ final class TableViewController: UITableViewController { } //3. Optional - create if neccessary a datasourceEditingController to enable the editing functionality on the tableView - - let tableEditingController = DataSourceEditingController(canEditConfigurator: { (indexPath, tableView) -> Bool in - return indexPath.row % 2 == 0 - }) { (tableView, editingStyle, indexPath) in - if editingStyle == .delete{ - if let _ = self.dataSourceProvider?.dataSource.remove(at: indexPath){ - tableView.deleteRows(at: [indexPath], with: .automatic) + let tableEditingController = DataSourceEditingController( + canEditConfigurator: { (indexPath, tableView) -> Bool in + return indexPath.row % 2 == 0 + }, + commitEditingStyle:{ (tableView, editingStyle, indexPath) in + if editingStyle == .delete{ + if let _ = self.dataSourceProvider?.dataSource.remove(at: indexPath){ + tableView.deleteRows(at: [indexPath], with: .automatic) + } } - } - } + }) // 4. create data source provider - dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory,dataSourceTableEditing:tableEditingController) + dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory, dataSourceTableEditing: tableEditingController) // 5. set data source tableView.dataSource = dataSourceProvider?.tableViewDataSource diff --git a/Source/BridgedDataSource.swift b/Source/BridgedDataSource.swift index e89d3bb..3e7588d 100644 --- a/Source/BridgedDataSource.swift +++ b/Source/BridgedDataSource.swift @@ -31,7 +31,7 @@ internal typealias TableTitleForHeaderInSectionHandler = (Int) -> String? internal typealias TableTitleForFooterInSectionHandler = (Int) -> String? internal typealias TableCanEditRowAtIndexPathHandler = (UITableView, IndexPath) -> Bool -internal typealias TableCommitEditingStyleForRowAtIndexPathHandler = (UITableView , UITableViewCellEditingStyle, IndexPath)->Void +internal typealias TableCommitEditingStyleForRowAtIndexPathHandler = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void /* @@ -50,8 +50,8 @@ internal typealias TableCommitEditingStyleForRowAtIndexPathHandler = (UITableVie var tableTitleForHeaderInSection: TableTitleForHeaderInSectionHandler? var tableTitleForFooterInSection: TableTitleForFooterInSectionHandler? - var tableCanEditRowAtIndexPath:TableCanEditRowAtIndexPathHandler? - var tableCommitEditingStyleForRowAtIndexPath:TableCommitEditingStyleForRowAtIndexPathHandler? + var tableCanEditRowAtIndexPath: TableCanEditRowAtIndexPathHandler? + var tableCommitEditingStyleForRowAtIndexPath: TableCommitEditingStyleForRowAtIndexPathHandler? init(numberOfSections: @escaping NumberOfSectionsHandler, numberOfItemsInSection: @escaping NumberOfItemsInSectionHandler) { diff --git a/Source/DataSource.swift b/Source/DataSource.swift index b35a46b..e25e3bf 100644 --- a/Source/DataSource.swift +++ b/Source/DataSource.swift @@ -160,16 +160,16 @@ public struct DataSource: DataSourceProtocol { return sections[section].footerTitle } - /// Removes an Item at a specific `IndexPath` - /// - /// - parameter indexPath: The index path specifying the location of the cell - /// - /// - returns: The item specified by indexPath, or `nil` - + /** + Removes an Item at a specific `IndexPath` + + - parameter indexPath: The index path specifying the location of the cell + - returns: The item specified by indexPath, or `nil` + */ @discardableResult - public mutating func remove(at indexPath:IndexPath)->S.Item?{ - guard indexPath.section <= numberOfSections() else {return nil} - guard indexPath.row <= numberOfItems(inSection: indexPath.section) else {return nil} + public mutating func remove(at indexPath: IndexPath) -> S.Item? { + guard indexPath.section <= numberOfSections() else { return nil } + guard indexPath.row <= numberOfItems(inSection: indexPath.section) else { return nil } return sections[indexPath.section].items.remove(at: indexPath.row) } diff --git a/Source/DataSourceProvider.swift b/Source/DataSourceProvider.swift index a484e18..28b39a0 100644 --- a/Source/DataSourceProvider.swift +++ b/Source/DataSourceProvider.swift @@ -39,7 +39,7 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour fileprivate var bridgedDataSource: BridgedDataSource? //The data source that provides the editing functionality on the tableView - public var dataSourceTableEditing:DataSourceTableEditingProtocol? + public var dataSourceTableEditing: DataSourceTableEditingProtocol? // MARK: Initialization @@ -49,7 +49,7 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour - parameter dataSource: The data source. - parameter cellFactory: The cell factory. - parameter supplementaryFactory: The supplementary view factory. - - parameter dataSourceTableEditing : The datasource that will enable the tableView only + - parameter dataSourceTableEditing: The datasource that will enable the tableView only to edit it's cells - returns: A new `DataSourceProvider` instance. @@ -58,7 +58,7 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour the generic constraints for Swift. You can simply pass the same `cellFactory` here. The parameter will be ignored. The same applies to collection views that do not have supplementary views. Again, the parameter will be ignored. */ - public init(dataSource: DataSource, cellFactory: CellFactory, supplementaryFactory: SupplementaryFactory,dataSourceTableEditing:DataSourceTableEditingProtocol? = nil) { + public init(dataSource: DataSource, cellFactory: CellFactory, supplementaryFactory: SupplementaryFactory, dataSourceTableEditing: DataSourceTableEditingProtocol? = nil) { self.dataSource = dataSource self.cellFactory = cellFactory self.supplementaryFactory = supplementaryFactory @@ -101,11 +101,11 @@ public extension DataSourceProvider where CellFactory.View: UITableViewCell { } dataSource.tableCanEditRowAtIndexPath = { [unowned self] (tableView, indexPath) -> Bool in - guard let editDataSource = self.dataSourceTableEditing else {return false} + guard let editDataSource = self.dataSourceTableEditing else { return false } return editDataSource.configureCanEditRowAt(indexPath: indexPath, in: tableView) } - dataSource.tableCommitEditingStyleForRowAtIndexPath = {[unowned self] (tableView, editingStyle,indexPath) in + dataSource.tableCommitEditingStyleForRowAtIndexPath = { [unowned self] (tableView, editingStyle,indexPath) in self.dataSourceTableEditing?.configureCommitEditStyleForRow(in: tableView, editingStyle: editingStyle, at: indexPath) } diff --git a/Source/OptionalDataSource.swift b/Source/OptionalDataSource.swift index 3c83adb..fa4ef45 100644 --- a/Source/OptionalDataSource.swift +++ b/Source/OptionalDataSource.swift @@ -9,47 +9,46 @@ import Foundation import UIKit - public protocol DataSourceTableEditingProtocol{ //MARK: Methods - /// Returns a `Bool` which indicates if the cell will be available for editing or not - /// - /// - parameter indexPath: The index path specifying the location of the cell. - /// - parameter tableView: The table view requesting this information. - /// - /// - returns: A `Bool` which indicates if the cell will be available for editing or not + /** + Returns a `Bool` which indicates if the cell will be available for editing or not - func configureCanEditRowAt(indexPath:IndexPath,in tableView:UITableView)->Bool + - parameter indexPath: The index path specifying the location of the cell. + - parameter tableView: The table view requesting this information. + - returns: A `Bool` which indicates if the cell will be available for editing or not + */ + func configureCanEditRowAt(indexPath: IndexPath, in tableView: UITableView) -> Bool - /// Commit any neccessary action in respect of the `editingStyle` on the current `indexPath` - /// - /// - parameter tableView: The table view requesting this information. - /// - parameter editingStyle: The editingStyle that requested on the current `indexPath` (for example `.delete`) - /// - parameter indexPath: The index path specifying the location of the cell. + /** + Commit any neccessary action in respect of the `editingStyle` on the current `indexPath` - func configureCommitEditStyleForRow(in tableView:UITableView,editingStyle:UITableViewCellEditingStyle,at indexPath:IndexPath) + - parameter tableView: The table view requesting this information. + - parameter editingStyle: The editingStyle that requested on the current `indexPath` (for example `.delete`) + - parameter indexPath: The index path specifying the location of the cell. + */ + func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) } -public struct DataSourceEditingController:DataSourceTableEditingProtocol{ +public struct DataSourceEditingController: DataSourceTableEditingProtocol { - public typealias CanEditRowConfigurator = (IndexPath,UITableView)->Bool - public typealias CommitEditingStyleConfigurator = (UITableView,UITableViewCellEditingStyle,IndexPath)->Void + public typealias CanEditRowConfigurator = (IndexPath, UITableView) -> Bool + public typealias CommitEditingStyleConfigurator = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void - public let canEditConfigurator:CanEditRowConfigurator - public let commitEditingStyle:CommitEditingStyleConfigurator + public let canEditConfigurator: CanEditRowConfigurator + public let commitEditingStyle: CommitEditingStyleConfigurator - public init(canEditConfigurator:@escaping CanEditRowConfigurator, - commitEditingStyle:@escaping CommitEditingStyleConfigurator){ + public init(canEditConfigurator: @escaping CanEditRowConfigurator, + commitEditingStyle: @escaping CommitEditingStyleConfigurator){ self.canEditConfigurator = canEditConfigurator self.commitEditingStyle = commitEditingStyle } - public func configureCanEditRowAt(indexPath: IndexPath, in tableView: UITableView) -> Bool { return canEditConfigurator(indexPath, tableView) } @@ -57,6 +56,5 @@ public struct DataSourceEditingController:DataSourceTableEditingProtocol{ public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) { return commitEditingStyle(tableView, editingStyle, indexPath) } - } diff --git a/Tests/DataSourceTests.swift b/Tests/DataSourceTests.swift index 7d9398e..81249f6 100644 --- a/Tests/DataSourceTests.swift +++ b/Tests/DataSourceTests.swift @@ -220,7 +220,7 @@ final class DataSourceTests: XCTestCase { XCTAssertEqual(dataSource[ip], item) } - func test_thatDataSource_removesExpectedData_atIndexPath(){ + func test_thatDataSource_removesExpectedData_atIndexPath() { // GIVEN: a data source let sectionA = Section(items: FakeViewModel(), FakeViewModel(), headerTitle: "Header") let sectionB = Section(items: FakeViewModel(), FakeViewModel(), footerTitle: "Footer") From 3b2d28af0124a1dff2a2bb1038ee60ad2c7b8d5c Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Sat, 1 Oct 2016 17:29:45 +0100 Subject: [PATCH 19/24] minor format adjustments, more tests cases added --- Source/OptionalDataSource.swift | 8 +-- Tests/DataSourceProviderTests.swift | 89 +++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/Source/OptionalDataSource.swift b/Source/OptionalDataSource.swift index fa4ef45..acaea10 100644 --- a/Source/OptionalDataSource.swift +++ b/Source/OptionalDataSource.swift @@ -9,7 +9,7 @@ import Foundation import UIKit -public protocol DataSourceTableEditingProtocol{ +public protocol DataSourceTableEditingProtocol { //MARK: Methods @@ -30,7 +30,7 @@ public protocol DataSourceTableEditingProtocol{ - parameter editingStyle: The editingStyle that requested on the current `indexPath` (for example `.delete`) - parameter indexPath: The index path specifying the location of the cell. */ - func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) + func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) -> Void } @@ -43,7 +43,7 @@ public struct DataSourceEditingController: DataSourceTableEditingProtocol { public let commitEditingStyle: CommitEditingStyleConfigurator public init(canEditConfigurator: @escaping CanEditRowConfigurator, - commitEditingStyle: @escaping CommitEditingStyleConfigurator){ + commitEditingStyle: @escaping CommitEditingStyleConfigurator) { self.canEditConfigurator = canEditConfigurator self.commitEditingStyle = commitEditingStyle @@ -53,7 +53,7 @@ public struct DataSourceEditingController: DataSourceTableEditingProtocol { return canEditConfigurator(indexPath, tableView) } - public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) { + public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) -> Void { return commitEditingStyle(tableView, editingStyle, indexPath) } diff --git a/Tests/DataSourceProviderTests.swift b/Tests/DataSourceProviderTests.swift index 2d1e861..72a8908 100644 --- a/Tests/DataSourceProviderTests.swift +++ b/Tests/DataSourceProviderTests.swift @@ -369,4 +369,93 @@ final class DataSourceProviderTests: TestCase { } } + func test_thatDataSourceProvider_forTableView_returnsExpectedData_afterRemovingRowFromTableView() { + // GIVEN: a single section with data items + let expectedModel = FakeViewModel() + let expectedIndexPath = IndexPath(row: 2, section: 0) + + let section0 = Section(items: FakeViewModel(), FakeViewModel(), expectedModel, FakeViewModel(), FakeViewModel(), + headerTitle: "Header", + footerTitle: "Footer") + let dataSource = DataSource([section0]) + + let oldItemForExpectedIndexPath = dataSource.item(atRow: expectedIndexPath.row, inSection: expectedIndexPath.section) + let oldCount = dataSource.numberOfItems(inSection: expectedIndexPath.section) + + let factoryExpectation = expectation(description: #function) + tableView.dequeueCellExpectation = expectation(description: dequeueCellExpectationName + #function) + + typealias TableCellFactory = ViewFactory + var dataSourceProvider: DataSourceProvider>, TableCellFactory, TableCellFactory>! + + + // GIVEN: a cell factory + let factory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, tableView, indexPath) -> FakeTableCell in + + XCTAssertEqual(cell.reuseIdentifier!, self.cellReuseId, "Dequeued cell should have expected identifier") + XCTAssertEqual(tableView, self.tableView, "TableView should equal the tableView for the data source") + + factoryExpectation.fulfill() + return cell + } + + //GIVEN: a data source editing controller + let tableEditingController = DataSourceEditingController( + canEditConfigurator: { (indexPath, tableView) -> Bool in + return indexPath == expectedIndexPath + }, + commitEditingStyle:{ (tableView, editingStyle, indexPath) in + if editingStyle == .delete{ + if let _ = dataSourceProvider.dataSource.remove(at: indexPath){ + tableView.deleteRows(at: [indexPath], with: .automatic) + } + } + }) + + // GIVEN: a data source provider + dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory, dataSourceTableEditing: tableEditingController) + let tableViewDataSource = dataSourceProvider.tableViewDataSource + + tableView.dataSource = tableViewDataSource + + // WHEN: we call the table view data source methods + let canEditRow = tableViewDataSource.tableView?(tableView, canEditRowAt: expectedIndexPath) + tableViewDataSource.tableView?(tableView, commit: .delete, forRowAt: expectedIndexPath) + let newItemForExpectedIndexPath = dataSourceProvider.dataSource.item(atRow: expectedIndexPath.row, inSection: expectedIndexPath.section) + let newCount = dataSourceProvider.dataSource.numberOfItems(inSection: expectedIndexPath.section) + + let numSections = tableViewDataSource.numberOfSections?(in: tableView) + let cell = tableViewDataSource.tableView(tableView, cellForRowAt: expectedIndexPath) + let header = tableViewDataSource.tableView?(tableView, titleForHeaderInSection: 0) + let footer = tableViewDataSource.tableView?(tableView, titleForFooterInSection: 0) + + // THEN: we receive the expected return values + XCTAssertNotNil(canEditRow, "canEditRow should not be nil") + XCTAssert(canEditRow!, "expectedIndexpath should be able to be removed from tableview") + + XCTAssertNotEqual(oldCount, newCount, "Number of items for \(expectedIndexPath.section) should not be equal after removing the expected row") + XCTAssertEqual(newCount, oldCount - 1, "Number of items for \(expectedIndexPath.section) should be less by one") + XCTAssertNotEqual(newItemForExpectedIndexPath, oldItemForExpectedIndexPath, "old item at row \(expectedIndexPath.row), section \(expectedIndexPath.section) shouldn't exist any more") + + XCTAssertNotNil(numSections, "Number of sections should not be nil") + XCTAssertEqual(numSections!, dataSourceProvider.dataSource.sections.count, "Data source should return expected number of sections") + + XCTAssertNotNil(cell.reuseIdentifier, "Cell reuse identifier should not be nil") + XCTAssertEqual(cell.reuseIdentifier!, cellReuseId, "Data source should return cells with the expected identifier") + + XCTAssertNotNil(header, "Header should not be nil") + XCTAssertNotNil(section0.headerTitle, "Section 0 header title should not be nil") + XCTAssertEqual(header!, section0.headerTitle!, "Data source should return expected header title") + + XCTAssertNotNil(footer, "Footer should not be nil") + XCTAssertNotNil(section0.footerTitle, "Section 0 footer title should not be nil") + XCTAssertEqual(footer!, section0.footerTitle!, "Data source should return expected footer title") + + // THEN: the tableView calls `dequeueReusableCellWithIdentifier` + // THEN: the cell factory calls its `ConfigurationHandler` + waitForExpectations(timeout: defaultTimeout, handler: { (error) -> Void in + XCTAssertNil(error, "Expectations should not error") + }) + } + } From 3ba85802d39b1f15dcf9fd2d44290013c5180b4a Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Sat, 1 Oct 2016 19:39:41 +0100 Subject: [PATCH 20/24] redundant void removed --- Source/OptionalDataSource.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/OptionalDataSource.swift b/Source/OptionalDataSource.swift index acaea10..afc1a07 100644 --- a/Source/OptionalDataSource.swift +++ b/Source/OptionalDataSource.swift @@ -53,7 +53,7 @@ public struct DataSourceEditingController: DataSourceTableEditingProtocol { return canEditConfigurator(indexPath, tableView) } - public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) -> Void { + public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) { return commitEditingStyle(tableView, editingStyle, indexPath) } From 250783fd89a70db65f83e94d8caaeadfeb9090c1 Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Wed, 9 Nov 2016 15:08:21 +0000 Subject: [PATCH 21/24] minor updates --- Example/Sources/TableViewController.swift | 12 ++++--- Source/BridgedDataSource.swift | 12 +++---- Source/DataSource.swift | 41 +++++++++++++++++++---- Source/DataSourceProvider.swift | 22 ++++++------ Source/OptionalDataSource.swift | 31 ++--------------- Tests/DataSourceProviderTests.swift | 7 ++-- Tests/DataSourceTests.swift | 6 +++- 7 files changed, 72 insertions(+), 59 deletions(-) diff --git a/Example/Sources/TableViewController.swift b/Example/Sources/TableViewController.swift index da2fda2..ecee018 100644 --- a/Example/Sources/TableViewController.swift +++ b/Example/Sources/TableViewController.swift @@ -43,8 +43,11 @@ final class TableViewController: UITableViewController { return cell } - //3. Optional - create if neccessary a datasourceEditingController to enable the editing functionality on the tableView - let tableEditingController = DataSourceEditingController( + // 3. create data source provider + dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory) + + // 4. Optional - create if neccessary a datasourceEditingController to enable the editing functionality on the tableView + let tableDataSourceEditingController = TableDataSourceEditingController( canEditConfigurator: { (indexPath, tableView) -> Bool in return indexPath.row % 2 == 0 }, @@ -55,9 +58,8 @@ final class TableViewController: UITableViewController { } } }) - - // 4. create data source provider - dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory, dataSourceTableEditing: tableEditingController) + + dataSourceProvider?.setTableDataSourceEditingController(tableDataSourceEditingController) // 5. set data source tableView.dataSource = dataSourceProvider?.tableViewDataSource diff --git a/Source/BridgedDataSource.swift b/Source/BridgedDataSource.swift index 3e7588d..1db4549 100644 --- a/Source/BridgedDataSource.swift +++ b/Source/BridgedDataSource.swift @@ -30,8 +30,8 @@ internal typealias TableCellForRowAtIndexPathHandler = (UITableView, IndexPath) internal typealias TableTitleForHeaderInSectionHandler = (Int) -> String? internal typealias TableTitleForFooterInSectionHandler = (Int) -> String? -internal typealias TableCanEditRowAtIndexPathHandler = (UITableView, IndexPath) -> Bool -internal typealias TableCommitEditingStyleForRowAtIndexPathHandler = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void +internal typealias TableCanEditHandler = (UITableView, IndexPath) -> Bool +internal typealias TableCommitEditingStyleHandler = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void /* @@ -50,8 +50,8 @@ internal typealias TableCommitEditingStyleForRowAtIndexPathHandler = (UITableVie var tableTitleForHeaderInSection: TableTitleForHeaderInSectionHandler? var tableTitleForFooterInSection: TableTitleForFooterInSectionHandler? - var tableCanEditRowAtIndexPath: TableCanEditRowAtIndexPathHandler? - var tableCommitEditingStyleForRowAtIndexPath: TableCommitEditingStyleForRowAtIndexPathHandler? + var tableCanEditRow: TableCanEditHandler? + var tableCommitEditingStyleForRow: TableCommitEditingStyleHandler? init(numberOfSections: @escaping NumberOfSectionsHandler, numberOfItemsInSection: @escaping NumberOfItemsInSectionHandler) { @@ -111,13 +111,13 @@ extension BridgedDataSource: UITableViewDataSource { } @objc func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - if let closure = tableCanEditRowAtIndexPath{ + if let closure = tableCanEditRow { return closure(tableView,indexPath) } return false } @objc func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { - tableCommitEditingStyleForRowAtIndexPath?(tableView,editingStyle,indexPath) + tableCommitEditingStyleForRow?(tableView,editingStyle,indexPath) } } diff --git a/Source/DataSource.swift b/Source/DataSource.swift index e25e3bf..494c24d 100644 --- a/Source/DataSource.swift +++ b/Source/DataSource.swift @@ -128,6 +128,34 @@ public struct DataSource: DataSourceProtocol { public func numberOfSections() -> Int { return sections.count } + + /** + Checks if a Section exists at a specific `IndexPath`. + + - parameter indexPath: The index path specifying the location of the cell. + - returns: `true` if the section exists at the specified `IndexPath`, otherwise it returns `false`. + */ + public func sectionExists(for indexPath: IndexPath) -> Bool { + let section = indexPath.section + return section < numberOfSections() + } + + /** + Checks if an Item exists at a specific `IndexPath`. + + - parameter indexPath: The index path specifying the location of the cell. + - returns: `true` if the item exists at the specified `IndexPath`, otherwise it returns `false`. + */ + public func itemExists(for indexPath: IndexPath) -> Bool { + if !sectionExists(for: indexPath) { + return false + } + + let section = indexPath.section + let row = indexPath.row + + return row < numberOfItems(inSection: section) + } /// :nodoc: public func numberOfItems(inSection section: Int) -> Int { @@ -161,16 +189,17 @@ public struct DataSource: DataSourceProtocol { } /** - Removes an Item at a specific `IndexPath` + Removes an Item at a specific `IndexPath`. - - parameter indexPath: The index path specifying the location of the cell - - returns: The item specified by indexPath, or `nil` + - parameter indexPath: The index path specifying the location of the cell. + - returns: The item specified by indexPath, or `nil`. */ @discardableResult public mutating func remove(at indexPath: IndexPath) -> S.Item? { - guard indexPath.section <= numberOfSections() else { return nil } - guard indexPath.row <= numberOfItems(inSection: indexPath.section) else { return nil } - return sections[indexPath.section].items.remove(at: indexPath.row) + guard itemExists(for: indexPath) else { return nil } + let section = indexPath.section + let row = indexPath.row + return sections[section].items.remove(at: row) } // MARK: Subscripts diff --git a/Source/DataSourceProvider.swift b/Source/DataSourceProvider.swift index 28b39a0..061e8a7 100644 --- a/Source/DataSourceProvider.swift +++ b/Source/DataSourceProvider.swift @@ -37,10 +37,10 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour public let supplementaryFactory: SupplementaryFactory fileprivate var bridgedDataSource: BridgedDataSource? - - //The data source that provides the editing functionality on the tableView - public var dataSourceTableEditing: DataSourceTableEditingProtocol? + //The data source that provides the editing functionality on the tableView + fileprivate var dataSourceTableEditing: TableDataSourceEditingController? + // MARK: Initialization /** @@ -49,7 +49,6 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour - parameter dataSource: The data source. - parameter cellFactory: The cell factory. - parameter supplementaryFactory: The supplementary view factory. - - parameter dataSourceTableEditing: The datasource that will enable the tableView only to edit it's cells - returns: A new `DataSourceProvider` instance. @@ -58,11 +57,10 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour the generic constraints for Swift. You can simply pass the same `cellFactory` here. The parameter will be ignored. The same applies to collection views that do not have supplementary views. Again, the parameter will be ignored. */ - public init(dataSource: DataSource, cellFactory: CellFactory, supplementaryFactory: SupplementaryFactory, dataSourceTableEditing: DataSourceTableEditingProtocol? = nil) { + public init(dataSource: DataSource, cellFactory: CellFactory, supplementaryFactory: SupplementaryFactory) { self.dataSource = dataSource self.cellFactory = cellFactory self.supplementaryFactory = supplementaryFactory - self.dataSourceTableEditing = dataSourceTableEditing } } @@ -77,6 +75,10 @@ public extension DataSourceProvider where CellFactory.View: UITableViewCell { } return bridgedDataSource! } + + public func setTableDataSourceEditingController(_ dataSourceTableEditing: TableDataSourceEditingController) { + self.dataSourceTableEditing = dataSourceTableEditing + } private func tableViewBridgedDataSource() -> BridgedDataSource { let dataSource = BridgedDataSource( @@ -100,13 +102,13 @@ public extension DataSourceProvider where CellFactory.View: UITableViewCell { return self.dataSource.footerTitle(inSection: section) } - dataSource.tableCanEditRowAtIndexPath = { [unowned self] (tableView, indexPath) -> Bool in + dataSource.tableCanEditRow = { [unowned self] (tableView, indexPath) -> Bool in guard let editDataSource = self.dataSourceTableEditing else { return false } - return editDataSource.configureCanEditRowAt(indexPath: indexPath, in: tableView) + return editDataSource.canEditRowAt(indexPath: indexPath, in: tableView) } - dataSource.tableCommitEditingStyleForRowAtIndexPath = { [unowned self] (tableView, editingStyle,indexPath) in - self.dataSourceTableEditing?.configureCommitEditStyleForRow(in: tableView, editingStyle: editingStyle, at: indexPath) + dataSource.tableCommitEditingStyleForRow = { [unowned self] (tableView, editingStyle,indexPath) in + self.dataSourceTableEditing?.commitEditStyleForRow(in: tableView, editingStyle: editingStyle, at: indexPath) } return dataSource diff --git a/Source/OptionalDataSource.swift b/Source/OptionalDataSource.swift index afc1a07..4965a44 100644 --- a/Source/OptionalDataSource.swift +++ b/Source/OptionalDataSource.swift @@ -9,32 +9,7 @@ import Foundation import UIKit -public protocol DataSourceTableEditingProtocol { - - //MARK: Methods - - /** - Returns a `Bool` which indicates if the cell will be available for editing or not - - - parameter indexPath: The index path specifying the location of the cell. - - parameter tableView: The table view requesting this information. - - - returns: A `Bool` which indicates if the cell will be available for editing or not - */ - func configureCanEditRowAt(indexPath: IndexPath, in tableView: UITableView) -> Bool - - /** - Commit any neccessary action in respect of the `editingStyle` on the current `indexPath` - - - parameter tableView: The table view requesting this information. - - parameter editingStyle: The editingStyle that requested on the current `indexPath` (for example `.delete`) - - parameter indexPath: The index path specifying the location of the cell. - */ - func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) -> Void - -} - -public struct DataSourceEditingController: DataSourceTableEditingProtocol { +public struct TableDataSourceEditingController { public typealias CanEditRowConfigurator = (IndexPath, UITableView) -> Bool public typealias CommitEditingStyleConfigurator = (UITableView, UITableViewCellEditingStyle, IndexPath) -> Void @@ -49,11 +24,11 @@ public struct DataSourceEditingController: DataSourceTableEditingProtocol { self.commitEditingStyle = commitEditingStyle } - public func configureCanEditRowAt(indexPath: IndexPath, in tableView: UITableView) -> Bool { + public func canEditRowAt(indexPath: IndexPath, in tableView: UITableView) -> Bool { return canEditConfigurator(indexPath, tableView) } - public func configureCommitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) { + public func commitEditStyleForRow(in tableView: UITableView, editingStyle: UITableViewCellEditingStyle, at indexPath: IndexPath) { return commitEditingStyle(tableView, editingStyle, indexPath) } diff --git a/Tests/DataSourceProviderTests.swift b/Tests/DataSourceProviderTests.swift index 72a8908..a9a81a3 100644 --- a/Tests/DataSourceProviderTests.swift +++ b/Tests/DataSourceProviderTests.swift @@ -400,7 +400,7 @@ final class DataSourceProviderTests: TestCase { } //GIVEN: a data source editing controller - let tableEditingController = DataSourceEditingController( + let tableDataSourceEditingController = TableDataSourceEditingController( canEditConfigurator: { (indexPath, tableView) -> Bool in return indexPath == expectedIndexPath }, @@ -413,9 +413,10 @@ final class DataSourceProviderTests: TestCase { }) // GIVEN: a data source provider - dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory, dataSourceTableEditing: tableEditingController) - let tableViewDataSource = dataSourceProvider.tableViewDataSource + dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory) + dataSourceProvider.setTableDataSourceEditingController(tableDataSourceEditingController) + let tableViewDataSource = dataSourceProvider.tableViewDataSource tableView.dataSource = tableViewDataSource // WHEN: we call the table view data source methods diff --git a/Tests/DataSourceTests.swift b/Tests/DataSourceTests.swift index 81249f6..baad287 100644 --- a/Tests/DataSourceTests.swift +++ b/Tests/DataSourceTests.swift @@ -230,7 +230,11 @@ final class DataSourceTests: XCTestCase { let ip = IndexPath(item: 1, section: 0) let itemToRemove = dataSource.item(atRow: ip.row, inSection: ip.section) - // THEN: the removedItem is the expected item + // THEN: Check if an item exists at the specified indexPath .Then check if the removedItem is the expected item + + let itemExists = dataSource.itemExists(for:ip) + XCTAssertTrue(itemExists) + let removedItem = dataSource.remove(at: ip) XCTAssertEqual(removedItem, itemToRemove) } From b94065b2f5ef73e5feb5bc8b3153464d762d76ba Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Mon, 12 Dec 2016 16:46:32 +0000 Subject: [PATCH 22/24] Merge remote-tracking branch 'jessesquires/develop' into issue_29_tableViewDataSource_editing --- .codecov.yml | 11 ++--------- .travis.yml | 15 ++++++--------- docs/Classes.html | 4 ++-- docs/Classes/DataSourceProvider.html | 4 ++-- docs/Classes/FetchedResultsController.html | 4 ++-- docs/Classes/FetchedResultsDelegateProvider.html | 4 ++-- docs/Classes/TitledSupplementaryView.html | 4 ++-- docs/Enums.html | 4 ++-- docs/Enums/ReusableViewType.html | 4 ++-- docs/Protocols.html | 4 ++-- docs/Protocols/CellParentViewProtocol.html | 4 ++-- docs/Protocols/DataSourceProtocol.html | 4 ++-- docs/Protocols/ReusableViewFactoryProtocol.html | 4 ++-- docs/Protocols/ReusableViewProtocol.html | 4 ++-- docs/Protocols/SectionInfoProtocol.html | 4 ++-- docs/Structs.html | 4 ++-- docs/Structs/DataSource.html | 4 ++-- docs/Structs/Section.html | 4 ++-- docs/Structs/TitledSupplementaryViewFactory.html | 4 ++-- docs/Structs/ViewFactory.html | 4 ++-- docs/index.html | 4 ++-- 21 files changed, 46 insertions(+), 56 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index 407f49e..bbb4bb2 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,5 +1,5 @@ codecov: - branch: develop + branch: master coverage: precision: 2 @@ -11,13 +11,6 @@ coverage: status: project: - default: - target: auto - threshold: 2.0 - branches: - - master - - develop - patch: default: target: auto branches: @@ -25,7 +18,7 @@ coverage: - develop comment: - layout: header, diff, changes, sunburst, uncovered + layout: "header, diff, changes, sunburst, uncovered, tree" behavior: default branches: - master diff --git a/.travis.yml b/.travis.yml index 4af8613..262f395 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,6 @@ language: objective-c -osx_image: xcode8 +osx_image: xcode8.1 -cache: - - cocoapods - env: global: - LANG=en_US.UTF-8 @@ -13,7 +10,7 @@ env: - IOS_SCHEME="JSQDataSourcesKit-iOS" - TVOS_SCHEME="JSQDataSourcesKit-tvOS" - - IOS_SDK=iphonesimulator10.0 + - IOS_SDK=iphonesimulator10.1 - TVOS_SDK=appletvsimulator10.0 matrix: @@ -27,15 +24,15 @@ env: - DESTINATION="OS=9.2,name=iPhone 6s Plus" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" - DESTINATION="OS=9.3,name=iPad Pro" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="NO" POD_LINT="NO" - - DESTINATION="OS=10.0,name=iPhone 7" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" + - DESTINATION="OS=10.0,name=iPhone 6s" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" + - DESTINATION="OS=10.1,name=iPhone 7" SDK="$IOS_SDK" SCHEME="$IOS_SCHEME" RUN_TESTS="YES" BUILD_EXAMPLE="YES" POD_LINT="NO" - DESTINATION="OS=9.0,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO" - DESTINATION="OS=10.0,name=Apple TV 1080p" SDK="$TVOS_SDK" SCHEME="$TVOS_SCHEME" RUN_TESTS="NO" BUILD_EXAMPLE="NO" POD_LINT="NO" -before_install: - - gem install cocoapods # travis is not always on latest version - script: +- set -o pipefail + - if [ $POD_LINT == "YES" ]; then pod lib lint; fi diff --git a/docs/Classes.html b/docs/Classes.html index cf406fc..49898c7 100644 --- a/docs/Classes.html +++ b/docs/Classes.html @@ -235,8 +235,8 @@

Declaration

diff --git a/docs/Classes/DataSourceProvider.html b/docs/Classes/DataSourceProvider.html index ba02a50..eccd6a3 100644 --- a/docs/Classes/DataSourceProvider.html +++ b/docs/Classes/DataSourceProvider.html @@ -377,8 +377,8 @@

Declaration

diff --git a/docs/Classes/FetchedResultsController.html b/docs/Classes/FetchedResultsController.html index c9641de..f9bb763 100644 --- a/docs/Classes/FetchedResultsController.html +++ b/docs/Classes/FetchedResultsController.html @@ -258,8 +258,8 @@

Return Value

diff --git a/docs/Classes/FetchedResultsDelegateProvider.html b/docs/Classes/FetchedResultsDelegateProvider.html index fcb35a9..66ae187 100644 --- a/docs/Classes/FetchedResultsDelegateProvider.html +++ b/docs/Classes/FetchedResultsDelegateProvider.html @@ -418,8 +418,8 @@

Declaration

diff --git a/docs/Classes/TitledSupplementaryView.html b/docs/Classes/TitledSupplementaryView.html index f5bfb67..b5b3d5e 100644 --- a/docs/Classes/TitledSupplementaryView.html +++ b/docs/Classes/TitledSupplementaryView.html @@ -241,8 +241,8 @@

Declaration

diff --git a/docs/Enums.html b/docs/Enums.html index 2ffc9ad..95127d3 100644 --- a/docs/Enums.html +++ b/docs/Enums.html @@ -141,8 +141,8 @@

Declaration

diff --git a/docs/Enums/ReusableViewType.html b/docs/Enums/ReusableViewType.html index 6738515..024cc01 100644 --- a/docs/Enums/ReusableViewType.html +++ b/docs/Enums/ReusableViewType.html @@ -171,8 +171,8 @@

Declaration

diff --git a/docs/Protocols.html b/docs/Protocols.html index b2b479d..cbcb6ae 100644 --- a/docs/Protocols.html +++ b/docs/Protocols.html @@ -288,8 +288,8 @@

Declaration

diff --git a/docs/Protocols/CellParentViewProtocol.html b/docs/Protocols/CellParentViewProtocol.html index 12f8096..5d8250a 100644 --- a/docs/Protocols/CellParentViewProtocol.html +++ b/docs/Protocols/CellParentViewProtocol.html @@ -304,8 +304,8 @@

Return Value

diff --git a/docs/Protocols/DataSourceProtocol.html b/docs/Protocols/DataSourceProtocol.html index a24c8a4..8eb6927 100644 --- a/docs/Protocols/DataSourceProtocol.html +++ b/docs/Protocols/DataSourceProtocol.html @@ -458,8 +458,8 @@

Return Value

diff --git a/docs/Protocols/ReusableViewFactoryProtocol.html b/docs/Protocols/ReusableViewFactoryProtocol.html index 5b190fe..62641a8 100644 --- a/docs/Protocols/ReusableViewFactoryProtocol.html +++ b/docs/Protocols/ReusableViewFactoryProtocol.html @@ -657,8 +657,8 @@

Return Value

diff --git a/docs/Protocols/ReusableViewProtocol.html b/docs/Protocols/ReusableViewProtocol.html index 6876cde..6c5e12f 100644 --- a/docs/Protocols/ReusableViewProtocol.html +++ b/docs/Protocols/ReusableViewProtocol.html @@ -225,8 +225,8 @@

Declaration

diff --git a/docs/Protocols/SectionInfoProtocol.html b/docs/Protocols/SectionInfoProtocol.html index 95353e9..108f267 100644 --- a/docs/Protocols/SectionInfoProtocol.html +++ b/docs/Protocols/SectionInfoProtocol.html @@ -239,8 +239,8 @@

Declaration

diff --git a/docs/Structs.html b/docs/Structs.html index 8cfefc2..b416760 100644 --- a/docs/Structs.html +++ b/docs/Structs.html @@ -243,8 +243,8 @@

Declaration

diff --git a/docs/Structs/DataSource.html b/docs/Structs/DataSource.html index ff80584..0a00e1e 100644 --- a/docs/Structs/DataSource.html +++ b/docs/Structs/DataSource.html @@ -365,8 +365,8 @@

Return Value

diff --git a/docs/Structs/Section.html b/docs/Structs/Section.html index 3362f66..9cf7bd5 100644 --- a/docs/Structs/Section.html +++ b/docs/Structs/Section.html @@ -447,8 +447,8 @@

Return Value

diff --git a/docs/Structs/TitledSupplementaryViewFactory.html b/docs/Structs/TitledSupplementaryViewFactory.html index e80341b..4ccbec3 100644 --- a/docs/Structs/TitledSupplementaryViewFactory.html +++ b/docs/Structs/TitledSupplementaryViewFactory.html @@ -289,8 +289,8 @@

Return Value

diff --git a/docs/Structs/ViewFactory.html b/docs/Structs/ViewFactory.html index 923cc3d..ff05e1f 100644 --- a/docs/Structs/ViewFactory.html +++ b/docs/Structs/ViewFactory.html @@ -414,8 +414,8 @@

Return Value

diff --git a/docs/index.html b/docs/index.html index cf7b30e..36db864 100644 --- a/docs/index.html +++ b/docs/index.html @@ -209,8 +209,8 @@ From c62032ac318a014e8b3b55371f6730b0579e2246 Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Mon, 12 Dec 2016 17:30:31 +0000 Subject: [PATCH 23/24] review updates --- Example/Sources/TableViewController.swift | 6 +-- JSQDataSourcesKit.xcodeproj/project.pbxproj | 8 ++-- Source/DataSource.swift | 40 +++---------------- Source/DataSourceProvider.swift | 18 +++++---- ...=> TableDataSourceEditingController.swift} | 18 +++++++-- Tests/DataSourceProviderTests.swift | 7 ++-- Tests/DataSourceTests.swift | 6 +-- 7 files changed, 43 insertions(+), 60 deletions(-) rename Source/{OptionalDataSource.swift => TableDataSourceEditingController.swift} (76%) diff --git a/Example/Sources/TableViewController.swift b/Example/Sources/TableViewController.swift index ecee018..0c843e7 100644 --- a/Example/Sources/TableViewController.swift +++ b/Example/Sources/TableViewController.swift @@ -52,14 +52,14 @@ final class TableViewController: UITableViewController { return indexPath.row % 2 == 0 }, commitEditingStyle:{ (tableView, editingStyle, indexPath) in - if editingStyle == .delete{ - if let _ = self.dataSourceProvider?.dataSource.remove(at: indexPath){ + if editingStyle == .delete { + if let _ = self.dataSourceProvider?.dataSource.remove(at: indexPath) { tableView.deleteRows(at: [indexPath], with: .automatic) } } }) - dataSourceProvider?.setTableDataSourceEditingController(tableDataSourceEditingController) + dataSourceProvider?.tableEditingController = tableDataSourceEditingController // 5. set data source tableView.dataSource = dataSourceProvider?.tableViewDataSource diff --git a/JSQDataSourcesKit.xcodeproj/project.pbxproj b/JSQDataSourcesKit.xcodeproj/project.pbxproj index e21f66f..a9c9c2f 100644 --- a/JSQDataSourcesKit.xcodeproj/project.pbxproj +++ b/JSQDataSourcesKit.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 1DD7AC5D1D86C4BC00B676A6 /* OptionalDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD7AC5C1D86C4BC00B676A6 /* OptionalDataSource.swift */; }; + 1DD7AC5D1D86C4BC00B676A6 /* TableDataSourceEditingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD7AC5C1D86C4BC00B676A6 /* TableDataSourceEditingController.swift */; }; 881A92DB1CB881550080BC5C /* FetchedResultsDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DCAD2C1CB87CB400C018AF /* FetchedResultsDelegate.swift */; }; 881A92DD1CB881550080BC5C /* JSQDataSourcesKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 88DCAD2F1CB87CB400C018AF /* JSQDataSourcesKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 881A92E11CB881550080BC5C /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DCAD331CB87CB400C018AF /* Section.swift */; }; @@ -85,7 +85,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 1DD7AC5C1D86C4BC00B676A6 /* OptionalDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionalDataSource.swift; sourceTree = ""; }; + 1DD7AC5C1D86C4BC00B676A6 /* TableDataSourceEditingController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableDataSourceEditingController.swift; sourceTree = ""; }; 881A92CC1CB881270080BC5C /* JSQDataSourcesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JSQDataSourcesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 882CA4531D1D7D48006112B9 /* BridgedFetchedResultsDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BridgedFetchedResultsDelegate.swift; sourceTree = ""; }; 882CA4571D1D82E1006112B9 /* TestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestCase.swift; sourceTree = ""; }; @@ -180,7 +180,7 @@ 88DCAD2C1CB87CB400C018AF /* FetchedResultsDelegate.swift */, 88DCAD2D1CB87CB400C018AF /* Info.plist */, 88DCAD2F1CB87CB400C018AF /* JSQDataSourcesKit.h */, - 1DD7AC5C1D86C4BC00B676A6 /* OptionalDataSource.swift */, + 1DD7AC5C1D86C4BC00B676A6 /* TableDataSourceEditingController.swift */, 88DCAD331CB87CB400C018AF /* Section.swift */, 88DCAD351CB87CB400C018AF /* TitledSupplementaryView.swift */, 88DCAD371CB87CB400C018AF /* TitledSupplementaryViewFactory.swift */, @@ -406,7 +406,7 @@ 88DCAD761CB87CC000C018AF /* TitledSupplementaryView.swift in Sources */, 88DCAD741CB87CC000C018AF /* Section.swift in Sources */, 88B80CD81CBBF62A00EDF9D5 /* DataSourceProvider.swift in Sources */, - 1DD7AC5D1D86C4BC00B676A6 /* OptionalDataSource.swift in Sources */, + 1DD7AC5D1D86C4BC00B676A6 /* TableDataSourceEditingController.swift in Sources */, 888799491D0E2D1700BBCCBC /* DataSource.swift in Sources */, 88DCAD781CB87CC000C018AF /* TitledSupplementaryViewFactory.swift in Sources */, ); diff --git a/Source/DataSource.swift b/Source/DataSource.swift index 494c24d..593491c 100644 --- a/Source/DataSource.swift +++ b/Source/DataSource.swift @@ -82,7 +82,7 @@ extension DataSourceProtocol { - returns: The item specified by indexPath, or `nil`. */ - func item(atIndexPath indexPath: IndexPath) -> Item? { + public func item(atIndexPath indexPath: IndexPath) -> Item? { return item(atRow: indexPath.row, inSection: indexPath.section) } } @@ -128,34 +128,6 @@ public struct DataSource: DataSourceProtocol { public func numberOfSections() -> Int { return sections.count } - - /** - Checks if a Section exists at a specific `IndexPath`. - - - parameter indexPath: The index path specifying the location of the cell. - - returns: `true` if the section exists at the specified `IndexPath`, otherwise it returns `false`. - */ - public func sectionExists(for indexPath: IndexPath) -> Bool { - let section = indexPath.section - return section < numberOfSections() - } - - /** - Checks if an Item exists at a specific `IndexPath`. - - - parameter indexPath: The index path specifying the location of the cell. - - returns: `true` if the item exists at the specified `IndexPath`, otherwise it returns `false`. - */ - public func itemExists(for indexPath: IndexPath) -> Bool { - if !sectionExists(for: indexPath) { - return false - } - - let section = indexPath.section - let row = indexPath.row - - return row < numberOfItems(inSection: section) - } /// :nodoc: public func numberOfItems(inSection section: Int) -> Int { @@ -188,15 +160,15 @@ public struct DataSource: DataSourceProtocol { return sections[section].footerTitle } - /** - Removes an Item at a specific `IndexPath`. + /** + Removes an item at the specified index path. - - parameter indexPath: The index path specifying the location of the cell. - - returns: The item specified by indexPath, or `nil`. + - parameter indexPath: The index path specifying the location of the item. + - returns: The item at `indexPath`, or `nil` if it does not exist. */ @discardableResult public mutating func remove(at indexPath: IndexPath) -> S.Item? { - guard itemExists(for: indexPath) else { return nil } + guard item(atIndexPath: indexPath) != nil else { return nil } let section = indexPath.section let row = indexPath.row return sections[section].items.remove(at: row) diff --git a/Source/DataSourceProvider.swift b/Source/DataSourceProvider.swift index 061e8a7..01c82f9 100644 --- a/Source/DataSourceProvider.swift +++ b/Source/DataSourceProvider.swift @@ -38,8 +38,7 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour fileprivate var bridgedDataSource: BridgedDataSource? - //The data source that provides the editing functionality on the tableView - fileprivate var dataSourceTableEditing: TableDataSourceEditingController? + fileprivate var _tableEditingController: TableDataSourceEditingController? // MARK: Initialization @@ -76,10 +75,15 @@ public extension DataSourceProvider where CellFactory.View: UITableViewCell { return bridgedDataSource! } - public func setTableDataSourceEditingController(_ dataSourceTableEditing: TableDataSourceEditingController) { - self.dataSourceTableEditing = dataSourceTableEditing + public var tableEditingController: TableDataSourceEditingController? { + set { + _tableEditingController = newValue + } + get { + return _tableEditingController + } } - + private func tableViewBridgedDataSource() -> BridgedDataSource { let dataSource = BridgedDataSource( numberOfSections: { [unowned self] () -> Int in @@ -103,12 +107,12 @@ public extension DataSourceProvider where CellFactory.View: UITableViewCell { } dataSource.tableCanEditRow = { [unowned self] (tableView, indexPath) -> Bool in - guard let editDataSource = self.dataSourceTableEditing else { return false } + guard let editDataSource = self.tableEditingController else { return false } return editDataSource.canEditRowAt(indexPath: indexPath, in: tableView) } dataSource.tableCommitEditingStyleForRow = { [unowned self] (tableView, editingStyle,indexPath) in - self.dataSourceTableEditing?.commitEditStyleForRow(in: tableView, editingStyle: editingStyle, at: indexPath) + self.tableEditingController?.commitEditStyleForRow(in: tableView, editingStyle: editingStyle, at: indexPath) } return dataSource diff --git a/Source/OptionalDataSource.swift b/Source/TableDataSourceEditingController.swift similarity index 76% rename from Source/OptionalDataSource.swift rename to Source/TableDataSourceEditingController.swift index 4965a44..2477085 100644 --- a/Source/OptionalDataSource.swift +++ b/Source/TableDataSourceEditingController.swift @@ -1,9 +1,19 @@ // -// DataSourceEditing.swift -// JSQDataSourcesKit +// Created by Jesse Squires +// http://www.jessesquires.com // -// Created by Panagiotis Sartzetakis on 12/09/2016. -// Copyright © 2016 Hexed Bits. All rights reserved. +// +// Documentation +// http://jessesquires.com/JSQDataSourcesKit +// +// +// GitHub +// https://github.com/jessesquires/JSQDataSourcesKit +// +// +// License +// Copyright © 2015 Jesse Squires +// Released under an MIT license: http://opensource.org/licenses/MIT // import Foundation diff --git a/Tests/DataSourceProviderTests.swift b/Tests/DataSourceProviderTests.swift index a9a81a3..b7a264e 100644 --- a/Tests/DataSourceProviderTests.swift +++ b/Tests/DataSourceProviderTests.swift @@ -387,7 +387,6 @@ final class DataSourceProviderTests: TestCase { typealias TableCellFactory = ViewFactory var dataSourceProvider: DataSourceProvider>, TableCellFactory, TableCellFactory>! - // GIVEN: a cell factory let factory = ViewFactory(reuseIdentifier: cellReuseId) { (cell, model: FakeViewModel?, type, tableView, indexPath) -> FakeTableCell in @@ -405,8 +404,8 @@ final class DataSourceProviderTests: TestCase { return indexPath == expectedIndexPath }, commitEditingStyle:{ (tableView, editingStyle, indexPath) in - if editingStyle == .delete{ - if let _ = dataSourceProvider.dataSource.remove(at: indexPath){ + if editingStyle == .delete { + if let _ = dataSourceProvider.dataSource.remove(at: indexPath) { tableView.deleteRows(at: [indexPath], with: .automatic) } } @@ -414,7 +413,7 @@ final class DataSourceProviderTests: TestCase { // GIVEN: a data source provider dataSourceProvider = DataSourceProvider(dataSource: dataSource, cellFactory: factory, supplementaryFactory: factory) - dataSourceProvider.setTableDataSourceEditingController(tableDataSourceEditingController) + dataSourceProvider.tableEditingController = tableDataSourceEditingController let tableViewDataSource = dataSourceProvider.tableViewDataSource tableView.dataSource = tableViewDataSource diff --git a/Tests/DataSourceTests.swift b/Tests/DataSourceTests.swift index baad287..16b22e1 100644 --- a/Tests/DataSourceTests.swift +++ b/Tests/DataSourceTests.swift @@ -228,12 +228,10 @@ final class DataSourceTests: XCTestCase { // WHEN: we set an item at a specific index path let ip = IndexPath(item: 1, section: 0) - let itemToRemove = dataSource.item(atRow: ip.row, inSection: ip.section) + let itemToRemove = dataSource.item(atIndexPath: ip) // THEN: Check if an item exists at the specified indexPath .Then check if the removedItem is the expected item - - let itemExists = dataSource.itemExists(for:ip) - XCTAssertTrue(itemExists) + XCTAssertNotNil(itemToRemove) let removedItem = dataSource.remove(at: ip) XCTAssertEqual(removedItem, itemToRemove) From 97f94dc7a80f44242c42e39b9b3b9925c27b74ce Mon Sep 17 00:00:00 2001 From: Panagiotis Sartzetakis Date: Tue, 13 Dec 2016 09:02:57 +0000 Subject: [PATCH 24/24] minor update --- JSQDataSourcesKit.xcodeproj/project.pbxproj | 2 ++ Source/DataSourceProvider.swift | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/JSQDataSourcesKit.xcodeproj/project.pbxproj b/JSQDataSourcesKit.xcodeproj/project.pbxproj index a9c9c2f..ddac0e6 100644 --- a/JSQDataSourcesKit.xcodeproj/project.pbxproj +++ b/JSQDataSourcesKit.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 1D68ECA31DFFEF4600A1AFB7 /* TableDataSourceEditingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD7AC5C1D86C4BC00B676A6 /* TableDataSourceEditingController.swift */; }; 1DD7AC5D1D86C4BC00B676A6 /* TableDataSourceEditingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD7AC5C1D86C4BC00B676A6 /* TableDataSourceEditingController.swift */; }; 881A92DB1CB881550080BC5C /* FetchedResultsDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DCAD2C1CB87CB400C018AF /* FetchedResultsDelegate.swift */; }; 881A92DD1CB881550080BC5C /* JSQDataSourcesKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 88DCAD2F1CB87CB400C018AF /* JSQDataSourcesKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -391,6 +392,7 @@ 88B80CD91CBBF62A00EDF9D5 /* DataSourceProvider.swift in Sources */, 882CA4551D1D7DE1006112B9 /* BridgedFetchedResultsDelegate.swift in Sources */, 882CA4561D1D7DE1006112B9 /* DataSource.swift in Sources */, + 1D68ECA31DFFEF4600A1AFB7 /* TableDataSourceEditingController.swift in Sources */, 881A92DB1CB881550080BC5C /* FetchedResultsDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Source/DataSourceProvider.swift b/Source/DataSourceProvider.swift index 01c82f9..520d54a 100644 --- a/Source/DataSourceProvider.swift +++ b/Source/DataSourceProvider.swift @@ -48,7 +48,6 @@ where CellFactory.Item == DataSource.Item, SupplementaryFactory.Item == DataSour - parameter dataSource: The data source. - parameter cellFactory: The cell factory. - parameter supplementaryFactory: The supplementary view factory. - to edit it's cells - returns: A new `DataSourceProvider` instance.