diff --git a/Buffer.xcodeproj/project.pbxproj b/Buffer.xcodeproj/project.pbxproj index a67f068..421a16c 100644 --- a/Buffer.xcodeproj/project.pbxproj +++ b/Buffer.xcodeproj/project.pbxproj @@ -7,192 +7,259 @@ objects = { /* Begin PBXBuildFile section */ - 160E25631CF44C3700A5F828 /* Buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 160E25621CF44C3700A5F828 /* Buffer.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 160E25771CF459B500A5F828 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 160E25721CF459B500A5F828 /* Buffer.swift */; }; - 160E25781CF459B500A5F828 /* CollectionViewDiffAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 160E25731CF459B500A5F828 /* CollectionViewDiffAdapter.swift */; }; - 160E257A1CF459B500A5F828 /* Diffing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 160E25751CF459B500A5F828 /* Diffing.swift */; }; - 160E257B1CF459B500A5F828 /* TableViewDiffAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 160E25761CF459B500A5F828 /* TableViewDiffAdapter.swift */; }; - 160E25A41CF4752700A5F828 /* AdapterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 160E25A31CF4752700A5F828 /* AdapterType.swift */; }; - 1611A8C81CF6365600DF2493 /* TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1611A8C71CF6365600DF2493 /* TableView.swift */; }; - 1611A8CA1CF636EF00DF2493 /* AnyListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1611A8C91CF636EF00DF2493 /* AnyListItem.swift */; }; - 165D96FF1CF5994C0040A48F /* PrototypeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165D96FE1CF5994C0040A48F /* PrototypeCell.swift */; }; + BF_129900734119 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_410994211877 /* Buffer.swift */; }; + BF_142601321502 /* Diffing.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_117720753967 /* Diffing.swift */; }; + BF_166615892941 /* TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_447204625897 /* TableView.swift */; }; + BF_184401418805 /* CollectionViewDiffAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_192249867684 /* CollectionViewDiffAdapter.swift */; }; + BF_226648680175 /* Diffing.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_117720753967 /* Diffing.swift */; }; + BF_362304106857 /* AdapterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_219619785040 /* AdapterType.swift */; }; + BF_369062063726 /* TableViewDiffAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_697572410803 /* TableViewDiffAdapter.swift */; }; + BF_420433651901 /* AdapterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_219619785040 /* AdapterType.swift */; }; + BF_488693606687 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_410994211877 /* Buffer.swift */; }; + BF_540167659288 /* CollectionViewDiffAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_192249867684 /* CollectionViewDiffAdapter.swift */; }; + BF_599316810726 /* AnyListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_629117886697 /* AnyListItem.swift */; }; + BF_617388784096 /* TableViewDiffAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_697572410803 /* TableViewDiffAdapter.swift */; }; + BF_673047461746 /* PrototypeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_761261387751 /* PrototypeCell.swift */; }; + BF_752354068978 /* Buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = FR_759165212399 /* Buffer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BF_760707255053 = {isa = PBXBuildFile; fileRef = FR_629006773661 /* Buffer.framework */; }; + BF_774605561720 /* TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_447204625897 /* TableView.swift */; }; + BF_831725708981 /* AnyListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_629117886697 /* AnyListItem.swift */; }; + BF_841461687791 = {isa = PBXBuildFile; fileRef = FR_461906688041 /* Buffer.framework */; }; + BF_864605773899 /* PrototypeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FR_761261387751 /* PrototypeCell.swift */; }; + BF_964449486626 /* Buffer.h in Headers */ = {isa = PBXBuildFile; fileRef = FR_759165212399 /* Buffer.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 160E255F1CF44C3700A5F828 /* Buffer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Buffer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 160E25621CF44C3700A5F828 /* Buffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Buffer.h; sourceTree = ""; }; - 160E25641CF44C3700A5F828 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 160E25721CF459B500A5F828 /* Buffer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Buffer.swift; sourceTree = ""; }; - 160E25731CF459B500A5F828 /* CollectionViewDiffAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewDiffAdapter.swift; sourceTree = ""; }; - 160E25751CF459B500A5F828 /* Diffing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Diffing.swift; sourceTree = ""; }; - 160E25761CF459B500A5F828 /* TableViewDiffAdapter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewDiffAdapter.swift; sourceTree = ""; }; - 160E25A31CF4752700A5F828 /* AdapterType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdapterType.swift; sourceTree = ""; }; - 1611A8C71CF6365600DF2493 /* TableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableView.swift; sourceTree = ""; }; - 1611A8C91CF636EF00DF2493 /* AnyListItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyListItem.swift; sourceTree = ""; }; - 165D96FE1CF5994C0040A48F /* PrototypeCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrototypeCell.swift; sourceTree = ""; }; + FR_117720753967 /* Diffing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Diffing.swift; sourceTree = ""; }; + FR_192249867684 /* CollectionViewDiffAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewDiffAdapter.swift; sourceTree = ""; }; + FR_219619785040 /* AdapterType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdapterType.swift; sourceTree = ""; }; + FR_410994211877 /* Buffer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buffer.swift; sourceTree = ""; }; + FR_447204625897 /* TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableView.swift; sourceTree = ""; }; + FR_456968685412 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + FR_461906688041 /* Buffer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Buffer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FR_629006773661 /* Buffer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Buffer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FR_629117886697 /* AnyListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyListItem.swift; sourceTree = ""; }; + FR_697572410803 /* TableViewDiffAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewDiffAdapter.swift; sourceTree = ""; }; + FR_759165212399 /* Buffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Buffer.h; sourceTree = ""; }; + FR_761261387751 /* PrototypeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrototypeCell.swift; sourceTree = ""; }; /* End PBXFileReference section */ -/* Begin PBXFrameworksBuildPhase section */ - 160E255B1CF44C3700A5F828 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - /* Begin PBXGroup section */ - 160E25551CF44C3700A5F828 = { - isa = PBXGroup; - children = ( - 160E25611CF44C3700A5F828 /* src */, - 160E25601CF44C3700A5F828 /* Products */, - ); - sourceTree = ""; - }; - 160E25601CF44C3700A5F828 /* Products */ = { + G_4799450059734 /* src */ = { isa = PBXGroup; children = ( - 160E255F1CF44C3700A5F828 /* Buffer.framework */, + FR_219619785040 /* AdapterType.swift */, + FR_629117886697 /* AnyListItem.swift */, + FR_759165212399 /* Buffer.h */, + FR_410994211877 /* Buffer.swift */, + FR_192249867684 /* CollectionViewDiffAdapter.swift */, + FR_117720753967 /* Diffing.swift */, + FR_456968685412 /* Info.plist */, + FR_761261387751 /* PrototypeCell.swift */, + FR_447204625897 /* TableView.swift */, + FR_697572410803 /* TableViewDiffAdapter.swift */, ); - name = Products; - sourceTree = ""; - }; - 160E25611CF44C3700A5F828 /* src */ = { - isa = PBXGroup; - children = ( - 1611A8C61CF6361C00DF2493 /* core */, - 1611A8C51CF6361500DF2493 /* ui */, - ); - name = src; + path = src; sourceTree = ""; }; - 1611A8C51CF6361500DF2493 /* ui */ = { + G_8448771205358 = { isa = PBXGroup; children = ( - 165D96FE1CF5994C0040A48F /* PrototypeCell.swift */, - 1611A8C71CF6365600DF2493 /* TableView.swift */, + G_8620238527590 /* Products */, + G_4799450059734 /* src */, ); - name = ui; - path = src; + indentWidth = 2; sourceTree = ""; + usesTabs = 0; }; - 1611A8C61CF6361C00DF2493 /* core */ = { + G_8620238527590 /* Products */ = { isa = PBXGroup; children = ( - 160E25721CF459B500A5F828 /* Buffer.swift */, - 160E25751CF459B500A5F828 /* Diffing.swift */, - 1611A8C91CF636EF00DF2493 /* AnyListItem.swift */, - 160E25A31CF4752700A5F828 /* AdapterType.swift */, - 160E25731CF459B500A5F828 /* CollectionViewDiffAdapter.swift */, - 160E25761CF459B500A5F828 /* TableViewDiffAdapter.swift */, - 160E25621CF44C3700A5F828 /* Buffer.h */, - 160E25641CF44C3700A5F828 /* Info.plist */, + FR_461906688041 /* Buffer.framework */, + FR_629006773661 /* Buffer.framework */, ); - name = core; - path = src; + name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 160E255C1CF44C3700A5F828 /* Headers */ = { + HBP_46190668804 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 160E25631CF44C3700A5F828 /* Buffer.h in Headers */, + BF_752354068978 /* Buffer.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + HBP_62900677366 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + BF_964449486626 /* Buffer.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 160E255E1CF44C3700A5F828 /* Buffer */ = { + NT_461906688041 /* Buffer_iOS */ = { isa = PBXNativeTarget; - buildConfigurationList = 160E25671CF44C3700A5F828 /* Build configuration list for PBXNativeTarget "Buffer" */; + buildConfigurationList = CL_461906688041 /* Build configuration list for PBXNativeTarget "Buffer_iOS" */; buildPhases = ( - 160E255A1CF44C3700A5F828 /* Sources */, - 160E255B1CF44C3700A5F828 /* Frameworks */, - 160E255C1CF44C3700A5F828 /* Headers */, - 160E255D1CF44C3700A5F828 /* Resources */, + SBP_46190668804 /* Sources */, + HBP_46190668804 /* Headers */, + SSBP_7447522410 /* Run Script */, ); buildRules = ( ); dependencies = ( ); - name = Buffer; - productName = Buffer; - productReference = 160E255F1CF44C3700A5F828 /* Buffer.framework */; + name = Buffer_iOS; + productName = Buffer_iOS; + productReference = FR_461906688041 /* Buffer.framework */; + productType = "com.apple.product-type.framework"; + }; + NT_629006773661 /* Buffer_macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = CL_629006773661 /* Build configuration list for PBXNativeTarget "Buffer_macOS" */; + buildPhases = ( + SBP_62900677366 /* Sources */, + HBP_62900677366 /* Headers */, + SSBP_6504248175 /* Run Script */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Buffer_macOS; + productName = Buffer_macOS; + productReference = FR_629006773661 /* Buffer.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - 160E25561CF44C3700A5F828 /* Project object */ = { + P_4795331179650 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0900; - ORGANIZATIONNAME = "Alex Usbergo"; - TargetAttributes = { - 160E255E1CF44C3700A5F828 = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 0900; - }; - }; + LastUpgradeCheck = 0930; }; - buildConfigurationList = 160E25591CF44C3700A5F828 /* Build configuration list for PBXProject "Buffer" */; + buildConfigurationList = CL_479533117965 /* Build configuration list for PBXProject "Buffer" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 160E25551CF44C3700A5F828; - productRefGroup = 160E25601CF44C3700A5F828 /* Products */; + mainGroup = G_8448771205358; projectDirPath = ""; projectRoot = ""; targets = ( - 160E255E1CF44C3700A5F828 /* Buffer */, + NT_461906688041 /* Buffer_iOS */, + NT_629006773661 /* Buffer_macOS */, ); }; /* End PBXProject section */ -/* Begin PBXResourcesBuildPhase section */ - 160E255D1CF44C3700A5F828 /* Resources */ = { - isa = PBXResourcesBuildPhase; +/* Begin PBXShellScriptBuildPhase section */ + SSBP_6504248175 /* Run Script */ = { + isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "PRODUCT=\"${BUILT_PRODUCTS_DIR}/${TARGET_NAME}\"; cp -R \"${PRODUCT}.framework\" ./bin; cp -R \"${PRODUCT}.framework.dSYM\" ./bin; cd ./bin; zip -r dist.zip Buffer.framework.dSYM Buffer.framework;"; }; -/* End PBXResourcesBuildPhase section */ + SSBP_7447522410 /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "PRODUCT=\"${BUILT_PRODUCTS_DIR}/${TARGET_NAME}\"; cp -R \"${PRODUCT}.framework\" ./bin; cp -R \"${PRODUCT}.framework.dSYM\" ./bin; cd ./bin; zip -r dist.zip Buffer.framework.dSYM Buffer.framework;"; + }; +/* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 160E255A1CF44C3700A5F828 /* Sources */ = { + SBP_46190668804 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 160E25771CF459B500A5F828 /* Buffer.swift in Sources */, - 160E257B1CF459B500A5F828 /* TableViewDiffAdapter.swift in Sources */, - 165D96FF1CF5994C0040A48F /* PrototypeCell.swift in Sources */, - 160E25781CF459B500A5F828 /* CollectionViewDiffAdapter.swift in Sources */, - 160E257A1CF459B500A5F828 /* Diffing.swift in Sources */, - 1611A8CA1CF636EF00DF2493 /* AnyListItem.swift in Sources */, - 1611A8C81CF6365600DF2493 /* TableView.swift in Sources */, - 160E25A41CF4752700A5F828 /* AdapterType.swift in Sources */, + BF_362304106857 /* AdapterType.swift in Sources */, + BF_831725708981 /* AnyListItem.swift in Sources */, + BF_488693606687 /* Buffer.swift in Sources */, + BF_540167659288 /* CollectionViewDiffAdapter.swift in Sources */, + BF_142601321502 /* Diffing.swift in Sources */, + BF_673047461746 /* PrototypeCell.swift in Sources */, + BF_166615892941 /* TableView.swift in Sources */, + BF_617388784096 /* TableViewDiffAdapter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + SBP_62900677366 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BF_420433651901 /* AdapterType.swift in Sources */, + BF_599316810726 /* AnyListItem.swift in Sources */, + BF_129900734119 /* Buffer.swift in Sources */, + BF_184401418805 /* CollectionViewDiffAdapter.swift in Sources */, + BF_226648680175 /* Diffing.swift in Sources */, + BF_864605773899 /* PrototypeCell.swift in Sources */, + BF_774605561720 /* TableView.swift in Sources */, + BF_369062063726 /* TableViewDiffAdapter.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ - 160E25651CF44C3700A5F828 /* Debug */ = { + BC_356228776115 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_TESTABILITY = YES; + GCC_DEBUGGING_SYMBOLS = "full,"; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + INFOPLIST_FILE = src/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + ONLY_ACTIVE_ARCH = NO; + PLATFORM = "platform iOS"; + PRODUCT_BUNDLE_IDENTIFIER = io.alexdrone.buffer; + PRODUCT_NAME = Buffer; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + BC_479945831424 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -200,32 +267,34 @@ 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_DOCUMENTATION_COMMENTS = YES; 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_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", "$(inherited)", + "DEBUG=1", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -233,23 +302,111 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + BC_669537055885 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_TESTABILITY = YES; + GCC_DEBUGGING_SYMBOLS = "full,"; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + INFOPLIST_FILE = src/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + ONLY_ACTIVE_ARCH = NO; + PLATFORM = "platform iOS"; + PRODUCT_BUNDLE_IDENTIFIER = io.alexdrone.buffer; + PRODUCT_NAME = Buffer; SDKROOT = iphoneos; + SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; }; name = Debug; }; - 160E25661CF44C3700A5F828 /* Release */ = { + BC_756593083793 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_TESTABILITY = YES; + GCC_DEBUGGING_SYMBOLS = "full,"; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + INFOPLIST_FILE = src/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + ONLY_ACTIVE_ARCH = NO; + PLATFORM = "platform macOS"; + PRODUCT_BUNDLE_IDENTIFIER = io.alexdrone.buffer; + PRODUCT_NAME = Buffer; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.2; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + BC_779463600906 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_TESTABILITY = YES; + GCC_DEBUGGING_SYMBOLS = "full,"; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + INFOPLIST_FILE = src/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; + ONLY_ACTIVE_ARCH = NO; + PLATFORM = "platform macOS"; + PRODUCT_BUNDLE_IDENTIFIER = io.alexdrone.buffer; + PRODUCT_NAME = Buffer; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.2; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + BC_881114754245 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -257,26 +414,28 @@ 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_DOCUMENTATION_COMMENTS = YES; 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_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -284,80 +443,46 @@ 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_OPTIMIZATION_LEVEL = "-Owholemodule"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 160E25681CF44C3700A5F828 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = src/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.s.Buffer; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; - }; - name = Debug; - }; - 160E25691CF44C3700A5F828 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = src/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.s.Buffer; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; + VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 160E25591CF44C3700A5F828 /* Build configuration list for PBXProject "Buffer" */ = { + CL_461906688041 /* Build configuration list for PBXNativeTarget "Buffer_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BC_669537055885 /* Debug */, + BC_356228776115 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = ""; + }; + CL_479533117965 /* Build configuration list for PBXProject "Buffer" */ = { isa = XCConfigurationList; buildConfigurations = ( - 160E25651CF44C3700A5F828 /* Debug */, - 160E25661CF44C3700A5F828 /* Release */, + BC_479945831424 /* Debug */, + BC_881114754245 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; - 160E25671CF44C3700A5F828 /* Build configuration list for PBXNativeTarget "Buffer" */ = { + CL_629006773661 /* Build configuration list for PBXNativeTarget "Buffer_macOS" */ = { isa = XCConfigurationList; buildConfigurations = ( - 160E25681CF44C3700A5F828 /* Debug */, - 160E25691CF44C3700A5F828 /* Release */, + BC_756593083793 /* Debug */, + BC_779463600906 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = ""; }; /* End XCConfigurationList section */ }; - rootObject = 160E25561CF44C3700A5F828 /* Project object */; + rootObject = P_4795331179650 /* Project object */; } diff --git a/Buffer.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Buffer.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 589ca4a..919434a 100644 --- a/Buffer.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/Buffer.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/Buffer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Buffer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Buffer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Buffer.xcodeproj/xcshareddata/xcschemes/Buffer.xcscheme b/Buffer.xcodeproj/xcshareddata/xcschemes/Buffer.xcscheme deleted file mode 100644 index 28f321d..0000000 --- a/Buffer.xcodeproj/xcshareddata/xcschemes/Buffer.xcscheme +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/dist.zip b/bin/dist.zip new file mode 100644 index 0000000..8432805 Binary files /dev/null and b/bin/dist.zip differ diff --git a/docs/logo.png b/docs/logo.png deleted file mode 100644 index c495360..0000000 Binary files a/docs/logo.png and /dev/null differ diff --git a/project.yml b/project.yml new file mode 100644 index 0000000..702cab7 --- /dev/null +++ b/project.yml @@ -0,0 +1,31 @@ +name: Buffer +options: + deploymentTarget: + iOS: 10.0 + macOS: 10.12 + usesTabs: false + indentWidth: 2 +targets: + Buffer: + platform: [iOS, macOS] + type: framework + sources: + - src + settings: + base: + INFOPLIST_FILE: src/Info.plist + PRODUCT_BUNDLE_IDENTIFIER: io.alexdrone.buffer + PLATFORM: platform $platform + SWIFT_VERSION: 4.2 + SWIFT_OPTIMIZATION_LEVEL: -Owholemodule + PLATFORM: platform $platform + GCC_GENERATE_DEBUGGING_SYMBOLS: YES + GCC_DEBUGGING_SYMBOLS: full, + DEBUG_INFORMATION_FORMAT: dwarf-with-dsym + ONLY_ACTIVE_ARCH: NO + configFiles: + Debug: configs/Debug.xcconfig + Release: configs/Release.xcconfig + postbuildScripts: + - name: Dist + - script: PRODUCT="${BUILT_PRODUCTS_DIR}/${TARGET_NAME}"; cp -R "${PRODUCT}.framework" ./bin; cp -R "${PRODUCT}.framework.dSYM" ./bin; cd ./bin; zip -r dist.zip Buffer.framework.dSYM Buffer.framework; diff --git a/samples/BufferDemo.xcodeproj/project.pbxproj b/samples/BufferDemo.xcodeproj/project.pbxproj index c576d13..5b60118 100644 --- a/samples/BufferDemo.xcodeproj/project.pbxproj +++ b/samples/BufferDemo.xcodeproj/project.pbxproj @@ -13,27 +13,8 @@ 160E25921CF45CFE00A5F828 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 160E25911CF45CFE00A5F828 /* Assets.xcassets */; }; 160E25951CF45CFE00A5F828 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 160E25931CF45CFE00A5F828 /* LaunchScreen.storyboard */; }; 160E25A21CF4604600A5F828 /* Lorem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 160E25A11CF4604600A5F828 /* Lorem.swift */; }; - 16A4DF001F4F093F0082BF5A /* Buffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16A4DEFF1F4F092E0082BF5A /* Buffer.framework */; }; - 16A4DF011F4F093F0082BF5A /* Buffer.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 16A4DEFF1F4F092E0082BF5A /* Buffer.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - 16A4DEFE1F4F092E0082BF5A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 16A4DEF51F4F09260082BF5A /* Buffer.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 160E255F1CF44C3700A5F828; - remoteInfo = Buffer; - }; - 16A4DF021F4F093F0082BF5A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 16A4DEF51F4F09260082BF5A /* Buffer.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 160E255E1CF44C3700A5F828; - remoteInfo = Buffer; - }; -/* End PBXContainerItemProxy section */ - /* Begin PBXCopyFilesBuildPhase section */ 160E259F1CF45D5200A5F828 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -41,7 +22,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 16A4DF011F4F093F0082BF5A /* Buffer.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -57,7 +37,7 @@ 160E25941CF45CFE00A5F828 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 160E25961CF45CFE00A5F828 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 160E25A11CF4604600A5F828 /* Lorem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lorem.swift; sourceTree = ""; }; - 16A4DEF51F4F09260082BF5A /* Buffer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Buffer.xcodeproj; path = ../Buffer.xcodeproj; sourceTree = ""; }; + 16D3214D210A75F00058E86D /* BufferDemo.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = BufferDemo.xcodeproj; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -65,7 +45,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 16A4DF001F4F093F0082BF5A /* Buffer.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -75,7 +54,7 @@ 160E257E1CF45CFE00A5F828 = { isa = PBXGroup; children = ( - 16A4DEF51F4F09260082BF5A /* Buffer.xcodeproj */, + 16D3214D210A75F00058E86D /* BufferDemo.xcodeproj */, 160E25891CF45CFE00A5F828 /* BufferDemo */, 160E25881CF45CFE00A5F828 /* Products */, ); @@ -103,11 +82,8 @@ path = BufferDemo; sourceTree = ""; }; - 16A4DEFB1F4F092E0082BF5A /* Products */ = { + 16D3214E210A75F00058E86D /* Products */ = { isa = PBXGroup; - children = ( - 16A4DEFF1F4F092E0082BF5A /* Buffer.framework */, - ); name = Products; sourceTree = ""; }; @@ -126,7 +102,6 @@ buildRules = ( ); dependencies = ( - 16A4DF031F4F093F0082BF5A /* PBXTargetDependency */, ); name = BufferDemo; productName = BufferDemo; @@ -162,8 +137,8 @@ projectDirPath = ""; projectReferences = ( { - ProductGroup = 16A4DEFB1F4F092E0082BF5A /* Products */; - ProjectRef = 16A4DEF51F4F09260082BF5A /* Buffer.xcodeproj */; + ProductGroup = 16D3214E210A75F00058E86D /* Products */; + ProjectRef = 16D3214D210A75F00058E86D /* BufferDemo.xcodeproj */; }, ); projectRoot = ""; @@ -173,16 +148,6 @@ }; /* End PBXProject section */ -/* Begin PBXReferenceProxy section */ - 16A4DEFF1F4F092E0082BF5A /* Buffer.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = Buffer.framework; - remoteRef = 16A4DEFE1F4F092E0082BF5A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - /* Begin PBXResourcesBuildPhase section */ 160E25851CF45CFE00A5F828 /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -209,14 +174,6 @@ }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXTargetDependency section */ - 16A4DF031F4F093F0082BF5A /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = Buffer; - targetProxy = 16A4DF021F4F093F0082BF5A /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - /* Begin PBXVariantGroup section */ 160E258E1CF45CFE00A5F828 /* Main.storyboard */ = { isa = PBXVariantGroup; diff --git a/samples/BufferDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/samples/BufferDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/samples/BufferDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/samples/BufferDemo/AppDelegate.swift b/samples/BufferDemo/AppDelegate.swift index 6a537e3..c688cfc 100644 --- a/samples/BufferDemo/AppDelegate.swift +++ b/samples/BufferDemo/AppDelegate.swift @@ -2,10 +2,13 @@ import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - + /// The key window. var window: UIWindow? - func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + /// Tells the delegate that the launch process is almost done and the app is almost ready to run. + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? + ) -> Bool { // Override point for customization after application launch. return true } diff --git a/samples/BufferDemo/Lorem.swift b/samples/BufferDemo/Lorem.swift index 51b326a..e98c183 100644 --- a/samples/BufferDemo/Lorem.swift +++ b/samples/BufferDemo/Lorem.swift @@ -1,71 +1,53 @@ import Foundation -open class Lorem { - - open static var word: String { +class Lorem { + static var word: String { return allWords.randomElement } - - open static func words(_ count: Int) -> String { + static func words(_ count: Int) -> String { return compose({ word }, count: count, middleSeparator: .Space) } - - open static var sentence: String { + static var sentence: String { let numberOfWordsInSentence = Int.random(min: 4, max: 16) let capitalizeFirstLetterDecorator: (String) -> String = { $0.stringWithCapitalizedFirstLetter } return compose({ word }, count: numberOfWordsInSentence, middleSeparator: .Space, endSeparator: .Dot, decorator: capitalizeFirstLetterDecorator) } - - open static func sentences(_ count: Int) -> String { + static func sentences(_ count: Int) -> String { return compose({ sentence }, count: count, middleSeparator: .Space) } - - open static var paragraph: String { + static var paragraph: String { let numberOfSentencesInParagraph = Int.random(min: 3, max: 9) return sentences(numberOfSentencesInParagraph) } - - open static func paragraphs(_ count: Int) -> String { + static func paragraphs(_ count: Int) -> String { return compose({ paragraph }, count: count, middleSeparator: .NewLine) } - - open static var title: String { + static var title: String { let numberOfWordsInTitle = Int.random(min: 2, max: 7) let capitalizeStringDecorator: (String) -> String = { $0.capitalized } return compose({ word }, count: numberOfWordsInTitle, middleSeparator: .Space, decorator: capitalizeStringDecorator) } - - // ======================================================= // - // MARK: - Misc - // ======================================================= // - - open static var firstName: String { + static var firstName: String { return firstNames.randomElement } - - open static var lastName: String { + static var lastName: String { return lastNames.randomElement } - - open static var name: String { + static var name: String { return "\(firstName) \(lastName)" } - - open static var email: String { + static var email: String { let delimiter = emailDelimiters.randomElement let domain = emailDomains.randomElement return "\(firstName)\(delimiter)\(lastName)@\(domain)".lowercased() } - - open static var URL: Foundation.URL { + static var URL: Foundation.URL { return Foundation.URL(string: "http://\(domains.randomElement)/")! } - - open static var tweet: String { + static var tweet: String { return tweets.randomElement } - - open static var date: Date { + static var date: Date { let currentDate = Date() let currentCalendar = Calendar.current var referenceDateComponents = DateComponents() @@ -76,38 +58,34 @@ open class Lorem { let randomTimeInterval = TimeInterval(Int.random(max: Int(timeIntervalSinceReferenceDate))) return referenceDate.addingTimeInterval(randomTimeInterval) } - - // ======================================================= // - // MARK: - Private - // ======================================================= // - fileprivate enum Separator: String { case None = "" case Space = " " case Dot = "." case NewLine = "\n" } - - fileprivate static func compose(_ provider: () -> String, count: Int, middleSeparator: Separator, endSeparator: Separator = .None, decorator: ((String) -> String)? = nil) -> String { + fileprivate static func compose( + _ provider: () -> String, + count: Int, + middleSeparator: Separator, + endSeparator: Separator = .None, + decorator: ((String) -> String)? = nil + ) -> String { var composedString = "" - for index in 0.. Int { assert(min >= 0) assert(min < max) - return Int(arc4random_uniform(UInt32((max - min) + 1))) + min } } extension Array { - - var randomElement: Element { - return self[Int.random(max: count - 1)] - } - + var randomElement: Element { return self[Int.random(max: count - 1)] } } extension String { - var stringWithCapitalizedFirstLetter: String { let firstLetterRange = startIndex.. Bool { } struct FooModel: Diffable { - var diffIdentifier: String { - return text - } + /// The identifier used from the diffing algorithm. + var diffIdentifier: String { return text } + /// Simple text property. let text: String } class ViewController: UIViewController, UITableViewDelegate { - - lazy var tableView: TableView = { - let tableView = TableView() + /// A declarative TableView from Buffer. + lazy var tableView: BufferTableView = { + let tableView = BufferTableView() tableView.delegate = self return tableView }() - + /// Some dummy elements. lazy var elements: [ListItem] = { var elements = [ListItem]() for i in 0...100 { - let item = ListItem(type: UITableViewCell.self, - container: self.tableView, - model: FooModel(text: ("\(i)"))) { cell, model in - cell.textLabel?.text = model.text - } + let item = ListItem( + type: UITableViewCell.self, + container: self.tableView, + model: FooModel(text: ("\(i)"))) { cell, model in cell.textLabel?.text = model.text } elements.append(item) } return elements @@ -44,9 +43,8 @@ class ViewController: UIViewController, UITableViewDelegate { } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - guard let tableView = tableView as? TableView else { - return - } + guard let tableView = tableView as? BufferTableView else { return } + // Performs a bunch of random operations on the list. var newElements = tableView.elements let index: Int = (indexPath as NSIndexPath).row let element = newElements[index] diff --git a/src/AnyListItem.swift b/src/AnyListItem.swift index cb2e7ef..547e91b 100644 --- a/src/AnyListItem.swift +++ b/src/AnyListItem.swift @@ -16,43 +16,44 @@ public protocol ListItemType: Diffable { var reuseIdentifier: String { get set } /// The TableView, or the CollectionView that will own this element. var referenceView: ListContainerView? { get } + /// A opaque pointer to the model associated to this row. var modelRef: Any? { get } - /// Configure the cell with the current item. func configure(cell: ListViewCell) } -public class ListItem: ListItemType, CustomDebugStringConvertible { +public class ListItem: ListItemType, CustomDebugStringConvertible { + /// The cell reuse identifier. public var reuseIdentifier: String - public var diffIdentifier: String { - return "\(reuseIdentifier)_\(model.diffIdentifier)" - } - public let referenceView: ListContainerView? - /// The actual item data. - public var model: Type + /// The unique identifier (used for the diffing algorithm). + public var diffIdentifier: String { return "\(reuseIdentifier)_\(model.diffIdentifier)" } + /// The *UICollectionView/UITableView* associated to this item. + public weak var referenceView: ListContainerView? + /// The actual model object. + public var model: T + /// A opaque pointer to the model associated to this row. public var modelRef: Any? { return self.model } + /// A textual representation of this instance, suitable for debugging. public var debugDescription: String { return self.diffIdentifier } - public var cellConfiguration: ((ListViewCell, Type) -> Void)? + /// The configuration block applied to the target cell. + public var cellConfiguration: ((ListViewCell, T) -> Void)? #if os(iOS) public init( - type: V.Type, - container: ListContainerView, - reuseIdentifer: String = String(describing: V.self), - model: Type, - configurationClosure: ((V, Type) -> Void)? = nil) { - - // registers the prototype cell if necessary. + type: V.Type, + container: ListContainerView, + reuseIdentifer: String = String(describing: V.self), + model: T, + configurationClosure: ((V, T) -> Void)? = nil + ) { + // Registers the prototype cell if necessary. if !Prototypes.isPrototypeCellRegistered(reuseIdentifer) { let cell = V(reuseIdentifier: reuseIdentifer) Prototypes.registerPrototypeCell(reuseIdentifer, cell: cell) } - self.reuseIdentifier = reuseIdentifer if let closure = configurationClosure { - self.cellConfiguration = { cell, type in - return closure(cell as! V, type) - } + self.cellConfiguration = { cell, type in return closure(cell as! V, type) } } self.referenceView = container self.model = model @@ -61,25 +62,23 @@ public class ListItem: ListItemType, CustomDebugStringConvertibl #endif public init( - type: V.Type, - container: ListContainerView? = nil, - reuseIdentifer: String = String(describing: V.self), - id: String? = nil, - model: Type, - configurationClosure: ((V, Type) -> Void)? = nil) { - + type: V.Type, + container: ListContainerView? = nil, + reuseIdentifer: String = String(describing: V.self), + id: String? = nil, + model: T, + configurationClosure: ((V, T) -> Void)? = nil + ) { self.reuseIdentifier = reuseIdentifer if let closure = configurationClosure { - self.cellConfiguration = { cell, type in - return closure(cell as! V, type) - } + self.cellConfiguration = { cell, type in return closure(cell as! V, type) } } self.referenceView = container self.model = model self.registerReferenceView(with: type) } - fileprivate func registerReferenceView(with cellClass: AnyClass) { + private func registerReferenceView(with cellClass: AnyClass) { #if os(iOS) if let tableView = self.referenceView as? UITableView { tableView.register(cellClass, forCellReuseIdentifier: self.reuseIdentifier) @@ -90,6 +89,7 @@ public class ListItem: ListItemType, CustomDebugStringConvertibl #endif } + /// Bind the cell passed as argument to this data item. public func configure(cell: ListViewCell) { self.cellConfiguration?(cell, self.model) } diff --git a/src/Buffer.swift b/src/Buffer.swift index 0e0215b..d5024a9 100644 --- a/src/Buffer.swift +++ b/src/Buffer.swift @@ -24,87 +24,70 @@ public protocol BufferDelegate: class { func buffer(didChangeElementAtIndex buffer: BufferType, index: UInt) } -public class Buffer: NSObject, BufferType { +public class Buffer: NSObject, BufferType { /// The object that will get notified every time chavbcnges occures to the array. public weak var delegate: BufferDelegate? /// The elements in the array observer's buffer. - public var currentElements: [ElementType] { + public var currentElements: [E] { return self.frontBuffer } /// Defines what is the maximum number of changes that you want the receiver to be notified for. - public var diffThreshold = 256 - // If set to 'true' the LCS algorithm is run synchronously on the main thread. + /// - note: If the number of changes exceeds this number, *buffer(didChangeAllContent:)* is going + /// to be invoked instead. + public var diffThreshold = 100 + /// If set to 'true' the LCS algorithm is run synchronously on the main thread. private var synchronous: Bool = false - // The two buffers. - private var frontBuffer = [ElementType]() { - willSet { - assert(Thread.isMainThread) - self.observe(shouldObserveTrackedKeyPaths: false) - } - didSet { - assert(Thread.isMainThread) - self.observe(shouldObserveTrackedKeyPaths: true) - } - } - private var backBuffer = [ElementType]() - // Sort closure. - private var sort: ((ElementType, ElementType) -> Bool)? - // Filter closure. - private var filter: ((ElementType) -> Bool)? - - // The serial operation queue for this controller. + /// The exposed array. + private var frontBuffer = [E]() + /// The internal array. + private var backBuffer = [E]() + /// Sort closure. + private var sort: ((E, E) -> Bool)? + /// Filter closure. + private var filter: ((E) -> Bool)? + /// The serial operation queue for this controller. private let serialOperationQueue: OperationQueue = { let operationQueue = OperationQueue() operationQueue.maxConcurrentOperationCount = 1 return operationQueue }() - - private var flags = (isRefreshing: false, - shouldRefresh: false) - - // Used if 'Element' is KVO-compliant. - private var trackedKeyPaths = [String]() - - public init(initialArray: [ElementType], - sort: ((ElementType, ElementType) -> Bool)? = nil, - filter: ((ElementType) -> Bool)? = nil) { - + /// Internal state flags. + private var flags = ( + isRefreshing: false, + shouldRefresh: false) + + /// Constructs a new buffer instance. + public init( + initialArray: [E], + sort: ((E, E) -> Bool)? = nil, + filter: ((E) -> Bool)? = nil + ) { self.frontBuffer = initialArray self.sort = sort self.filter = filter } - deinit { - self.observe(shouldObserveTrackedKeyPaths: false) - } - /// Compute the diffs between the current array and the new one passed as argument. public func update( - with values: [ElementType]? = nil, + with values: [E]? = nil, synchronous: Bool = false, - completion: (() -> Void)? = nil) { - - let new = values ?? self.frontBuffer - + completion: (() -> Void)? = nil + ) -> Void { // Should be called on the main thread. assert(Thread.isMainThread) - + let new = values ?? self.frontBuffer self.backBuffer = new - // Is already refreshing. if self.flags.isRefreshing { self.flags.shouldRefresh = true return } - self.flags.isRefreshing = true - self.dispatchOnSerialQueue(synchronous: synchronous) { [weak self] in guard let `self` = self else { return } var backBuffer = self.backBuffer - // Filter and sorts (if necessary). if let filter = self.filter { backBuffer = backBuffer.filter(filter) @@ -112,25 +95,27 @@ public class Buffer: NSObject, BufferType { if let sort = self.sort { backBuffer = backBuffer.sorted(by: sort) } - - let diff = Diff.diffing(oldArray: self.frontBuffer.map { $0.diffIdentifier}, - newArray: backBuffer.map { $0.diffIdentifier }) { + // Compute the diffing. + let diff = Diff.diffing( + oldArray: self.frontBuffer.map { $0.diffIdentifier}, + newArray: backBuffer.map { $0.diffIdentifier }) { return $0 == $1 } - + // Update the front buffer on the main thread. self.dispatchOnMainThread(synchronous: synchronous) { [weak self] in guard let `self` = self else { return } - //swaps the buffers. + // Swaps the buffers. self.frontBuffer = backBuffer - if diff.inserts.count < self.diffThreshold && diff.deletes.count < self.diffThreshold { self.delegate?.buffer(willChangeContent: self) - self.delegate?.buffer(didInsertElementsAtIndices: self, - indices: diff.inserts.map({ UInt($0) })) - self.delegate?.buffer(didDeleteElementAtIndices: self, - indices: diff.deletes.map({ UInt($0) })) + self.delegate?.buffer( + didInsertElementsAtIndices: self, + indices: diff.inserts.map({ UInt($0) })) + self.delegate?.buffer( + didDeleteElementAtIndices: self, + indices: diff.deletes.map({ UInt($0) })) for move in diff.moves { self.delegate?.buffer(didMoveElement: self, from: UInt(move.from), to: UInt(move.to)) } @@ -138,122 +123,52 @@ public class Buffer: NSObject, BufferType { } else { self.delegate?.buffer(didChangeAllContent: self) } - - //re-rerun refresh if necessary. + // Re-rerun refresh if necessary. self.flags.isRefreshing = false if self.flags.shouldRefresh { self.flags.shouldRefresh = false self.update(with: self.backBuffer) } - completion?() } } } - - /// This message is sent to the receiver when the value at the specified key path relative - /// to the given object has changed. - public override func observeValue(forKeyPath keyPath: String?, - of object: Any?, - change: [NSKeyValueChangeKey : Any]?, - context: UnsafeMutableRawPointer?) { - - if context != &__observationContext { - super.observeValue(forKeyPath: keyPath, of:object, change:change, context:context) - return - } - if self.trackedKeyPaths.contains(keyPath!) { - self.objectDidChangeValue(for: keyPath, in: object as AnyObject?) - } - - } -} - -// MARK: KVO Extension - -extension Buffer where ElementType: AnyObject { - - /// Observe the keypaths passed as argument. - public func trackKeyPaths(_ keypaths: [String]) { - self.observe(shouldObserveTrackedKeyPaths: false) - self.trackedKeyPaths = keypaths - self.observe() - } -} - -extension Buffer { - - /// Adds or remove observations. - /// - Note: This code is executed only when 'Element: AnyObject'. - private func observe(shouldObserveTrackedKeyPaths: Bool = true) { - if self.trackedKeyPaths.count == 0 { - return - } - for keyPath in trackedKeyPaths { - for item in self.frontBuffer { - if let object = item as? NSObject { - if shouldObserveTrackedKeyPaths { - object.addObserver(self, - forKeyPath: keyPath, - options: NSKeyValueObservingOptions.new, - context: &__observationContext) - - } else { - object.removeObserver(self, forKeyPath: keyPath) - } - } - } - } - } - - // - Note: This code is executed only when 'Element: AnyObject'. - private func objectDidChangeValue(for keyPath: String?, in object: AnyObject?) { - guard let object = object else { - return - } - dispatchOnMainThread { - self.update() { - var idx = 0 - let frontBuffer: [AnyObject] = self.frontBuffer.flatMap { $0 as AnyObject } - for item in frontBuffer { - if item === object { break } - idx += 1 - } - if idx < self.frontBuffer.count { - self.delegate?.buffer(didChangeElementAtIndex: self, index: UInt(idx)) - } - } - } - } } -private var __observationContext: UInt8 = 0 - //MARK: Dispatch Helpers private extension Buffer { - - func dispatchOnMainThread(synchronous: Bool = false, - block: @escaping () -> Void) { + /// Dispatches the block passed as argument on the main thread. + /// - parameter synchronous: If true the block is going to be called on the current call stack. + /// - parameter block: The block that is going to be executed. + func dispatchOnMainThread( + synchronous: Bool = false, + block: @escaping () -> Void + ) -> Void { if synchronous { assert(Thread.isMainThread) block() + return + } + if Thread.isMainThread { + block() } else { - if Thread.isMainThread { block() - } else { - DispatchQueue.main.async(execute: block) - } + DispatchQueue.main.async(execute: block) } } - - func dispatchOnSerialQueue(synchronous: Bool = false, - block: @escaping () -> Void) { + /// Dispatches the block passed as argument on the ad-hoc serial queue (if necesary). + /// - parameter synchronous: If true the block is going to be called on the current call stack. + /// - parameter block: The block that is going to be executed. + func dispatchOnSerialQueue( + synchronous: Bool = false, + block: @escaping () -> Void + ) -> Void { if synchronous { block() - } else { - self.serialOperationQueue.addOperation { - DispatchQueue.global().async(execute: block) - } + return + } + self.serialOperationQueue.addOperation { + DispatchQueue.global().async(execute: block) } } } diff --git a/src/CollectionViewDiffAdapter.swift b/src/CollectionViewDiffAdapter.swift index 5d82b90..016ffc7 100644 --- a/src/CollectionViewDiffAdapter.swift +++ b/src/CollectionViewDiffAdapter.swift @@ -1,21 +1,32 @@ #if os(iOS) import UIKit -open class CollectionViewDiffAdapter: NSObject, - AdapterType, - UICollectionViewDataSource { - public typealias `Type` = ElementType +open class CollectionViewDiffAdapter: + NSObject, + AdapterType, + UICollectionViewDataSource { + + public typealias `Type` = E public typealias ViewType = UICollectionView - open fileprivate(set) var buffer: Buffer + /// The buffer object. + open fileprivate(set) var buffer: Buffer + /// The collection view owning this adapter. open fileprivate(set) weak var view: ViewType? - /// Right now this only works on a single section of a collectionView. /// If your collectionView has multiple sections, though, you can just use multiple /// CollectionViewDiffAdapter, one per section, and set this value appropriately on each one. open var sectionIndex: Int = 0 + /// The indexpaths used for the batch update. + fileprivate var indexPaths: ( + insertion: [IndexPath], + deletion: [IndexPath], + move: [(IndexPath, IndexPath)] ) = ([], [], []) + /// The *cellForItemAtIndexPath* block. + fileprivate var cellForItemAtIndexPath: + ((UICollectionView, E, IndexPath) -> UICollectionViewCell)? = nil public required init(buffer: BufferType, view: ViewType) { - guard let buffer = buffer as? Buffer else { + guard let buffer = buffer as? Buffer else { fatalError() } self.buffer = buffer @@ -24,22 +35,15 @@ open class CollectionViewDiffAdapter: NSObject, self.buffer.delegate = self } - public required init(initialElements: [ElementType], view: ViewType) { + public required init(initialElements: [E], view: ViewType) { self.buffer = Buffer(initialArray: initialElements) self.view = view super.init() self.buffer.delegate = self } - fileprivate var indexPaths: (insertion: [IndexPath], - deletion: [IndexPath], - move: [(IndexPath, IndexPath)] ) = ([], [], []) - - fileprivate var cellForItemAtIndexPath: ((UICollectionView, ElementType, IndexPath) - -> UICollectionViewCell)? = nil - /// Returns the element currently on the front buffer at the given index path. - open func displayedElement(at index: Int) -> ElementType { + open func displayedElement(at index: Int) -> E { return self.buffer.currentElements[index] } @@ -53,9 +57,11 @@ open class CollectionViewDiffAdapter: NSObject, /// - parameter synchronous: Wether the filter, sorting and diff should be executed /// synchronously or not. /// - parameter completion: Code that will be executed once the buffer is updated. - open func update(with newValues: [ElementType]? = nil, - synchronous: Bool = false, - completion: (() -> Void)? = nil) { + open func update( + with newValues: [E]? = nil, + synchronous: Bool = false, + completion: (() -> Void)? = nil + ) -> Void { self.buffer.update(with: newValues, synchronous: synchronous, completion: completion) } @@ -66,28 +72,32 @@ open class CollectionViewDiffAdapter: NSObject, /// - parameter cellForRowAtIndexPath: The closure that returns a cell for the given /// index path. open func useAsDataSource(_ cellForItemAtIndexPath: - @escaping (UICollectionView, ElementType, IndexPath) -> UICollectionViewCell) { + @escaping (UICollectionView, E, IndexPath) -> UICollectionViewCell) { self.view?.dataSource = self self.cellForItemAtIndexPath = cellForItemAtIndexPath } /// Tells the data source to return the number of rows in a given section of a table view. - open func collectionView(_ collectionView: UICollectionView, - numberOfItemsInSection section: Int) -> Int { + open func collectionView( + _ collectionView: UICollectionView, + numberOfItemsInSection section: Int + ) -> Int { return self.buffer.currentElements.count } /// Asks the data source for a cell to insert in a particular location of the table view. - open func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - return self.cellForItemAtIndexPath!(collectionView, - buffer.currentElements[(indexPath as NSIndexPath).row], - indexPath) + open func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath + ) -> UICollectionViewCell { + return self.cellForItemAtIndexPath!( + collectionView, + buffer.currentElements[(indexPath as NSIndexPath).row], + indexPath) } } extension CollectionViewDiffAdapter: BufferDelegate { - /// Notifies the receiver that the content is about to change. public func buffer(willChangeContent buffer: BufferType) { self.indexPaths = ([], [], []) @@ -109,8 +119,9 @@ extension CollectionViewDiffAdapter: BufferDelegate { /// Notifies the receiver that a row got moved. public func buffer(didMoveElement buffer: BufferType, from: UInt, to: UInt) { - self.indexPaths.move.append((IndexPath(row: Int(from), section: self.sectionIndex), - IndexPath(row: Int(to), section: self.sectionIndex))) + self.indexPaths.move.append(( + IndexPath(row: Int(from), section: self.sectionIndex), + IndexPath(row: Int(to), section: self.sectionIndex))) } /// Notifies the receiver that the content updates has ended. diff --git a/src/Diffing.swift b/src/Diffing.swift index da4447a..ceffc59 100644 --- a/src/Diffing.swift +++ b/src/Diffing.swift @@ -13,104 +13,93 @@ public protocol Diffable { public protocol Diffing { /// Return the diff result from 'oldArray' to 'newArray' - static func diffing(oldArray: [T], - newArray: [T], - isEqual: EqualityChecker) -> DiffResultType + static func diffing( + oldArray: [T], + newArray: [T], + isEqual: EqualityChecker) -> DiffResultType } public protocol DiffResultType { + /// The computed required insert to match the destination array. var inserts: IndexSet { get set } + /// The computed required updates to match the destination array. var updates: IndexSet { get set } + /// The computed required deletes to match the destination array. var deletes: IndexSet { get set } + /// The computed required moves to match the destination array. var moves: [MoveIndex] { get set } } -public struct MoveIndex : Equatable, CustomDebugStringConvertible, CustomPlaygroundQuickLookable { +public struct MoveIndex: Equatable { + /// The source index. public let from: Int + /// The target index. public let to: Int public init(from: Int, to: Int) { self.from = from self.to = to } - + /// Returns *true* only if the two indices are the same. public static func == (lhs: MoveIndex, rhs: MoveIndex) -> Bool { return lhs.from == rhs.from && lhs.to == rhs.to } - - public var debugDescription: String { - return "\(from) => \(to)" - } - - public var customPlaygroundQuickLook: PlaygroundQuickLook { - return .text(debugDescription) - } } -public struct DiffResult : DiffResultType, - CustomDebugStringConvertible, - CustomPlaygroundQuickLookable { +public struct DiffResult: DiffResultType { + /// The computed required insert to match the destination array. public var inserts = IndexSet() + /// The computed required updates to match the destination array. public var updates = IndexSet() + /// The computed required deletes to match the destination array. public var deletes = IndexSet() + /// The computed required moves to match the destination array. public var moves = Array() + /// Internal data. public var oldMap = Dictionary() public var newMap = Dictionary() public func validate(_ oldArray: [T], _ newArray: [T]) -> Bool { return (oldArray.count + self.inserts.count - self.deletes.count) == newArray.count } + public func oldIndexFor(identifier: H) -> Int? { return self.oldMap[identifier] } + public func newIndexFor(identifier: H) -> Int? { return self.newMap[identifier] } - - public var debugDescription: String { - return [ - "Inserts => \(inserts.map { $0 })", - "Updates => \(updates.map { $0 })", - "Deletes => \(deletes.map { $0 })", - "Moves => \(moves.map { $0.debugDescription }.joined(separator: ","))", - ] - .joined(separator: "\n") - } - - public var customPlaygroundQuickLook: PlaygroundQuickLook { - return .text(debugDescription) - } } extension DiffResultType { + /// Returns *true* if there are any changes associated to this diff. public var hasChanges: Bool { - guard inserts.isEmpty else { return true } - guard deletes.isEmpty else { return true } - guard updates.isEmpty else { return true } - guard moves.isEmpty else { return true } - return false + return inserts.isEmpty && deletes.isEmpty && updates.isEmpty && moves.isEmpty } - + /// The number of changes. public var changeCount: Int { return inserts.count + deletes.count + updates.count + moves.count } } -struct Stack { - var items = [Element]() - var isEmpty: Bool { - return self.items.isEmpty - } - mutating func push(_ item: Element) { - items.append(item) - } - mutating func pop() -> Element { - return items.removeLast() - } -} - /// https://github.com/Instagram/IGListKit/blob/master/Source/IGListDiff.mm public enum Diff: Diffing { + /// Internal stack data structure. + private struct Stack { + /// All of the items in the stack. + var items = [T]() + /// Whether there are any elements in this stack. + var isEmpty: Bool { return self.items.isEmpty } + /// Adds a new elements to the stack. + mutating func push(_ item: T) { + items.append(item) + } + /// Remove the most recently added element to the stack. + mutating func pop() -> T { + return items.removeLast() + } + } /// Used to track data stats while diffing. /// We expect to keep a reference of entry, thus its declaration as (final) class. private final class Entry { @@ -135,7 +124,6 @@ public enum Diff: Diffing { self.oldIndexes.push(index) } } - /// Track both the entry and the algorithm index. Default the index to `nil` private struct Record { let entry: Entry @@ -156,29 +144,22 @@ public enum Diff: Diffing { } static func == (lhs: OptimizedIdentity, rhs: OptimizedIdentity) -> Bool { - if lhs.hashValue != rhs.hashValue { - return false - } - - if lhs.identity.distance(to: rhs.identity) == 0 { - return true - } - + if lhs.hashValue != rhs.hashValue { return false } + if lhs.identity.distance(to: rhs.identity) == 0 { return true } return lhs.identity.pointee == rhs.identity.pointee } } - /// Diffing - public static func diffing(oldArray: [T], - newArray: [T], - isEqual: EqualityChecker) -> DiffResultType { + /// The diffing algorithm. + public static func diffing( + oldArray: [T], + newArray: [T], + isEqual: EqualityChecker + ) -> DiffResultType { // symbol table uses the old/new array `diffIdentifier` as the key and `Entry` as the value - var table = Dictionary, Entry> - .init(minimumCapacity: oldArray.count) - + var table = Dictionary, Entry>.init(minimumCapacity: oldArray.count) let __oldArray = ContiguousArray(oldArray) let __newArray = ContiguousArray(newArray) - // pass 1 // create an entry for every item in the new array // increment its new count for each occurence @@ -198,7 +179,6 @@ public enum Diff: Diffing { return Record(entry) } } - // pass 2 // update or create an entry for every item in the old array // increment its old count for each occurence @@ -219,7 +199,6 @@ public enum Diff: Diffing { return Record(entry) } } - // pass 3 // handle data that occurs in both arrays newRecords.enumerated().filter { $1.entry.occurOnBothSides }.forEach { (i, newRecord) in @@ -236,16 +215,13 @@ public enum Diff: Diffing { entry.updated = true } } - // if an item occurs in the new and old array, it is unique // assign the index of new and old records to the opposite index (reverse lookup) newRecords[i].index = oldIndex oldRecords[oldIndex].index = i } - // storage for final indexes var result = DiffResult() - // track offsets from deleted items to calculate where items have moved // iterate old array records checking for deletes // increment offset for each delete @@ -260,17 +236,15 @@ public enum Diff: Diffing { result.oldMap[__oldArray[i].diffIdentifier] = i return deleteOffset } - //reset and track offsets from inserted items to calculate where items have moved runningOffset = 0 - /* let insertOffsets */_ = newRecords.enumerated().map { (i, newRecord) -> Int in + _ = newRecords.enumerated().map { (i, newRecord) -> Int in let insertOffset = runningOffset if let oldIndex = newRecord.index { // note that an entry can be updated /and/ moved if newRecord.entry.updated { result.updates.insert(oldIndex) } - // calculate the offset and determine if there was a move // if the indexes match, ignore the index let deleteOffset = deleteOffsets[oldIndex] @@ -284,34 +258,29 @@ public enum Diff: Diffing { result.newMap[__newArray[i].diffIdentifier] = i return insertOffset } - assert(result.validate(oldArray, newArray)) return result } } -// MARK: - Extensions +// MARK: - Diffable extensions. extension Int: Diffable { public var diffIdentifier: String { return "\(self)" } } - extension NSNumber: Diffable { public var diffIdentifier: String { return "\(self)" } } - extension String: Diffable { public var diffIdentifier: String { return self } } - extension NSString: Diffable { public var diffIdentifier: String { return "\(self)" } } - extension FloatingPoint { public var diffIdentifier: String { return "\(self)" } } - extension Float : Diffable { } - extension Double : Diffable { } + + diff --git a/src/PrototypeCell.swift b/src/PrototypeCell.swift index 0670ff1..a501071 100644 --- a/src/PrototypeCell.swift +++ b/src/PrototypeCell.swift @@ -7,19 +7,20 @@ public protocol PrototypeViewCell: ListViewCell { /// Apply the model. /// - Note: This is used internally from the infra to set the model. func applyModel(_ model: Any?) - + /// Constructor. init(reuseIdentifier: String) } open class PrototypeTableViewCell : UITableViewCell, PrototypeViewCell { /// The wrapped view. open var view: UIView! + /// The associated model. open var model: Any? { - didSet { - didSetModelClosure?(model) - } + didSet { didSetModelClosure?(model) } } + /// The *UICollectionView/UITableView* for this prototype cell. open weak var referenceView: ListContainerView? + /// Internal state. fileprivate var didInitializeCell = false fileprivate var didSetModelClosure: ((Any?) -> Void)? @@ -31,11 +32,11 @@ open class PrototypeTableViewCell : UITableViewCell, PrototypeViewCell { fatalError("init(coder:) has not been implemented") } - open func initializeCellIfNecessary(_ view: UIView, - didSetModel: ((Any?) -> Void)? = nil) { - + open func initializeCellIfNecessary( + _ view: UIView, + didSetModel: ((Any?) -> Void)? = nil + ) -> Void { assert(Thread.isMainThread) - // make sure this happens just once. if self.didInitializeCell { return } self.didInitializeCell = true @@ -73,11 +74,11 @@ open class PrototypeCollectionViewCell: UICollectionViewCell, PrototypeViewCell ///The model for this cell. /// - Note: This is propagated to the associted. open var model: Any? { - didSet { - didSetModelClosure?(model) - } + didSet { didSetModelClosure?(model) } } + /// The *UICollectionView/UITableView* for this prototype cell. weak open var referenceView: ListContainerView? + /// Internal state. fileprivate var didInitializeCell = false fileprivate var didSetModelClosure: ((Any?) -> Void)? @@ -89,13 +90,14 @@ open class PrototypeCollectionViewCell: UICollectionViewCell, PrototypeViewCell fatalError("init(coder:) has not been implemented") } - open func initializeCellIfNecessary(_ view: UIView, - didSetModel: ((Any?) -> Void)? = nil) { + open func initializeCellIfNecessary( + _ view: UIView, + didSetModel: ((Any?) -> Void)? = nil + ) -> Void { assert(Thread.isMainThread) // make sure this happens just once if self.didInitializeCell { return } self.didInitializeCell = true - self.view = view self.contentView.addSubview(view) self.didSetModelClosure = didSetModel @@ -143,11 +145,9 @@ public struct Prototypes { guard let cell = Prototypes.registeredPrototypes[item.reuseIdentifier] else { fatalError("Unregistered prototype with reuse identifier \(item.reuseIdentifier).") } - cell.applyModel(item.modelRef) cell.referenceView = item.referenceView item.configure(cell: cell) - if let cell = cell as? UIView { return cell.bounds.size } else { diff --git a/src/TableView.swift b/src/TableView.swift index eba988e..8d07c1f 100644 --- a/src/TableView.swift +++ b/src/TableView.swift @@ -1,26 +1,25 @@ #if os(iOS) import UIKit -open class TableView: UITableView { +open class BufferTableView: UITableView { /// The elements for the table view. - open var elements = [ListItem]() { - didSet { - self.adapter.buffer.update(with: self.elements) - } + open var elements = [ListItem]() { + didSet { self.adapter.buffer.update(with: self.elements) } } /// The adapter for this table view. - open lazy var adapter: TableViewDiffAdapter> = { - return TableViewDiffAdapter(initialElements: [ListItem](), view: self) + open lazy var adapter: TableViewDiffAdapter> = { + return TableViewDiffAdapter(initialElements: [ListItem](), view: self) }() + /// Convenience constructor. public convenience init() { self.init(frame: CGRect.zero, style: .plain) } - public override init(frame: CGRect, style: UITableViewStyle) { + /// Initializes and returns a table view object having the given frame and style. + public override init(frame: CGRect, style: UITableView.Style) { super.init(frame: frame, style: style) - - self.rowHeight = UITableViewAutomaticDimension + self.rowHeight = UITableView.automaticDimension if #available(iOS 11, *) { self.estimatedRowHeight = -1 } else { @@ -28,12 +27,14 @@ open class TableView: UITableView { } self.adapter.useAsDataSource() { tableView, item, indexPath in let cell = tableView.dequeueReusableCell( - withIdentifier: item.reuseIdentifier, for: indexPath as IndexPath) + withIdentifier: item.reuseIdentifier, + for: indexPath as IndexPath) item.cellConfiguration?(cell, item.model) return cell } } + /// - note: Not supported. required public init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/src/TableViewDiffAdapter.swift b/src/TableViewDiffAdapter.swift index 839f98b..81d4e62 100644 --- a/src/TableViewDiffAdapter.swift +++ b/src/TableViewDiffAdapter.swift @@ -1,21 +1,27 @@ #if os(iOS) import UIKit -open class TableViewDiffAdapter: NSObject, - AdapterType, - UITableViewDataSource { - public typealias `Type` = ElementType +open class TableViewDiffAdapter: + NSObject, + AdapterType, + UITableViewDataSource { + + public typealias `Type` = E public typealias ViewType = UITableView - open fileprivate(set) var buffer: Buffer + /// The buffer object. + open fileprivate(set) var buffer: Buffer + /// The collection view owning this adapter. open fileprivate(set) weak var view: ViewType? - /// Right now this only works on a single section of a tableView. /// If your tableView has multiple sections, though, you can just use multiple /// TableViewDiffAdapter, one per section, and set this value appropriately on each one. open var sectionIndex: Int = 0 + /// The *cellForItemAtIndexPath* block. + fileprivate var cellForRowAtIndexPath: + ((UITableView, E, IndexPath) -> UITableViewCell)? = nil public required init(buffer: BufferType, view: ViewType) { - guard let buffer = buffer as? Buffer else { + guard let buffer = buffer as? Buffer else { fatalError() } self.buffer = buffer @@ -24,16 +30,13 @@ open class TableViewDiffAdapter: NSObject, self.buffer.delegate = self } - public required init(initialElements: [ElementType], view: ViewType) { + public required init(initialElements: [E], view: ViewType) { self.buffer = Buffer(initialArray: initialElements) self.view = view super.init() self.buffer.delegate = self } - fileprivate var cellForRowAtIndexPath: - ((UITableView, ElementType, IndexPath) -> UITableViewCell)? = nil - /// Returns the element currently on the front buffer at the given index path. open func displayedElement(at index: Int) -> Type { return self.buffer.currentElements[index] @@ -49,9 +52,11 @@ open class TableViewDiffAdapter: NSObject, /// - parameter synchronous: Wether the filter, sorting and diff should be /// executed synchronously or not. /// - parameter completion: Code that will be executed once the buffer is updated. - open func update(with newValues: [ElementType]? = nil, - synchronous: Bool = false, - completion: (() -> Void)? = nil) { + open func update( + with newValues: [E]? = nil, + synchronous: Bool = false, + completion: (() -> Void)? = nil + ) -> Void { self.buffer.update(with: newValues, synchronous: synchronous, completion: completion) } @@ -62,28 +67,32 @@ open class TableViewDiffAdapter: NSObject, /// - parameter cellForRowAtIndexPath: The closure that returns a cell for the /// given index path. open func useAsDataSource(_ cellForRowAtIndexPath: - @escaping (UITableView, ElementType, IndexPath) -> UITableViewCell) { + @escaping (UITableView, E, IndexPath) -> UITableViewCell) { self.view?.dataSource = self self.cellForRowAtIndexPath = cellForRowAtIndexPath } /// Tells the data source to return the number of rows in a given section of a table view. - dynamic open func tableView(_ tableView: UITableView, - numberOfRowsInSection section: Int) -> Int { + dynamic open func tableView( + _ tableView: UITableView, + numberOfRowsInSection section: Int + ) -> Int { return self.buffer.currentElements.count } /// Asks the data source for a cell to insert in a particular location of the table view. - open func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return self.cellForRowAtIndexPath!(tableView, - buffer.currentElements[(indexPath as NSIndexPath).row], - indexPath) + open func tableView( + _ tableView: UITableView, + cellForRowAt indexPath: IndexPath + ) -> UITableViewCell { + return self.cellForRowAtIndexPath!( + tableView, + buffer.currentElements[(indexPath as NSIndexPath).row], + indexPath) } } extension TableViewDiffAdapter: BufferDelegate { - /// Notifies the receiver that the content is about to change. public func buffer(willChangeContent buffer: BufferType) { self.view?.beginUpdates() @@ -107,8 +116,9 @@ extension TableViewDiffAdapter: BufferDelegate { /// Notifies the receiver that a row got moved. public func buffer(didMoveElement buffer: BufferType, from: UInt, to: UInt) { - self.view?.moveRow(at: IndexPath(row: Int(from), section: self.sectionIndex), - to: IndexPath(row: Int(to), section: self.sectionIndex)) + self.view?.moveRow( + at: IndexPath(row: Int(from), section: self.sectionIndex), + to: IndexPath(row: Int(to), section: self.sectionIndex)) } /// Notifies the receiver that the content updates has ended.