From 6719c0e7b2e9c0f6d04e709af4fb8441d833fefe Mon Sep 17 00:00:00 2001 From: Malcolm Hall Date: Wed, 17 Jan 2024 22:37:47 +0000 Subject: [PATCH 1/4] Updated for Swift 5, Xcode 15.2 --- JadKit.xcodeproj/project.pbxproj | 111 +++-- .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/JadKit.xcscheme | 78 ++++ JadKit/Extensions/Date.swift | 57 --- JadKit/Extensions/Size.swift | 20 +- JadKit/Extensions/View.swift | 306 ++++++------- JadKit/Extensions/ViewController.swift | 38 +- JadKit/Protocols/FetchedList.swift | 289 ++++++------- JadKit/Protocols/List.swift | 66 +-- JadKit/Protocols/NonFetchedList.swift | 198 +++++---- JadKit/Views/PaddedLabel.swift | 129 +++--- JadKitTests/JadKitTests.swift | 323 +++++++------- .../JadKitTests.xcdatamodel/contents | 7 +- .../Protocols/CollectionListTests.swift | 188 ++++---- .../FetchedCollectionListTests.swift | 404 +++++++++--------- JadKitTests/Protocols/FetchedListTests.swift | 32 +- .../Protocols/FetchedTableListTests.swift | 378 ++++++++-------- .../Protocols/NonFetchedListTests.swift | 26 +- JadKitTests/Protocols/TableListTests.swift | 38 +- 19 files changed, 1376 insertions(+), 1320 deletions(-) create mode 100644 JadKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 JadKit.xcodeproj/xcshareddata/xcschemes/JadKit.xcscheme delete mode 100644 JadKit/Extensions/Date.swift diff --git a/JadKit.xcodeproj/project.pbxproj b/JadKit.xcodeproj/project.pbxproj index 49910e4..7c6c25d 100644 --- a/JadKit.xcodeproj/project.pbxproj +++ b/JadKit.xcodeproj/project.pbxproj @@ -3,28 +3,27 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 0502844F1B1960C0007167E8 /* JadKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 0502844E1B1960C0007167E8 /* JadKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 050284551B1960C0007167E8 /* JadKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 050284491B1960C0007167E8 /* JadKit.framework */; }; 0502845C1B1960C0007167E8 /* JadKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0502845B1B1960C0007167E8 /* JadKitTests.swift */; }; - 052AF6031B63ED5B0039DFA1 /* NonFetchedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 052AF6021B63ED5B0039DFA1 /* NonFetchedList.swift */; }; - 054F27AD1B7FB5DB0084261B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 054F27AC1B7FB5DB0084261B /* ViewController.swift */; }; 054FBA841C8B86C8003C5A83 /* FetchedListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 054FBA831C8B86C8003C5A83 /* FetchedListTests.swift */; }; 054FBA871C8B8935003C5A83 /* JadKitTests.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 054FBA851C8B8935003C5A83 /* JadKitTests.xcdatamodeld */; }; 054FBA8F1C8CED7A003C5A83 /* FetchedTableListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 054FBA8E1C8CED7A003C5A83 /* FetchedTableListTests.swift */; }; 054FBA911C8D0004003C5A83 /* FetchedCollectionListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 054FBA901C8D0004003C5A83 /* FetchedCollectionListTests.swift */; }; - 055135AB1BF7D890000098F9 /* PaddedLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055135AA1BF7D890000098F9 /* PaddedLabel.swift */; }; - 0567E0201B54C30A00C04CF3 /* Size.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0567E01A1B54C30A00C04CF3 /* Size.swift */; }; - 0567E0211B54C30A00C04CF3 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0567E01B1B54C30A00C04CF3 /* View.swift */; }; - 0567E0221B54C30A00C04CF3 /* List.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0567E01D1B54C30A00C04CF3 /* List.swift */; }; - 0567E0251B54C32000C04CF3 /* FetchedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0567E0241B54C32000C04CF3 /* FetchedList.swift */; }; - 05C805291BC4910900295AB1 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C805281BC4910900295AB1 /* Date.swift */; }; 05E3E58C1C8A91F9006B9AC1 /* TableListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05E3E58A1C8A91F9006B9AC1 /* TableListTests.swift */; }; 05E3E58F1C8A9364006B9AC1 /* CollectionListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05E3E58E1C8A9364006B9AC1 /* CollectionListTests.swift */; }; 05E3E59C1C8B64B7006B9AC1 /* NonFetchedListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05E3E59B1C8B64B7006B9AC1 /* NonFetchedListTests.swift */; }; + EC76FCE82B58425600990A60 /* Size.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0567E01A1B54C30A00C04CF3 /* Size.swift */; }; + EC76FCE92B58425C00990A60 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0567E01B1B54C30A00C04CF3 /* View.swift */; }; + EC76FCEA2B58427000990A60 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 054F27AC1B7FB5DB0084261B /* ViewController.swift */; }; + EC76FCEC2B58429800990A60 /* List.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0567E01D1B54C30A00C04CF3 /* List.swift */; }; + EC76FCED2B5842A500990A60 /* NonFetchedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 052AF6021B63ED5B0039DFA1 /* NonFetchedList.swift */; }; + EC76FCEE2B5842AC00990A60 /* FetchedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0567E0241B54C32000C04CF3 /* FetchedList.swift */; }; + EC76FCEF2B5842CC00990A60 /* PaddedLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 055135AA1BF7D890000098F9 /* PaddedLabel.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -55,7 +54,6 @@ 0567E01B1B54C30A00C04CF3 /* View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; 0567E01D1B54C30A00C04CF3 /* List.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = List.swift; sourceTree = ""; }; 0567E0241B54C32000C04CF3 /* FetchedList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchedList.swift; sourceTree = ""; }; - 05C805281BC4910900295AB1 /* Date.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = ""; }; 05E3E58A1C8A91F9006B9AC1 /* TableListTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableListTests.swift; sourceTree = ""; }; 05E3E58E1C8A9364006B9AC1 /* CollectionListTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionListTests.swift; sourceTree = ""; }; 05E3E59B1C8B64B7006B9AC1 /* NonFetchedListTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NonFetchedListTests.swift; sourceTree = ""; }; @@ -151,7 +149,6 @@ 0567E01A1B54C30A00C04CF3 /* Size.swift */, 0567E01B1B54C30A00C04CF3 /* View.swift */, 054F27AC1B7FB5DB0084261B /* ViewController.swift */, - 05C805281BC4910900295AB1 /* Date.swift */, ); path = Extensions; sourceTree = ""; @@ -235,9 +232,10 @@ 050284401B1960C0007167E8 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 1520; ORGANIZATIONNAME = "Jad Osseiran"; TargetAttributes = { 050284481B1960C0007167E8 = { @@ -251,10 +249,11 @@ }; buildConfigurationList = 050284431B1960C0007167E8 /* Build configuration list for PBXProject "JadKit" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 0502843F1B1960C0007167E8; productRefGroup = 0502844A1B1960C0007167E8 /* Products */; @@ -289,14 +288,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0567E0251B54C32000C04CF3 /* FetchedList.swift in Sources */, - 05C805291BC4910900295AB1 /* Date.swift in Sources */, - 052AF6031B63ED5B0039DFA1 /* NonFetchedList.swift in Sources */, - 0567E0221B54C30A00C04CF3 /* List.swift in Sources */, - 054F27AD1B7FB5DB0084261B /* ViewController.swift in Sources */, - 0567E0201B54C30A00C04CF3 /* Size.swift in Sources */, - 0567E0211B54C30A00C04CF3 /* View.swift in Sources */, - 055135AB1BF7D890000098F9 /* PaddedLabel.swift in Sources */, + EC76FCEA2B58427000990A60 /* ViewController.swift in Sources */, + EC76FCE92B58425C00990A60 /* View.swift in Sources */, + EC76FCE82B58425600990A60 /* Size.swift in Sources */, + EC76FCEC2B58429800990A60 /* List.swift in Sources */, + EC76FCED2B5842A500990A60 /* NonFetchedList.swift in Sources */, + EC76FCEF2B5842CC00990A60 /* PaddedLabel.swift in Sources */, + EC76FCEE2B5842AC00990A60 /* FetchedList.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -330,17 +328,29 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -349,6 +359,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -364,7 +375,6 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -379,17 +389,29 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -398,6 +420,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -406,9 +429,9 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -420,21 +443,27 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = JadKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; PRODUCT_BUNDLE_IDENTIFIER = "com.jadosseiran.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -442,32 +471,43 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = JadKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; PRODUCT_BUNDLE_IDENTIFIER = "com.jadosseiran.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; }; name = Release; }; 050284631B1960C0007167E8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = JadKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.jadosseiran.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -476,8 +516,13 @@ 050284641B1960C0007167E8 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; INFOPLIST_FILE = JadKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.jadosseiran.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; diff --git a/JadKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/JadKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/JadKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/JadKit.xcodeproj/xcshareddata/xcschemes/JadKit.xcscheme b/JadKit.xcodeproj/xcshareddata/xcschemes/JadKit.xcscheme new file mode 100644 index 0000000..067fce5 --- /dev/null +++ b/JadKit.xcodeproj/xcshareddata/xcschemes/JadKit.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/JadKit/Extensions/Date.swift b/JadKit/Extensions/Date.swift deleted file mode 100644 index ef7c3c5..0000000 --- a/JadKit/Extensions/Date.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// Date.swift -// JadKit -// -// Created by Jad Osseiran on 6/10/2015. -// Copyright © 2016 Jad Osseiran. All rights reserved. -// -// -------------------------------------------- -// -// Much nicer than using the more verbose compare: method. -// -// -------------------------------------------- -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -// THE POSSIBILITY OF SUCH DAMAGE. -// - -import Foundation - -public func ==(lhs: NSDate, rhs: NSDate) -> Bool { - return lhs.compare(rhs) == .OrderedSame -} - -public func <(lhs: NSDate, rhs: NSDate) -> Bool { - return lhs.compare(rhs) == .OrderedAscending -} - -public func >(lhs: NSDate, rhs: NSDate) -> Bool { - return rhs < lhs -} - -public func <=(lhs: NSDate, rhs: NSDate) -> Bool { - return (lhs > rhs) == false -} - -public func >=(lhs: NSDate, rhs: NSDate) -> Bool { - return (lhs < rhs) == false -} diff --git a/JadKit/Extensions/Size.swift b/JadKit/Extensions/Size.swift index 83f38da..8a922b6 100644 --- a/JadKit/Extensions/Size.swift +++ b/JadKit/Extensions/Size.swift @@ -36,13 +36,13 @@ import UIKit public extension CGSize { - /// The resulting size from flooring the width and height. - public var floorSize: CGSize { - return CGSize(width: floor(width), height: floor(height)) - } - - /// The resulting size from ceiling the width and height. - public var ceilSize: CGSize { - return CGSize(width: ceil(width), height: ceil(height)) - } -} \ No newline at end of file + /// The resulting size from flooring the width and height. + var floorSize: CGSize { + return CGSize(width: floor(width), height: floor(height)) + } + + /// The resulting size from ceiling the width and height. + var ceilSize: CGSize { + return CGSize(width: ceil(width), height: ceil(height)) + } +} diff --git a/JadKit/Extensions/View.swift b/JadKit/Extensions/View.swift index 4c1bb20..6154d3a 100644 --- a/JadKit/Extensions/View.swift +++ b/JadKit/Extensions/View.swift @@ -44,7 +44,7 @@ import UIKit - returns: The views which share the widest width. - complexity: O(n) */ -public func widestViews(views views: [UIView]) -> [UIView] { +public func widestViews(_ views: [UIView]) -> [UIView] { var widestViews = [UIView]() for view in views { @@ -53,7 +53,7 @@ public func widestViews(views views: [UIView]) -> [UIView] { let viewWidth = view.frame.size.width if widestWidth < viewWidth { - widestViews.removeAll(keepCapacity: false) + widestViews.removeAll(keepingCapacity: false) widestViews += [view] } else if widestWidth == viewWidth { widestViews += [view] @@ -73,8 +73,8 @@ public func widestViews(views views: [UIView]) -> [UIView] { - returns: The first widest view. - complexity: O(n) */ -public func widestView(views views: [UIView]) -> UIView { - let wideViews = widestViews(views: views) +public func widestView(_ views: [UIView]) -> UIView { + let wideViews = widestViews(views) return wideViews.first! } @@ -85,7 +85,7 @@ public func widestView(views views: [UIView]) -> UIView { - returns: The views which share the tallest height. - complexity: O(n) */ -public func tallestViews(views views: [UIView]) -> [UIView] { +public func tallestViews(_ views: [UIView]) -> [UIView] { var tallestViews = [UIView]() for view in views { @@ -94,7 +94,7 @@ public func tallestViews(views views: [UIView]) -> [UIView] { let viewHeight = view.frame.size.height if tallestHeight < viewHeight { - tallestViews.removeAll(keepCapacity: false) + tallestViews.removeAll(keepingCapacity: false) tallestViews += [view] } else if tallestHeight == viewHeight { tallestViews += [view] @@ -114,8 +114,8 @@ public func tallestViews(views views: [UIView]) -> [UIView] { - returns: The first tallest view. - complexity: O(n) */ -public func tallestView(views views: [UIView]) -> UIView { - let tallViews = tallestViews(views: views) +public func tallestView(_ views: [UIView]) -> UIView { + let tallViews = tallestViews(views) return tallViews.first! } @@ -127,7 +127,7 @@ public func tallestView(views views: [UIView]) -> UIView { - returns: The combined total width including the separation between views. - complexity: O(n) */ -public func totalWidth(views views: [UIView], separatorLength: CGFloat = 0.0) -> CGFloat { +public func totalWidth(_ views: [UIView], separatorLength: CGFloat = 0.0) -> CGFloat { var totalWidth: CGFloat = 0.0 for view in views { totalWidth += view.frame.size.width @@ -143,7 +143,7 @@ public func totalWidth(views views: [UIView], separatorLength: CGFloat = 0.0) -> - returns: The combined total height including the separation between views. - complexity: O(n) */ -public func totalHeight(views views: [UIView], separatorLength: CGFloat = 0.0) -> CGFloat { +public func totalHeight(_ views: [UIView], separatorLength: CGFloat = 0.0) -> CGFloat { var totalHeight: CGFloat = 0.0 for view in views { totalHeight += view.frame.size.height @@ -152,152 +152,156 @@ public func totalHeight(views views: [UIView], separatorLength: CGFloat = 0.0) - } public extension UIView { - /** - The duration for an animation. - */ - public enum AnimationDuration: Double { - /// 0.3s, quick animation. - case Short = 0.3 - /// 0.6s, twice as long as the `Short` duration. - case Medium = 0.6 - /// 0.9s, three times as long as the `Short` duration. - case Long = 0.9 - } - - // MARK: Hiding - - // FIXME: This method could get some loving, specially with the iOS 9 UIVisualEffectView stuff. - /** - Hides or unhides the view with the option the animate the transition. - - parameter hidden: Wether the view is to be hidden or not. - - parameter animated: Flag to animate the trasition. - - parameter duration: The duration of the hiding animation if turned on. `Short` by default. - - parameter effect: The `UIVisualEffect` that the view will take when it is shown again. - `nil` by default. - - parameter completion: Call back when the view has been hid or unhid. `nil` by default. - */ - public func setHidden(hide: Bool, animated: Bool, - duration: Double = AnimationDuration.Short.rawValue, - effect: UIVisualEffect? = nil, completion: ((Bool) -> Void)! = nil) { - if animated { - if hide { - UIView.animateWithDuration(duration, animations: { - if #available(iOS 9, *) { - if let effectView = self as? UIVisualEffectView { - effectView.effect = nil - effectView.contentView.alpha = 0.0 + /** + The duration for an animation. + */ + enum AnimationDuration: Double { + /// 0.3s, quick animation. + case Short = 0.3 + /// 0.6s, twice as long as the `Short` duration. + case Medium = 0.6 + /// 0.9s, three times as long as the `Short` duration. + case Long = 0.9 + } + + // MARK: Hiding + + // FIXME: This method could get some loving, specially with the iOS 9 UIVisualEffectView stuff. + /** + Hides or unhides the view with the option the animate the transition. + - parameter hidden: Wether the view is to be hidden or not. + - parameter animated: Flag to animate the trasition. + - parameter duration: The duration of the hiding animation if turned on. `Short` by default. + - parameter effect: The `UIVisualEffect` that the view will take when it is shown again. + `nil` by default. + - parameter completion: Call back when the view has been hid or unhid. `nil` by default. + */ + func setHidden( + hide: Bool, + animated: Bool, + duration: Double = AnimationDuration.Short.rawValue, + effect: UIVisualEffect? = nil, + completion: ((Bool) -> Void)! = nil + ) { + if animated { + if hide { + UIView.animate(withDuration: duration, animations: { + if #available(iOS 9, *) { + if let effectView = self as? UIVisualEffectView { + effectView.effect = nil + effectView.contentView.alpha = 0.0 + } else { + self.alpha = 0.0 + } + } else { + self.alpha = 0.0 + } + + }, completion: { finished in + if finished { + self.isHidden = true + } + + if completion != nil { + completion(finished) + } + }) } else { - self.alpha = 0.0 + if #available(iOS 9, *) { + if let effectView = self as? UIVisualEffectView { + effectView.contentView.alpha = 1.0 + } else { + alpha = 0.0 + } + } else { + alpha = 0.0 + } + isHidden = false + + UIView.animate(withDuration: duration, animations: { + if #available(iOS 9, *) { + if let effectView = self as? UIVisualEffectView { + effectView.effect = effect ?? UIBlurEffect(style: .light) + effectView.contentView.alpha = 1.0 + } else { + self.alpha = 1.0 + } + } else { + self.alpha = 1.0 + } + }, completion: completion) } - } else { - self.alpha = 0.0 - } - - }, completion: { finished in - if finished { - self.hidden = true + } else { + if self is UIVisualEffectView == false { + alpha = hide ? 0.0 : 1.0 } - + isHidden = hide + if completion != nil { - completion(finished) + completion(true) } - }) - } else { - if #available(iOS 9, *) { - if let effectView = self as? UIVisualEffectView { - effectView.contentView.alpha = 1.0 - } else { - alpha = 0.0 - } - } else { - alpha = 0.0 } - hidden = false - - UIView.animateWithDuration(duration, animations: { - if #available(iOS 9, *) { - if let effectView = self as? UIVisualEffectView { - effectView.effect = effect ?? UIBlurEffect(style: .Light) - effectView.contentView.alpha = 1.0 - } else { - self.alpha = 1.0 - } - } else { - self.alpha = 1.0 - } - }, completion: completion) - } - } else { - if self is UIVisualEffectView == false { - alpha = hide ? 0.0 : 1.0 - } - hidden = hide - - if completion != nil { - completion(true) - } } - } - - // MARK: Positioning - - /** - Calculates and returns: the value for the X origin of the view which will - center it in relation to the given frame. - The returned X origin is floored. - - parameter frame: The frame which the view will use to center itself. - - returns: The X origin for the view to take in order to be centered. - */ - public func horizontalCenterWithReferenceFrame(frame: CGRect) -> CGFloat { - let offset = floor((frame.size.width - self.frame.size.width) / 2.0) - return frame.origin.x + offset - } - - /** - Calculates and returns: the value for the Y origin of the view which will - center it in relation to the given frame. - The returned Y origin is floored. - - parameter frame: The frame which the view will use to center itself. - - returns: The Y origin for the view to take in order to be centered. - */ - public func verticalCenterWithReferenceFrame(frame: CGRect) -> CGFloat { - let offset = floor((frame.size.height - self.frame.size.height) / 2.0) - return frame.origin.y + offset - } - - /** - This method centers the view to be centered on the X axis with relation - to the passed frame. - - parameter rect: The rect which is used as a horizontal centering reference. - */ - public func centerHorizontallyWithReferenceRect(rect: CGRect) { - self.frame.origin.x = horizontalCenterWithReferenceFrame(rect) - } - - /** - This method centers the view to be centered on the Y axis with relation - to the passed frame. - - parameter rect: The rect which is used as a vertical centering reference. - */ - public func centerVerticallyWithReferenceRect(rect: CGRect) { - self.frame.origin.y = verticalCenterWithReferenceFrame(rect) - } - - // MARK: Masking - - /** - Method to set a rounded edges mask on the view's layer. - - parameter radius: The radius to use for the rounded edges. - */ - public func maskToRadius(radius: CGFloat) { - layer.cornerRadius = radius - layer.masksToBounds = true - } - - /** - Masks the view's layer to be in a cirle. - */ - public func maskToCircle() { - maskToRadius(frame.size.width / 2.0) - } + + // MARK: Positioning + + /** + Calculates and returns: the value for the X origin of the view which will + center it in relation to the given frame. + The returned X origin is floored. + - parameter frame: The frame which the view will use to center itself. + - returns: The X origin for the view to take in order to be centered. + */ + func horizontalCenterWithReferenceFrame(frame: CGRect) -> CGFloat { + let offset = floor((frame.size.width - self.frame.size.width) / 2.0) + return frame.origin.x + offset + } + + /** + Calculates and returns: the value for the Y origin of the view which will + center it in relation to the given frame. + The returned Y origin is floored. + - parameter frame: The frame which the view will use to center itself. + - returns: The Y origin for the view to take in order to be centered. + */ + func verticalCenterWithReferenceFrame(frame: CGRect) -> CGFloat { + let offset = floor((frame.size.height - self.frame.size.height) / 2.0) + return frame.origin.y + offset + } + + /** + This method centers the view to be centered on the X axis with relation + to the passed frame. + - parameter rect: The rect which is used as a horizontal centering reference. + */ + func centerHorizontallyWithReferenceRect(rect: CGRect) { + self.frame.origin.x = horizontalCenterWithReferenceFrame(frame: rect) + } + + /** + This method centers the view to be centered on the Y axis with relation + to the passed frame. + - parameter rect: The rect which is used as a vertical centering reference. + */ + func centerVerticallyWithReferenceRect(rect: CGRect) { + self.frame.origin.y = verticalCenterWithReferenceFrame(frame: rect) + } + + // MARK: Masking + + /** + Method to set a rounded edges mask on the view's layer. + - parameter radius: The radius to use for the rounded edges. + */ + func maskToRadius(radius: CGFloat) { + layer.cornerRadius = radius + layer.masksToBounds = true + } + + /** + Masks the view's layer to be in a cirle. + */ + func maskToCircle() { + maskToRadius(radius: frame.size.width / 2.0) + } } diff --git a/JadKit/Extensions/ViewController.swift b/JadKit/Extensions/ViewController.swift index 7688872..adfc2a5 100644 --- a/JadKit/Extensions/ViewController.swift +++ b/JadKit/Extensions/ViewController.swift @@ -36,24 +36,24 @@ import UIKit public extension UIViewController { - /// Whether the view controller was presented modally or not. - public var modal: Bool { - if self.presentingViewController?.presentedViewController == self { - return true + /// Whether the view controller was presented modally or not. + var modal: Bool { + if self.presentingViewController?.presentedViewController == self { + return true + } + + // UINavigationController + if self.navigationController != nil && + self.navigationController?.presentingViewController?.presentedViewController == + self.navigationController { + return true + } + + // UITabBarController + if self.tabBarController?.presentingViewController is UITabBarController { + return true + } + + return false } - - // UINavigationController - if self.navigationController != nil && - self.navigationController?.presentingViewController?.presentedViewController == - self.navigationController { - return true - } - - // UITabBarController - if self.tabBarController?.presentingViewController is UITabBarController { - return true - } - - return false - } } diff --git a/JadKit/Protocols/FetchedList.swift b/JadKit/Protocols/FetchedList.swift index f1296c8..99b313e 100644 --- a/JadKit/Protocols/FetchedList.swift +++ b/JadKit/Protocols/FetchedList.swift @@ -43,24 +43,27 @@ import CoreData conforming object will need to create in order to properly calculate the list data. */ -public protocol FetchedList: List, NSFetchedResultsControllerDelegate { - /// The fetched results controller that will be used to populate the list - /// dynamically as the backing store is updated. - var fetchedResultsController: NSFetchedResultsController! { get set } +public protocol FetchedList: List, NSFetchedResultsControllerDelegate where Object: NSFetchRequestResult { + + + /// The fetched results controller that will be used to populate the list + /// dynamically as the backing store is updated. + var fetchedResultsController: NSFetchedResultsController! { get set } } /** Protocol extension to implement the basic fetched list methods. */ public extension FetchedList { + /// The number of sections fetched by the `fetchedResultsController`. var numberOfSections: Int { return fetchedResultsController?.sections?.count ?? 0 } /// The index titles for the fetched list. - var sectionIndexTitles: [AnyObject]? { - return fetchedResultsController?.sectionIndexTitles + var sectionIndexTitles: [String]? { + return fetchedResultsController?.sectionIndexTitles } /** @@ -69,7 +72,7 @@ public extension FetchedList { - returns: The number of rows in a given section. `0` if the section is not found. */ - func numberOfRowsInSection(section: Int) -> Int { + func numberOfRows(inSection section: Int) -> Int { if let sections = fetchedResultsController?.sections { return sections[section].numberOfObjects } @@ -83,27 +86,27 @@ public extension FetchedList { - parameter indexPath: The index path to check for existance. - returns: `true` iff the index path is valid for your data source. */ - func isValidIndexPath(indexPath: NSIndexPath) -> Bool { + func isValid(_ indexPath: IndexPath) -> Bool { guard indexPath.section < numberOfSections && indexPath.section >= 0 else { return false } - return indexPath.row < numberOfRowsInSection(indexPath.section) && indexPath.row >= 0 + return indexPath.row < numberOfRows(inSection: indexPath.section) && indexPath.row >= 0 } /** Convenient helper method to find the object at a given index path. - This method works well with `isValidIndexPath:`. + This method works well with `isValid:`. - note: This method is implemented by a protocol extension if the object conforms to either `FetchedList` or `NonFetchedList` - parameter indexPath: The index path to retreive the object for. - returns: An optional with the corresponding object at an index path or nil if the index path is invalid. */ - func objectAtIndexPath(indexPath: NSIndexPath) -> AnyObject? { - guard isValidIndexPath(indexPath) else { + func object(at indexPath: IndexPath) -> Object? { + guard isValid(indexPath) else { return nil } - return fetchedResultsController?.objectAtIndexPath(indexPath) + return fetchedResultsController?.object(at: indexPath) } /** @@ -112,7 +115,7 @@ public extension FetchedList { - returns: The header title for the section or `nil` if none is found. */ func titleForHeaderInSection(section: Int) -> String? { - guard isValidIndexPath(NSIndexPath(forRow: 0, inSection: section)) else { + guard isValid(IndexPath(row: 0, section: section)) else { return nil } return fetchedResultsController?.sections?[section].name @@ -134,31 +137,30 @@ public protocol FetchedTableList: FetchedList, UITableViewDataSource, UITableVie /** Protocol extension to implement the table view delegate & data source methods. */ -public extension FetchedTableList where ListView == UITableView, Cell == UITableViewCell, - Object == AnyObject { +public extension FetchedTableList where ListView == UITableView, Cell == UITableViewCell { /** - Method to call in `tableView:cellForRowAtIndexPath:`. + Method to call in `tableView:cellForRowAt:`. - parameter indexPath: An index path locating a row in `tableView` */ - func tableCellAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell { - let identifier = cellIdentifierForIndexPath(indexPath) - let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath) - - if let object = objectAtIndexPath(indexPath) { - listView(tableView, configureCell: cell, withObject: object, atIndexPath: indexPath) - } - - return cell + func tableCell(at indexPath: IndexPath) -> UITableViewCell { + let identifier = cellIdentifier(for: indexPath) + let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) + + if let object = object(at: indexPath) { + listView(tableView, configure: cell, with: object, at: indexPath) + } + + return cell } - + /** - Method to call in `tableView:didSelectRowAtIndexPath:`. + Method to call in `tableView:didSelectRowAt:`. - parameter indexPath: An index path locating the new selected row in `tableView`. */ - func tableDidSelectItemAtIndexPath(indexPath: NSIndexPath) { - if let object = objectAtIndexPath(indexPath) { - listView(tableView, didSelectObject: object, atIndexPath: indexPath) - } + func tableDidSelectItem(at indexPath: IndexPath) { + if let object = object(at: indexPath) { + listView(tableView, didSelect: object, at: indexPath) + } } } @@ -166,15 +168,14 @@ public extension FetchedTableList where ListView == UITableView, Cell == UITable Protocol extension to implement the fetched results controller sdelegate methods. */ -public extension FetchedTableList where ListView == UITableView, Cell == UITableViewCell, - Object == AnyObject { +public extension FetchedTableList where ListView == UITableView, Cell == UITableViewCell { /** Method to call in `controllerWillChangeContent:`. */ func tableWillChangeContent() { - tableView.beginUpdates() + tableView.beginUpdates() } - + /** Method to call in `controller:didChangeSection:atIndex:forChangeType:`. - parameter sectionIndex: The index of the changed section. @@ -182,19 +183,19 @@ public extension FetchedTableList where ListView == UITableView, Cell == UITable `NSFetchedResultsChangeInsert` and `NSFetchedResultsChangeDelete`. */ func tableDidChangeSection(sectionIndex: Int, withChangeType type: NSFetchedResultsChangeType) { - switch type { - case .Insert: - tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic) - case .Delete: - tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic) - case .Update: - tableView.reloadSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Automatic) - default: - // FIXME: Figure out what to do with .Move - break - } + switch type { + case .insert: + tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic) + case .delete: + tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic) + case .update: + tableView.reloadSections(IndexSet(integer: sectionIndex), with: .automatic) + default: + // FIXME: Figure out what to do with .Move + break + } } - + /** Method to call in `controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:`. - parameter indexPath: The index path of the changed object (this value is `nil` @@ -203,26 +204,28 @@ public extension FetchedTableList where ListView == UITableView, Cell == UITable - parameter newIndexPath: The destination path for the object for insertions or moves (this value is `nil` for a deletion). */ - func tableDidChangeObjectAtIndexPath(indexPath: NSIndexPath?, - withChangeType type: NSFetchedResultsChangeType, - newIndexPath: NSIndexPath?) { - switch type { - case .Insert: - tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Automatic) - case .Delete: - tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic) - case .Update: - tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: .Automatic) - case .Move: - tableView.moveRowAtIndexPath(indexPath!, toIndexPath: newIndexPath!) - } + func tableDidChangeObject(at indexPath: IndexPath?, + withChangeType type: NSFetchedResultsChangeType, + newIndexPath: IndexPath?) { + switch type { + case .insert: + tableView.insertRows(at: [newIndexPath!], with: .automatic) + case .delete: + tableView.deleteRows(at: [indexPath!], with: .automatic) + case .update: + tableView.reloadRows(at: [indexPath!], with: .automatic) + case .move: + tableView.moveRow(at: indexPath!, to: newIndexPath!) + default: + break + } } - + /** Method to call in `controllerDidChangeContent:` */ func tableDidChangeContent() { - tableView.endUpdates() + tableView.endUpdates() } } @@ -234,31 +237,29 @@ public extension FetchedTableList where ListView == UITableView, Cell == UITable */ public protocol FetchedCollectionList: FetchedList, UICollectionViewDataSource, UICollectionViewDelegate { - // FIXME: collectionView is still an optional on UICollectionViewController - // Update this when Apple updates the Swift interface. /// The collection view to update with the fetched changes. - var collectionView: UICollectionView? { get set } + var collectionView: UICollectionView! { get set } /// Classes that conform to this protocol need only to initialise this /// property. It is an array of block operations used to hold the section /// and row changes so that the collection view can be animated in the same /// way a table view controller handles section changes. - var changeOperations: [NSBlockOperation] { get set } + var changeOperations: [BlockOperation] { get set } } /** Protocol extension to implement the custom source methods. */ public extension FetchedCollectionList where ListView == UICollectionView, - Cell == UICollectionViewCell, Object == AnyObject { + Cell == UICollectionViewCell { /** Cancel the queued up collection view row & section changes. */ func cancelCollectionViewChangeOperations() { - for operation: NSBlockOperation in changeOperations { + for operation: BlockOperation in changeOperations { operation.cancel() } - changeOperations.removeAll(keepCapacity: false) + changeOperations.removeAll(keepingCapacity: false) } } @@ -267,31 +268,31 @@ public extension FetchedCollectionList where ListView == UICollectionView, data source methods. */ public extension FetchedCollectionList where ListView == UICollectionView, - Cell == UICollectionViewCell, Object == AnyObject { + Cell == UICollectionViewCell { /** - Method to call in `collectionView:cellForItemAtIndexPath:`. + Method to call in `collectionView:cellForItemAt:`. - parameter indexPath: The index path that specifies the location of the item. */ - func collectionCellAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewCell { - let identifier = cellIdentifierForIndexPath(indexPath) + func collectionCell(at indexPath: IndexPath) -> UICollectionViewCell { + let identifier = cellIdentifier(for: indexPath) - let cell = collectionView!.dequeueReusableCellWithReuseIdentifier(identifier, - forIndexPath: indexPath) + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, + for: indexPath) - if let object = objectAtIndexPath(indexPath) { - listView(collectionView!, configureCell: cell, withObject: object, atIndexPath: indexPath) + if let object = object(at: indexPath) { + listView(collectionView, configure: cell, with: object, at: indexPath) } return cell } /** - Method to call in `collectionView:didSelectItemAtIndexPath:`. + Method to call in `collectionView:didSelectItemAt:`. - parameter indexPath: The index path of the cell that was selected. */ - func collectionDidSelectItemAtIndexPath(indexPath: NSIndexPath) { - if let object = objectAtIndexPath(indexPath) { - listView(collectionView!, didSelectObject: object, atIndexPath: indexPath) + func collectionDidSelectItem(at indexPath: IndexPath) { + if let object = object(at: indexPath) { + listView(collectionView, didSelect: object, at: indexPath) } } } @@ -301,14 +302,14 @@ public extension FetchedCollectionList where ListView == UICollectionView, sdelegate methods. */ public extension FetchedCollectionList where ListView == UICollectionView, - Cell == UICollectionViewCell, Object == AnyObject { + Cell == UICollectionViewCell { /** Method to call in `controllerWillChangeContent:`. */ func collectionWillChangeContent() { - self.changeOperations.removeAll(keepCapacity: false) + self.changeOperations.removeAll(keepingCapacity: false) } - + /** Method to call in `controller:didChangeSection:atIndex:forChangeType:`. - parameter sectionIndex: The index of the changed section. @@ -317,29 +318,29 @@ public extension FetchedCollectionList where ListView == UICollectionView, */ func collectionDidChangeSection(sectionIndex: Int, withChangeType type: NSFetchedResultsChangeType) { - let indexSet = NSIndexSet(index: sectionIndex) - - switch type { - case .Insert: - changeOperations.append( - NSBlockOperation { [weak self] in - self?.collectionView!.insertSections(indexSet) - }) - case .Update: - changeOperations.append( - NSBlockOperation { [weak self] in - self?.collectionView!.reloadSections(indexSet) - }) - case .Delete: - changeOperations.append( - NSBlockOperation { [weak self] in - self?.collectionView!.deleteSections(indexSet) - }) - default: - break - } + let indexSet = IndexSet(integer: sectionIndex) + + switch type { + case .insert: + changeOperations.append( + BlockOperation { [weak self] in + self?.collectionView!.insertSections(indexSet) + }) + case .update: + changeOperations.append( + BlockOperation { [weak self] in + self?.collectionView!.reloadSections(indexSet) + }) + case .delete: + changeOperations.append( + BlockOperation { [weak self] in + self?.collectionView!.deleteSections(indexSet) + }) + default: + break + } } - + /** Method to call in `controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:`. - parameter indexPath: The index path of the changed object (this value is `nil` @@ -348,47 +349,49 @@ public extension FetchedCollectionList where ListView == UICollectionView, - parameter newIndexPath: The destination path for the object for insertions or moves (this value is `nil` for a deletion). */ - func collectionDidChangeObjectAtIndexPath(indexPath: NSIndexPath?, - withChangeType type: NSFetchedResultsChangeType, - newIndexPath: NSIndexPath?) { - switch type { - case .Insert: - changeOperations.append( - NSBlockOperation { [weak self] in - self?.collectionView!.insertItemsAtIndexPaths([newIndexPath!]) - }) - case .Update: - changeOperations.append( - NSBlockOperation { [weak self] in - self?.collectionView!.reloadItemsAtIndexPaths([indexPath!]) - }) - case .Move: - changeOperations.append( - NSBlockOperation { [weak self] in - self?.collectionView!.moveItemAtIndexPath(indexPath!, toIndexPath: newIndexPath!) - }) - case .Delete: - changeOperations.append( - NSBlockOperation { [weak self] in - self?.collectionView!.deleteItemsAtIndexPaths([indexPath!]) - }) - } + func collectionDidChangeObject(at indexPath: IndexPath?, + withChangeType type: NSFetchedResultsChangeType, + newIndexPath: IndexPath?) { + switch type { + case .insert: + changeOperations.append( + BlockOperation { [weak self] in + self?.collectionView!.insertItems(at: [newIndexPath!]) + }) + case .update: + changeOperations.append( + BlockOperation { [weak self] in + self?.collectionView!.reloadItems(at: [indexPath!]) + }) + case .move: + changeOperations.append( + BlockOperation { [weak self] in + self?.collectionView!.moveItem(at: indexPath!, to: newIndexPath!) + }) + case .delete: + changeOperations.append( + BlockOperation { [weak self] in + self?.collectionView!.deleteItems(at: [indexPath!]) + }) + default: + return + } } - + /** Method to call in `controllerDidChangeContent:` */ func collectionDidChangeContent() { - for section in fetchedResultsController.sections! { - print(section.numberOfObjects) - } - - collectionView!.performBatchUpdates({ - for operation in self.changeOperations { - operation.start() + for section in fetchedResultsController.sections! { + print(section.numberOfObjects) } - }, completion: { [weak self] finished in - self?.changeOperations.removeAll(keepCapacity: false) - }) + + collectionView.performBatchUpdates({ + for operation in self.changeOperations { + operation.start() + } + }, completion: { [weak self] finished in + self?.changeOperations.removeAll(keepingCapacity: false) + }) } } diff --git a/JadKit/Protocols/List.swift b/JadKit/Protocols/List.swift index 522d606..a31c19c 100644 --- a/JadKit/Protocols/List.swift +++ b/JadKit/Protocols/List.swift @@ -40,37 +40,37 @@ import UIKit This protocol outlines the most basic bhaviour that a list should implement. */ public protocol List { - /// The list view for the list (i.e. `UITableView`). - associatedtype ListView - /// The list cell view (i.e. `UITableViewCell`). - associatedtype Cell - /// The object that is tied to each cell. - associatedtype Object - - /** - The cell identifier for the given index path. - - parameter indexPath: The index path of the cell. - - returns: The cell identifier. - */ - func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> String - - /** - Helper method to configure a cell at the given index path with a given - object. - - parameter listView: The list view that is cnofiguring the cell. - - parameter cell: The cell to configure. - - parameter object: The object which matches the cell's index path. - - parameter indexPath: The index path of the cell to configure. - */ - func listView(listView: ListView, configureCell cell: Cell, withObject object: Object, - atIndexPath indexPath: NSIndexPath) - - /** - Called when the user selects a cell at the given index path. - - parameter listView: The list view that is interacted with. - - parameter object: The object at the selected index path. - - parameter indexPath: The index path of the cell which was selected. - */ - func listView(listView: ListView, didSelectObject object: Object, - atIndexPath indexPath: NSIndexPath) + /// The list view for the list (i.e. `UITableView`). + associatedtype ListView + /// The list cell view (i.e. `UITableViewCell`). + associatedtype Cell + /// The object that is tied to each cell. + associatedtype Object + + /** + The cell identifier for the given index path. + - parameter indexPath: The index path of the cell. + - returns: The cell identifier. + */ + func cellIdentifier(for indexPath: IndexPath) -> String + + /** + Helper method to configure a cell at the given index path with a given + object. + - parameter listView: The list view that is cnofiguring the cell. + - parameter cell: The cell to configure. + - parameter object: The object which matches the cell's index path. + - parameter indexPath: The index path of the cell to configure. + */ + func listView(_ listView: ListView, configure cell: Cell, with anObject: Object, + at indexPath: IndexPath) + + /** + Called when the user selects a cell at the given index path. + - parameter listView: The list view that is interacted with. + - parameter object: The object at the selected index path. + - parameter indexPath: The index path of the cell which was selected. + */ + func listView(_ listView: ListView, didSelect anObject: Object, + at indexPath: IndexPath) } diff --git a/JadKit/Protocols/NonFetchedList.swift b/JadKit/Protocols/NonFetchedList.swift index c3b3aa6..b840feb 100644 --- a/JadKit/Protocols/NonFetchedList.swift +++ b/JadKit/Protocols/NonFetchedList.swift @@ -41,62 +41,62 @@ import Foundation rather basic, as all a non-fetched list really needs is a data source. */ public protocol NonFetchedList: List { - /// The list data used to populate the list. This an array to - /// populate the rows. Currently this is limited to a single section. - var listData: [[Object]]! { get set } + /// The list data used to populate the list. This an array to + /// populate the rows. Currently this is limited to a single section. + var listData: [[Object]]! { get set } } /** Protocol extension to implement the basic non fetched list methods. */ public extension NonFetchedList { - /// The number of sections in the `listData`. - var numberOfSections: Int { - return listData?.count ?? 0 - } - - /** - The number of rows in a section of the `listData`. - - parameter section: The section in which the row count will be returned. - - returns: The number of rows in a given section. `0` if the section is - not found. - */ - func numberOfRowsInSection(section: Int) -> Int { - guard listData != nil && section >= 0 && section < listData!.count else { - return 0 + /// The number of sections in the `listData`. + var numberOfSections: Int { + return listData?.count ?? 0 } - return listData![section].count - } - - /** - Convenient helper method to find the object at a given index path. - This method works well with `isValidIndexPath:`. - - note: This method is implemented by a protocol extension if the object - conforms to either `FetchedList` or `NonFetchedList` - - parameter indexPath: The index path to retreive the object for. - - returns: An optional with the corresponding object at an index - path or nil if the index path is invalid. - */ - func objectAtIndexPath(indexPath: NSIndexPath) -> Object? { - guard isValidIndexPath(indexPath) else { - return nil + + /** + The number of rows in a section of the `listData`. + - parameter section: The section in which the row count will be returned. + - returns: The number of rows in a given section. `0` if the section is + not found. + */ + func numberOfRows(inSection section: Int) -> Int { + guard listData != nil && section >= 0 && section < listData!.count else { + return 0 + } + return listData![section].count } - return listData?[indexPath.section][indexPath.row] - } - - /** - Conveneient helper method to ensure that a given index path is valid. - - note: This method is implemented by a protocol extension if the object - conforms to either `FetchedList` or `NonFetchedList` - - parameter indexPath: The index path to check for existance. - - returns: `true` iff the index path is valid for your data source. - */ - func isValidIndexPath(indexPath: NSIndexPath) -> Bool { - guard listData != nil && indexPath.section >= 0 && indexPath.section < listData!.count else { - return false + + /** + Convenient helper method to find the object at a given index path. + This method works well with `isValid:`. + - note: This method is implemented by a protocol extension if the object + conforms to either `FetchedList` or `NonFetchedList` + - parameter indexPath: The index path to retreive the object for. + - returns: An optional with the corresponding object at an index + path or nil if the index path is invalid. + */ + func object(at indexPath: IndexPath) -> Object? { + guard isValid(indexPath) else { + return nil + } + return listData?[indexPath.section][indexPath.row] + } + + /** + Conveneient helper method to ensure that a given index path is valid. + - note: This method is implemented by a protocol extension if the object + conforms to either `FetchedList` or `NonFetchedList` + - parameter indexPath: The index path to check for existance. + - returns: `true` iff the index path is valid for your data source. + */ + func isValid(_ indexPath: IndexPath) -> Bool { + guard listData != nil && indexPath.section >= 0 && indexPath.section < listData!.count else { + return false + } + return indexPath.row >= 0 && indexPath.row < listData![indexPath.section].count } - return indexPath.row >= 0 && indexPath.row < listData![indexPath.section].count - } } // MARK: Table @@ -106,39 +106,39 @@ public extension NonFetchedList { for a valid table view protocol extension implementation. */ public protocol TableList: NonFetchedList, UITableViewDataSource, UITableViewDelegate { - /// The table view that will present the data. - var tableView: UITableView! { get set } + /// The table view that will present the data. + var tableView: UITableView! { get set } } /** Protocol extension to implement the table view delegate & data source methods. */ public extension TableList where ListView == UITableView, Cell == UITableViewCell { - /** - Method to call in `tableView:cellForRowAtIndexPath:`. - - parameter indexPath: An index path locating a row in `tableView` - */ - func tableCellAtIndexPath(indexPath: NSIndexPath) -> UITableViewCell { - let identifier = cellIdentifierForIndexPath(indexPath) - let cell = tableView.dequeueReusableCellWithIdentifier(identifier, - forIndexPath: indexPath) - - if let object = objectAtIndexPath(indexPath) { - listView(tableView, configureCell: cell, withObject: object, atIndexPath: indexPath) + /** + Method to call in `tableView:cellForRowAt:`. + - parameter indexPath: An index path locating a row in `tableView` + */ + func tableCell(at indexPath: IndexPath) -> UITableViewCell { + let identifier = cellIdentifier(for: indexPath) + + let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) + + if let object = object(at: indexPath) { + listView(tableView, configure: cell, with: object, at: indexPath) + } + + return cell } - - return cell - } - - /** - Method to call in `tableView:didSelectRowAtIndexPath:`. - - parameter indexPath: An index path locating the new selected row in `tableView`. - */ - func tableDidSelectItemAtIndexPath(indexPath: NSIndexPath) { - if let object = objectAtIndexPath(indexPath) { - listView(tableView, didSelectObject: object, atIndexPath: indexPath) + + /** + Method to call in `tableView:didSelectRowAt:`. + - parameter indexPath: An index path locating the new selected row in `tableView`. + */ + func tableDidSelectItem(at indexPath: IndexPath) { + if let object = object(at: indexPath) { + listView(tableView, didSelect: object, at: indexPath) + } } - } } // MARK: Collection @@ -147,10 +147,9 @@ public extension TableList where ListView == UITableView, Cell == UITableViewCel Empty protocol to set up the conformance to the various protocols to allow for a valid collection view protocol extension implementation. */ -public protocol CollectionList: NonFetchedList, UICollectionViewDataSource, - UICollectionViewDelegate { +public protocol CollectionList: NonFetchedList, UICollectionViewDataSource, UICollectionViewDelegate { /// The collection view that will present the data. - var collectionView: UICollectionView? { get set } + var collectionView: UICollectionView! { get set } } /** @@ -158,30 +157,29 @@ public protocol CollectionList: NonFetchedList, UICollectionViewDataSource, source methods. */ public extension CollectionList where ListView == UICollectionView, Cell == UICollectionViewCell { - /** - Method to call in `collectionView:cellForItemAtIndexPath:`. - - parameter indexPath: The index path that specifies the location of the item. - */ - func collectionCellAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewCell { - let identifier = cellIdentifierForIndexPath(indexPath) - - let cell = collectionView!.dequeueReusableCellWithReuseIdentifier(identifier, - forIndexPath: indexPath) - - if let object = objectAtIndexPath(indexPath) { - listView(collectionView!, configureCell: cell, withObject: object, atIndexPath: indexPath) + /** + Method to call in `collectionView:cellForItemAt:`. + - parameter indexPath: The index path that specifies the location of the item. + */ + func collectionCell(at indexPath: IndexPath) -> UICollectionViewCell { + let identifier = cellIdentifier(for: indexPath) + + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) + + if let object = object(at: indexPath) { + listView(collectionView, configure: cell, with: object, at: indexPath) + } + + return cell } - - return cell - } - - /** - Method to call in `collectionView:didSelectItemAtIndexPath:`. - - parameter indexPath: The index path of the cell that was selected. - */ - func collectionDidSelectItemAtIndexPath(indexPath: NSIndexPath) { - if let object = objectAtIndexPath(indexPath) { - listView(collectionView!, didSelectObject: object, atIndexPath: indexPath) + + /** + Method to call in `collectionView:didSelectItemAt:`. + - parameter indexPath: The index path of the cell that was selected. + */ + func collectionDidSelectItem(at indexPath: IndexPath) { + if let object = object(at: indexPath) { + listView(collectionView, didSelect: object, at: indexPath) + } } - } -} \ No newline at end of file +} diff --git a/JadKit/Views/PaddedLabel.swift b/JadKit/Views/PaddedLabel.swift index 564e8df..bdccffd 100644 --- a/JadKit/Views/PaddedLabel.swift +++ b/JadKit/Views/PaddedLabel.swift @@ -42,70 +42,69 @@ import UIKit */ @IBDesignable public class PaddedLabel: UILabel { - - /// IB exposed insets that control the padding for the label. - /// - note: `width` translates to the `left` & `right` of the backing `UIEdgeInsets` object - /// and `height` translates to the `top` and `bottom` of that same `UIEdgeInsets` object. - @IBInspectable public var inset: CGSize = CGSize(width: 0.0, height: 0.0) - - /// The driving object that controls the padding for each edge. - public var padding: UIEdgeInsets { - var hasText: Bool = false - - if let text = text?.characters.count where text > 0 { - hasText = true - } else if let text = attributedText?.length where text > 0 { - hasText = true + + /// IB exposed insets that control the padding for the label. + /// - note: `width` translates to the `left` & `right` of the backing `UIEdgeInsets` object + /// and `height` translates to the `top` and `bottom` of that same `UIEdgeInsets` object. + @IBInspectable public var inset: CGSize = CGSize(width: 0.0, height: 0.0) + + /// The driving object that controls the padding for each edge. + public var padding: UIEdgeInsets { + var hasText: Bool = false + + if let text = text?.count, text > 0 { + hasText = true + } else if let text = attributedText?.length, text > 0 { + hasText = true + } + + return hasText ? UIEdgeInsets(top: inset.height, left: inset.width, + bottom: inset.height, right: inset.width) : UIEdgeInsets() + } + + public override func drawText(in rect: CGRect) { + super.drawText(in: rect.inset(by: padding)) + } + + // FIXME: This is still not perfect. Spend some time trying to understand it. + public override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect { + var rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines) + + if let text = text { + let estimatedWidth = CGRectGetWidth(rect) - (2 * (padding.left + padding.right)) + let estimatedHeight = CGFloat.greatestFiniteMagnitude + + let boundingSize = CGSize(width: estimatedWidth, height: estimatedHeight) + let calculatedFrame = text.boundingRect(with: boundingSize, + options: .usesLineFragmentOrigin, + attributes: [.font : font as Any], + context: nil) + + let calculatedWidth = ceil(CGRectGetWidth(calculatedFrame)) + let calculatedHeight = ceil(CGRectGetHeight(calculatedFrame)) + + // let finalHeight = (calculatedHeight + padding.top + padding.bottom) + rect.size = CGSize(width: calculatedWidth, height: calculatedHeight) + } + + return rect + } + + public override var intrinsicContentSize: CGSize { + let superContentSize = super.intrinsicContentSize + + let width = superContentSize.width + padding.left + padding.right + let heigth = superContentSize.height + padding.top + padding.bottom + + return CGSize(width: width, height: heigth) + } + + public override func sizeThatFits(_ size: CGSize) -> CGSize { + let superSizeThatFits = super.sizeThatFits(size) + + let width = superSizeThatFits.width + padding.left + padding.right + let heigth = superSizeThatFits.height + padding.top + padding.bottom + + return CGSize(width: width, height: heigth) } - - return hasText ? UIEdgeInsets(top: inset.height, left: inset.width, - bottom: inset.height, right: inset.width) : UIEdgeInsets() - } - - public override func drawTextInRect(rect: CGRect) { - super.drawTextInRect(UIEdgeInsetsInsetRect(rect, padding)) - } - - // FIXME: This is still not perfect. Spend some time trying to understand it. - public override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) - -> CGRect { - var rect = super.textRectForBounds(bounds, limitedToNumberOfLines: numberOfLines) - - if let text = text { - let estimatedWidth = CGRectGetWidth(rect) - (2 * (padding.left + padding.right)) - let estimatedHeight = CGFloat.max - - let boundingSize = CGSize(width: estimatedWidth, height: estimatedHeight) - let calculatedFrame = text.boundingRectWithSize(boundingSize, - options: .UsesLineFragmentOrigin, - attributes: [NSFontAttributeName : font], - context: nil) - - let calculatedWidth = ceil(CGRectGetWidth(calculatedFrame)) - let calculatedHeight = ceil(CGRectGetHeight(calculatedFrame)) - - // let finalHeight = (calculatedHeight + padding.top + padding.bottom) - rect.size = CGSize(width: calculatedWidth, height: calculatedHeight) - } - - return rect - } - - public override func intrinsicContentSize() -> CGSize { - let superContentSize = super.intrinsicContentSize() - - let width = superContentSize.width + padding.left + padding.right - let heigth = superContentSize.height + padding.top + padding.bottom - - return CGSize(width: width, height: heigth) - } - - public override func sizeThatFits(size: CGSize) -> CGSize { - let superSizeThatFits = super.sizeThatFits(size) - - let width = superSizeThatFits.width + padding.left + padding.right - let heigth = superSizeThatFits.height + padding.top + padding.bottom - - return CGSize(width: width, height: heigth) - } } diff --git a/JadKitTests/JadKitTests.swift b/JadKitTests/JadKitTests.swift index 7dcd60a..cd589f3 100644 --- a/JadKitTests/JadKitTests.swift +++ b/JadKitTests/JadKitTests.swift @@ -15,187 +15,180 @@ let testReuseIdentifier = "Identifier" private(set) var testManagedObjectContext: NSManagedObjectContext! private func setUpCoreData() { - let bundles = [NSBundle(forClass: JadKitTests.self)] - guard let model = NSManagedObjectModel.mergedModelFromBundles(bundles) else { - fatalError("Model not found") - } - - let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model) - try! persistentStoreCoordinator.addPersistentStoreWithType(NSInMemoryStoreType, - configuration: nil, URL: nil, options: nil) - - let managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType) - managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator - - testManagedObjectContext = managedObjectContext + let bundles = [Bundle(for: JadKitTests.self)] + guard let model = NSManagedObjectModel.mergedModel(from: bundles) else { + fatalError("Model not found") + } + + let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model) + try! persistentStoreCoordinator.addPersistentStore(ofType: NSInMemoryStoreType, + configurationName: nil, at: nil, options: nil) + + let managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) + managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator + + testManagedObjectContext = managedObjectContext } private func tearDownCoreData() { - testManagedObjectContext.reset() - - let fetchRequest = NSFetchRequest(entityName: TestObject.entityName) - - do { - let fetchedObjects = try testManagedObjectContext.executeFetchRequest(fetchRequest) - as! [TestObject] - for fetchedObject in fetchedObjects { - testManagedObjectContext.deleteObject(fetchedObject) + testManagedObjectContext.reset() + + let fetchRequest = NSFetchRequest() + + do { + let fetchedObjects = try testManagedObjectContext.fetch(fetchRequest) + for fetchedObject in fetchedObjects { + testManagedObjectContext.delete(fetchedObject) + } + } catch let error { + XCTFail("\(error)") } - } catch let error { - XCTFail("\(error)") - } - - saveCoreData() + + saveCoreData() } private func saveCoreData() { - do { - try testManagedObjectContext.save() - } catch let error { - XCTFail("\(error)") - } -} - -class JadKitTests: XCTestCase { - var listData: [[TestObject]]! - - var fetchedResultsController: NSFetchedResultsController! - - override func setUp() { - super.setUp() - - setUpCoreData() - - listData = [[TestObject(color: UIColor.blueColor()), TestObject(color: UIColor.whiteColor()), - TestObject(color: UIColor.redColor())], [TestObject(color: UIColor.blackColor())]] - - let fetchRequest = NSFetchRequest(entityName: TestObject.entityName) - fetchRequest.sortDescriptors = [NSSortDescriptor(key: "sectionName", ascending: true)] - fetchRequest.predicate = NSPredicate(value: true) - - fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, - managedObjectContext: testManagedObjectContext, sectionNameKeyPath: "sectionName", - cacheName: nil) - } - - override func tearDown() { - tearDownCoreData() - - super.tearDown() - } - - func performFetch() { do { - try fetchedResultsController.performFetch() + try testManagedObjectContext.save() } catch let error { - XCTFail("\(error)") + XCTFail("\(error)") } - } - - func insertAndSaveObjects(numObjects: Int, sectionName: String) { - for _ in 0..! + + override func setUp() { + super.setUp() + + setUpCoreData() + + listData = [[TestObject(color: UIColor.blue), TestObject(color: UIColor.white), + TestObject(color: UIColor.red)], [TestObject(color: UIColor.black)]] + + let fetchRequest = NSFetchRequest(entityName: TestObject.entityName) + fetchRequest.sortDescriptors = [NSSortDescriptor(key: "sectionName", ascending: true)] + fetchRequest.predicate = NSPredicate(value: true) + + fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, + managedObjectContext: testManagedObjectContext, sectionNameKeyPath: "sectionName", + cacheName: nil) } - - saveCoreData() - } - - func addAndSaveObject(color: UIColor, sectionName: String) { - insertObject(color, sectionName: sectionName) - saveCoreData() - } - - func updateAndSaveObject(forName name: String, updateClosure: (object: TestObject) -> Void) { - let request = NSFetchRequest(entityName: TestObject.entityName) - request.predicate = NSPredicate(format: "name == %@", name) - - do { - guard let foundObject = try testManagedObjectContext.executeFetchRequest(request).first - as? TestObject else { - XCTFail() - return + + override func tearDown() { + tearDownCoreData() + + super.tearDown() + } + + func performFetch() { + do { + try fetchedResultsController.performFetch() + } catch let error { + XCTFail("\(error)") } - - // Let the updater do its thing. - updateClosure(object: foundObject) - // Save after the update. + } + + func insertAndSaveObjects(_ numObjects: Int, sectionName: String) { + for _ in 0.. Void) { + let request = NSFetchRequest(entityName: TestObject.entityName) + request.predicate = NSPredicate(format: "name == %@", name) + + do { + guard let foundObject = try testManagedObjectContext.fetch(request).first else { + XCTFail() + return + } + + // Let the updater do its thing. + updateClosure(foundObject) + // Save after the update. + saveCoreData() + } catch let error { + XCTFail("\(error)") + } + } + + func deleteAndSaveObject(_ object: TestObject) { + testManagedObjectContext.delete(object) + saveCoreData() + } + + func deleteAndSaveSectionName(_ sectionName: String) { + let request = NSFetchRequest(entityName: TestObject.entityName) + request.predicate = NSPredicate(format: "sectionName == %@", sectionName) + + do { + let foundObjects = try testManagedObjectContext.fetch(request) + for foundObject in foundObjects { + testManagedObjectContext.delete(foundObject) + } + + saveCoreData() + } catch let error { + XCTFail("\(error)") + } + } + + private func insertObject(color: UIColor, sectionName: String) { + let object = NSEntityDescription.insertNewObject(forEntityName: TestObject.entityName, + into: testManagedObjectContext) as! TestObject + + object.name = NSUUID().uuidString + object.sectionName = sectionName + object.color = color + } } class TestObject: NSManagedObject { - @NSManaged var name: String - @NSManaged var color: UIColor - @NSManaged var sectionName: String? - - private class var entityName: String { - return "TestObject" - } - - private class var entityDescription: NSEntityDescription { - return NSEntityDescription.entityForName(entityName, - inManagedObjectContext: testManagedObjectContext)! - } - - convenience init(color: UIColor) { - self.init(entity: TestObject.entityDescription, insertIntoManagedObjectContext: nil) - - self.name = NSUUID().UUIDString - self.color = color - } + @NSManaged var name: String + @NSManaged var color: UIColor + @NSManaged var sectionName: String? + + class var entityName: String { + return "TestObject" + } + + private class var entityDescription: NSEntityDescription { + return NSEntityDescription.entity(forEntityName: entityName, + in: testManagedObjectContext)! + } + + convenience init(color: UIColor) { + self.init(entity: TestObject.entityDescription, insertInto: nil) + + self.name = NSUUID().uuidString + self.color = color + } } diff --git a/JadKitTests/JadKitTests.xcdatamodeld/JadKitTests.xcdatamodel/contents b/JadKitTests/JadKitTests.xcdatamodeld/JadKitTests.xcdatamodel/contents index ba7f207..b4ec3d4 100644 --- a/JadKitTests/JadKitTests.xcdatamodeld/JadKitTests.xcdatamodel/contents +++ b/JadKitTests/JadKitTests.xcdatamodeld/JadKitTests.xcdatamodel/contents @@ -1,11 +1,8 @@ - + - + - - - \ No newline at end of file diff --git a/JadKitTests/Protocols/CollectionListTests.swift b/JadKitTests/Protocols/CollectionListTests.swift index 923040f..4ffefd7 100644 --- a/JadKitTests/Protocols/CollectionListTests.swift +++ b/JadKitTests/Protocols/CollectionListTests.swift @@ -12,104 +12,104 @@ import XCTest @testable import JadKit class CollectionListTests: JadKitTests { - private var collectionViewController: CollectionListViewController! - - private var collectionView: UICollectionView { - return collectionViewController.collectionView! - } - - override func setUp() { - super.setUp() - - collectionViewController = CollectionListViewController( - collectionViewLayout: UICollectionViewFlowLayout()) - collectionViewController.listData = listData - - collectionView.registerClass(UICollectionViewCell.self, - forCellWithReuseIdentifier: testReuseIdentifier) - } - - override func tearDown() { - // Make sure our list controller and view are always in sync. - testListRowsAndSections() - - super.tearDown() - } - - func testListRowsAndSections() { - XCTAssertEqual(collectionView.numberOfSections(), collectionViewController.numberOfSections) - - for section in 0.. String { - return testReuseIdentifier - } - - func listView(listView: UICollectionView, configureCell cell: UICollectionViewCell, - withObject object: TestObject, atIndexPath indexPath: NSIndexPath) { - cell.backgroundColor = object.color - } - - func listView(listView: UICollectionView, didSelectObject object: TestObject, - atIndexPath indexPath: NSIndexPath) { - selectedCellIndexPaths.append(indexPath) - } - - // MARK: Collection View - - override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { - return numberOfSections - } - - override func collectionView(collectionView: UICollectionView, - numberOfItemsInSection section: Int) -> Int { - return numberOfRowsInSection(section) - } - - override func collectionView(collectionView: UICollectionView, - cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { - return collectionCellAtIndexPath(indexPath) - } - - override func collectionView(collectionView: UICollectionView, - didSelectItemAtIndexPath indexPath: NSIndexPath) { - collectionDidSelectItemAtIndexPath(indexPath) - } -} \ No newline at end of file + + var listData: [[TestObject]]! + var selectedCellIndexPaths = [IndexPath]() + + func cellIdentifier(for indexPath: IndexPath) -> String { + return testReuseIdentifier + } + + func listView(_ listView: UICollectionView, configure cell: UICollectionViewCell, + with anObject: TestObject, at indexPath: IndexPath) { + cell.backgroundColor = anObject.color + } + + func listView(_ listView: UICollectionView, didSelect anObject: TestObject, + at indexPath: IndexPath) { + selectedCellIndexPaths.append(indexPath) + } + + + + // MARK: Collection View + override func numberOfSections(in collectionView: UICollectionView) -> Int { + return numberOfSections + } + + override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return numberOfRows(inSection: section) + } + + override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + return collectionCell(at: indexPath) + } + + override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + collectionDidSelectItem(at: indexPath) + } +} diff --git a/JadKitTests/Protocols/FetchedCollectionListTests.swift b/JadKitTests/Protocols/FetchedCollectionListTests.swift index cba7a62..643ec73 100644 --- a/JadKitTests/Protocols/FetchedCollectionListTests.swift +++ b/JadKitTests/Protocols/FetchedCollectionListTests.swift @@ -13,225 +13,221 @@ import XCTest @testable import JadKit class FetchedCollectionListTests: JadKitTests { - private var collectionViewController: FetchedCollectionListViewController! - - private var collectionView: UICollectionView { - return collectionViewController.collectionView! - } - - override func setUp() { - super.setUp() - - collectionViewController = FetchedCollectionListViewController( - collectionViewLayout: UICollectionViewFlowLayout()) - collectionViewController.fetchedResultsController = fetchedResultsController - - collectionView.registerClass(UICollectionViewCell.self, - forCellWithReuseIdentifier: testReuseIdentifier) - - insertAndSaveObjects(10, sectionName: "First") - insertAndSaveObjects(5, sectionName: "Second") - - performFetch() - } - - override func tearDown() { - // Make sure our list controller and view are always in sync. - testListRowsAndSections() - - super.tearDown() - } - - func testListRowsAndSections() { - XCTAssertEqual(collectionView.numberOfSections(), collectionViewController.numberOfSections) - - for section in 0.. String { - return testReuseIdentifier - } - - func listView(listView: UICollectionView, configureCell cell: UICollectionViewCell, - withObject object: AnyObject, atIndexPath indexPath: NSIndexPath) { - if let testObject = object as? TestObject { - cell.backgroundColor = testObject.color + FetchedCollectionList { + + + + var changeOperations: [BlockOperation] = [] + + + var fetchedResultsController: NSFetchedResultsController! { + didSet { + fetchedResultsController.delegate = self } } - - func listView(listView: UICollectionView, didSelectObject object: AnyObject, - atIndexPath indexPath: NSIndexPath) { + + var selectedCellIndexPaths = [IndexPath]() + + func cellIdentifier(for indexPath: IndexPath) -> String { + return testReuseIdentifier + } + + func listView(_ listView: UICollectionView, configure cell: UICollectionViewCell, + with anObject: TestObject, at indexPath: IndexPath) { + // if let testObject = anObject as? TestObject { + cell.backgroundColor = anObject.color + // } + } + + func listView(_ listView: UICollectionView, didSelect anObject: TestObject, + at indexPath: IndexPath) { selectedCellIndexPaths.append(indexPath) } - + // MARK: Collection View - - override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { - return numberOfSections - } - - override func collectionView(collectionView: UICollectionView, - numberOfItemsInSection section: Int) -> Int { - return numberOfRowsInSection(section) - } - - override func collectionView(collectionView: UICollectionView, - cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { - return collectionCellAtIndexPath(indexPath) - } - - override func collectionView(collectionView: UICollectionView, - didSelectItemAtIndexPath indexPath: NSIndexPath) { - collectionDidSelectItemAtIndexPath(indexPath) - } - + + override func numberOfSections(in collectionView: UICollectionView) -> Int { + return numberOfSections + } + + override func collectionView(_ collectionView: UICollectionView, + numberOfItemsInSection section: Int) -> Int { + return numberOfRows(inSection: section) + } + + override func collectionView(_ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + return collectionCell(at: indexPath) + } + + override func collectionView(_ collectionView: UICollectionView, + didSelectItemAt indexPath: IndexPath) { + collectionDidSelectItem(at: indexPath) + } + // MARK: Fetched Controller - - @objc func controllerWillChangeContent(controller: NSFetchedResultsController) { - collectionWillChangeContent() - } - - @objc func controller(controller: NSFetchedResultsController, - didChangeSection sectionInfo: NSFetchedResultsSectionInfo, - atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { - collectionDidChangeSection(sectionIndex, withChangeType: type) - } - - @objc func controller(controller: NSFetchedResultsController, - didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, - forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { - collectionDidChangeObjectAtIndexPath(indexPath, withChangeType: type, - newIndexPath: newIndexPath) - } - - @objc func controllerDidChangeContent(controller: NSFetchedResultsController) { - collectionDidChangeContent() + + @objc func controllerWillChangeContent(_ controller: NSFetchedResultsController) { + collectionWillChangeContent() + } + + @objc func controller(_ controller: NSFetchedResultsController, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) { + collectionDidChangeSection(sectionIndex: sectionIndex, withChangeType: type) + } + + @objc func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { + collectionDidChangeObject(at: indexPath, withChangeType: type, + newIndexPath: newIndexPath) + } + + @objc func controllerDidChangeContent(_ controller: NSFetchedResultsController) { + collectionDidChangeContent() } } diff --git a/JadKitTests/Protocols/FetchedListTests.swift b/JadKitTests/Protocols/FetchedListTests.swift index 48ac107..e479a06 100644 --- a/JadKitTests/Protocols/FetchedListTests.swift +++ b/JadKitTests/Protocols/FetchedListTests.swift @@ -31,54 +31,54 @@ class FetchedListTests: JadKitTests, FetchedList { XCTAssertEqual(numberOfSections, sections.count) for sectionIndex in 0.. String { + func cellIdentifier(for indexPath: IndexPath) -> String { return testReuseIdentifier } - func listView(listView: ListView, configureCell cell: Cell, withObject object: Object, - atIndexPath indexPath: NSIndexPath) { } + func listView(_ listView: ListView, configure cell: Cell, with anObject: Object, + at indexPath: IndexPath) { } - func listView(listView: ListView, didSelectObject object: Object, - atIndexPath indexPath: NSIndexPath) { } + func listView(_ listView: ListView, didSelect anObject: Object, + at indexPath: IndexPath) { } } diff --git a/JadKitTests/Protocols/FetchedTableListTests.swift b/JadKitTests/Protocols/FetchedTableListTests.swift index 9aea453..be80b8c 100644 --- a/JadKitTests/Protocols/FetchedTableListTests.swift +++ b/JadKitTests/Protocols/FetchedTableListTests.swift @@ -13,211 +13,203 @@ import XCTest @testable import JadKit class FetchedTableListTests: JadKitTests { - private var tableViewController: FetchedTableListViewController! - - private var tableView: UITableView { - return tableViewController.tableView - } - - override func setUp() { - super.setUp() - - tableViewController = FetchedTableListViewController(style: .Plain) - tableViewController.fetchedResultsController = fetchedResultsController - - tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: testReuseIdentifier) - - insertAndSaveObjects(10, sectionName: "First") - insertAndSaveObjects(5, sectionName: "Second") - - performFetch() - } - - override func tearDown() { - // Make sure our list controller and view are always in sync. - testListRowsAndSections() - - super.tearDown() - } - - func testListRowsAndSections() { - XCTAssertEqual(tableView.numberOfSections, tableViewController.numberOfSections) - - for section in 0..! { + didSet { + fetchedResultsController.delegate = self + } + } + + var selectedCellIndexPaths = [IndexPath]() + + func cellIdentifier(for indexPath: IndexPath) -> String { + return testReuseIdentifier + } + + func listView(_ listView: UITableView, configure cell: UITableViewCell, + with anObject: TestObject, at indexPath: IndexPath) { + cell.textLabel?.text = anObject.name + } + + func listView(_ listView: UITableView, didSelect anObject: TestObject, + at indexPath: IndexPath) { + selectedCellIndexPaths.append(indexPath) + } + + // MARK: Table View + + override func numberOfSections(in tableView: UITableView) -> Int { + return numberOfSections + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return numberOfRows(inSection: section) + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + return tableCell(at: indexPath) + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableDidSelectItem(at: indexPath) + } + + // MARK: Fetched Controller + + @objc func controllerWillChangeContent(_ controller: NSFetchedResultsController) { + tableWillChangeContent() + } + + @objc func controller(_ controller: NSFetchedResultsController, + didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, + for type: NSFetchedResultsChangeType) { + tableDidChangeSection(sectionIndex: sectionIndex, withChangeType: type) + } + + @objc func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { + tableDidChangeObject(at: indexPath, withChangeType: type, newIndexPath: newIndexPath) + } + + @objc func controllerDidChangeContent(_ controller: NSFetchedResultsController) { + tableDidChangeContent() } - } - - var selectedCellIndexPaths = [NSIndexPath]() - - func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> String { - return testReuseIdentifier - } - - func listView(listView: UITableView, configureCell cell: UITableViewCell, - withObject object: AnyObject, atIndexPath indexPath: NSIndexPath) { - if let testObject = object as? TestObject { - cell.textLabel?.text = testObject.name - } - } - - func listView(listView: UITableView, didSelectObject object: AnyObject, - atIndexPath indexPath: NSIndexPath) { - selectedCellIndexPaths.append(indexPath) - } - - // MARK: Table View - - override func numberOfSectionsInTableView(tableView: UITableView) -> Int { - return numberOfSections - } - - override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return numberOfRowsInSection(section) - } - - override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) - -> UITableViewCell { - return tableCellAtIndexPath(indexPath) - } - - override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { - tableDidSelectItemAtIndexPath(indexPath) - } - - // MARK: Fetched Controller - - @objc func controllerWillChangeContent(controller: NSFetchedResultsController) { - tableWillChangeContent() - } - - @objc func controller(controller: NSFetchedResultsController, - didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, - forChangeType type: NSFetchedResultsChangeType) { - tableDidChangeSection(sectionIndex, withChangeType: type) - } - - @objc func controller(controller: NSFetchedResultsController, - didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, - forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { - tableDidChangeObjectAtIndexPath(indexPath, withChangeType: type, newIndexPath: newIndexPath) - } - - @objc func controllerDidChangeContent(controller: NSFetchedResultsController) { - tableDidChangeContent() - } } diff --git a/JadKitTests/Protocols/NonFetchedListTests.swift b/JadKitTests/Protocols/NonFetchedListTests.swift index 2381108..ebd9b5d 100644 --- a/JadKitTests/Protocols/NonFetchedListTests.swift +++ b/JadKitTests/Protocols/NonFetchedListTests.swift @@ -19,7 +19,7 @@ class NonFetchedListTests: JadKitTests, NonFetchedList { func testObjectAtValidIndexPaths() { for section in 0.. String { + func cellIdentifier(for indexPath: IndexPath) -> String { return testReuseIdentifier } - func listView(listView: ListView, configureCell cell: Cell, withObject object: Object, - atIndexPath indexPath: NSIndexPath) { } + func listView(_ listView: ListView, configure cell: Cell, with anObject: Object, + at indexPath: IndexPath) { } - func listView(listView: ListView, didSelectObject object: Object, - atIndexPath indexPath: NSIndexPath) { } + func listView(_ listView: ListView, didSelect anObject: Object, + at indexPath: IndexPath) { } } diff --git a/JadKitTests/Protocols/TableListTests.swift b/JadKitTests/Protocols/TableListTests.swift index 134b454..f21baa4 100644 --- a/JadKitTests/Protocols/TableListTests.swift +++ b/JadKitTests/Protocols/TableListTests.swift @@ -38,17 +38,17 @@ class TableListTests: JadKitTests { XCTAssertEqual(tableView.numberOfSections, tableViewController.numberOfSections) for section in 0.. String { + func cellIdentifier(for indexPath: IndexPath) -> String { return testReuseIdentifier } - func listView(listView: UITableView, configureCell cell: UITableViewCell, - withObject object: TestObject, atIndexPath indexPath: NSIndexPath) { + func listView(_ listView: UITableView, configure cell: UITableViewCell, + with anObject: TestObject, at indexPath: IndexPath) { cell.textLabel?.text = object.name } - func listView(listView: UITableView, didSelectObject object: TestObject, - atIndexPath indexPath: NSIndexPath) { + func listView(_ listView: UITableView, didSelect anObject: TestObject, + at indexPath: IndexPath) { selectedCellIndexPaths.append(indexPath) } // MARK: Table View - override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + override func numberOfSections(in: tableView: UITableView) -> Int { return numberOfSections } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return numberOfRowsInSection(section) + return numberOfRows(inSection: section) } - override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) + override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell { - return tableCellAtIndexPath(indexPath) + return tableCell(at: indexPath) } - override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { - tableDidSelectItemAtIndexPath(indexPath) + override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) { + tableDidSelectItem(at: indexPath) } } From f2d6b597f6a5af7117db77441be8d9c501925bf5 Mon Sep 17 00:00:00 2001 From: Malcolm Hall Date: Thu, 18 Jan 2024 00:20:45 +0000 Subject: [PATCH 2/4] More tidying --- JadKit/Protocols/FetchedList.swift | 8 +- .../Protocols/FetchedTableListTests.swift | 2 +- .../Protocols/NonFetchedListTests.swift | 112 +++++++++--------- JadKitTests/Protocols/TableListTests.swift | 72 +++++------ 4 files changed, 97 insertions(+), 97 deletions(-) diff --git a/JadKit/Protocols/FetchedList.swift b/JadKit/Protocols/FetchedList.swift index 99b313e..b9bf73e 100644 --- a/JadKit/Protocols/FetchedList.swift +++ b/JadKit/Protocols/FetchedList.swift @@ -182,14 +182,14 @@ public extension FetchedTableList where ListView == UITableView, Cell == UITable - parameter type: The type of change (insert or delete). Valid values are `NSFetchedResultsChangeInsert` and `NSFetchedResultsChangeDelete`. */ - func tableDidChangeSection(sectionIndex: Int, withChangeType type: NSFetchedResultsChangeType) { + func tableDidChange(section: Int, withChangeType type: NSFetchedResultsChangeType) { switch type { case .insert: - tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic) + tableView.insertSections(IndexSet(integer: section), with: .automatic) case .delete: - tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic) + tableView.deleteSections(IndexSet(integer: section), with: .automatic) case .update: - tableView.reloadSections(IndexSet(integer: sectionIndex), with: .automatic) + tableView.reloadSections(IndexSet(integer: section), with: .automatic) default: // FIXME: Figure out what to do with .Move break diff --git a/JadKitTests/Protocols/FetchedTableListTests.swift b/JadKitTests/Protocols/FetchedTableListTests.swift index be80b8c..bfb7ce4 100644 --- a/JadKitTests/Protocols/FetchedTableListTests.swift +++ b/JadKitTests/Protocols/FetchedTableListTests.swift @@ -202,7 +202,7 @@ private class FetchedTableListViewController: UITableViewController, FetchedTabl @objc func controller(_ controller: NSFetchedResultsController, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) { - tableDidChangeSection(sectionIndex: sectionIndex, withChangeType: type) + tableDidChange(section: sectionIndex, withChangeType: type) } @objc func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { diff --git a/JadKitTests/Protocols/NonFetchedListTests.swift b/JadKitTests/Protocols/NonFetchedListTests.swift index ebd9b5d..1bb8b78 100644 --- a/JadKitTests/Protocols/NonFetchedListTests.swift +++ b/JadKitTests/Protocols/NonFetchedListTests.swift @@ -12,63 +12,63 @@ import XCTest @testable import JadKit class NonFetchedListTests: JadKitTests, NonFetchedList { - typealias ListView = UIView - typealias Cell = UIView - typealias Object = TestObject - - func testObjectAtValidIndexPaths() { - for section in 0.. String { - return testReuseIdentifier - } - - func listView(_ listView: ListView, configure cell: Cell, with anObject: Object, - at indexPath: IndexPath) { } - - func listView(_ listView: ListView, didSelect anObject: Object, - at indexPath: IndexPath) { } + + func testValidIndexPath() { + XCTAssertTrue(isValid(IndexPath(row: 0, section: 1))) + } + + func testInvalidIndexPath() { + XCTAssertFalse(isValid(IndexPath(row: 1, section: 10))) + } + + func testObjectAtIndexPathSectionTooBig() { + XCTAssertNil(object(at: IndexPath(row: 0, section: 2))) + } + + func testObjectAtIndexPathSectionTooSmall() { + XCTAssertNil(object(at: IndexPath(row: 0, section: -1))) + } + + func testObjectAtIndexPathRowTooBig() { + XCTAssertNil(object(at: IndexPath(row: 10, section: 0))) + } + + func testObjectAtIndexPathRowTooSmall() { + XCTAssertNil(object(at: IndexPath(row: -1, section: 0))) + } + + // MARK: Conformance + + func cellIdentifier(for indexPath: IndexPath) -> String { + return testReuseIdentifier + } + + func listView(_ listView: ListView, configure cell: Cell, with anObject: Object, + at indexPath: IndexPath) { } + + func listView(_ listView: ListView, didSelect anObject: Object, + at indexPath: IndexPath) { } } diff --git a/JadKitTests/Protocols/TableListTests.swift b/JadKitTests/Protocols/TableListTests.swift index f21baa4..9a8f1f7 100644 --- a/JadKitTests/Protocols/TableListTests.swift +++ b/JadKitTests/Protocols/TableListTests.swift @@ -21,10 +21,10 @@ class TableListTests: JadKitTests { override func setUp() { super.setUp() - tableViewController = TableListViewController(style: .Plain) + tableViewController = TableListViewController(style: .plain) tableViewController.listData = listData - tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: testReuseIdentifier) + tableView.register(UITableViewCell.self, forCellReuseIdentifier: testReuseIdentifier) } override func tearDown() { @@ -71,39 +71,39 @@ class TableListTests: JadKitTests { } private class TableListViewController: UITableViewController, TableList { - var listData: [[TestObject]]! - var selectedCellIndexPaths = [IndexPath]() - - func cellIdentifier(for indexPath: IndexPath) -> String { - return testReuseIdentifier - } - - func listView(_ listView: UITableView, configure cell: UITableViewCell, - with anObject: TestObject, at indexPath: IndexPath) { - cell.textLabel?.text = object.name - } - - func listView(_ listView: UITableView, didSelect anObject: TestObject, - at indexPath: IndexPath) { - selectedCellIndexPaths.append(indexPath) - } - - // MARK: Table View - - override func numberOfSections(in: tableView: UITableView) -> Int { - return numberOfSections - } - - override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return numberOfRows(inSection: section) - } - - override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) + var listData: [[TestObject]]! + var selectedCellIndexPaths = [IndexPath]() + + func cellIdentifier(for indexPath: IndexPath) -> String { + return testReuseIdentifier + } + + func listView(_ listView: UITableView, configure cell: UITableViewCell, + with anObject: TestObject, at indexPath: IndexPath) { + cell.textLabel?.text = anObject.name + } + + func listView(_ listView: UITableView, didSelect anObject: TestObject, + at indexPath: IndexPath) { + selectedCellIndexPaths.append(indexPath) + } + + // MARK: Table View + + override func numberOfSections(in tableView: UITableView) -> Int { + return numberOfSections + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return numberOfRows(inSection: section) + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return tableCell(at: indexPath) - } - - override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) { - tableDidSelectItem(at: indexPath) - } + return tableCell(at: indexPath) + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableDidSelectItem(at: indexPath) + } } From 5eaa874c6d9131d4e6493c559cac1ac3d877feb9 Mon Sep 17 00:00:00 2001 From: Malcolm Hall Date: Thu, 18 Jan 2024 00:42:37 +0000 Subject: [PATCH 3/4] Small change --- JadKit/Protocols/FetchedList.swift | 2 +- JadKitTests/Protocols/FetchedTableListTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/JadKit/Protocols/FetchedList.swift b/JadKit/Protocols/FetchedList.swift index b9bf73e..87039b6 100644 --- a/JadKit/Protocols/FetchedList.swift +++ b/JadKit/Protocols/FetchedList.swift @@ -182,7 +182,7 @@ public extension FetchedTableList where ListView == UITableView, Cell == UITable - parameter type: The type of change (insert or delete). Valid values are `NSFetchedResultsChangeInsert` and `NSFetchedResultsChangeDelete`. */ - func tableDidChange(section: Int, withChangeType type: NSFetchedResultsChangeType) { + func tableDidChangeSection(_ section: Int, withChangeType type: NSFetchedResultsChangeType) { switch type { case .insert: tableView.insertSections(IndexSet(integer: section), with: .automatic) diff --git a/JadKitTests/Protocols/FetchedTableListTests.swift b/JadKitTests/Protocols/FetchedTableListTests.swift index bfb7ce4..76c0604 100644 --- a/JadKitTests/Protocols/FetchedTableListTests.swift +++ b/JadKitTests/Protocols/FetchedTableListTests.swift @@ -202,7 +202,7 @@ private class FetchedTableListViewController: UITableViewController, FetchedTabl @objc func controller(_ controller: NSFetchedResultsController, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) { - tableDidChange(section: sectionIndex, withChangeType: type) + tableDidChangeSection(sectionIndex, withChangeType: type) } @objc func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { From 475d63e9b9a3896a2306373fcf749ff0e6a6673f Mon Sep 17 00:00:00 2001 From: Malcolm Hall Date: Thu, 18 Jan 2024 00:51:02 +0000 Subject: [PATCH 4/4] Small fix to inSection func --- JadKit/Protocols/FetchedList.swift | 2 +- JadKitTests/Protocols/FetchedListTests.swift | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/JadKit/Protocols/FetchedList.swift b/JadKit/Protocols/FetchedList.swift index 87039b6..1df1dc2 100644 --- a/JadKit/Protocols/FetchedList.swift +++ b/JadKit/Protocols/FetchedList.swift @@ -114,7 +114,7 @@ public extension FetchedList { - parameter section: The section for the header's title to grab. - returns: The header title for the section or `nil` if none is found. */ - func titleForHeaderInSection(section: Int) -> String? { + func titleForHeader(inSection section: Int) -> String? { guard isValid(IndexPath(row: 0, section: section)) else { return nil } diff --git a/JadKitTests/Protocols/FetchedListTests.swift b/JadKitTests/Protocols/FetchedListTests.swift index e479a06..e9fe52d 100644 --- a/JadKitTests/Protocols/FetchedListTests.swift +++ b/JadKitTests/Protocols/FetchedListTests.swift @@ -61,13 +61,13 @@ class FetchedListTests: JadKitTests, FetchedList { } func testValidSectionNames() { - XCTAssertEqual(titleForHeaderInSection(section: 0), "First") - XCTAssertEqual(titleForHeaderInSection(section: 1), "Second") + XCTAssertEqual(titleForHeader(inSection:0), "First") + XCTAssertEqual(titleForHeader(inSection:1), "Second") } func testInvalidSectionNames() { - XCTAssertNil(titleForHeaderInSection(section: 2)) - XCTAssertNil(titleForHeaderInSection(section: -2)) + XCTAssertNil(titleForHeader(inSection:2)) + XCTAssertNil(titleForHeader(inSection:-2)) } // MARK: Conformance