From c7e233e57595f9c459745dbe8d237ea12e6bb092 Mon Sep 17 00:00:00 2001 From: Mathias Claassen Date: Fri, 7 Oct 2016 12:14:06 -0300 Subject: [PATCH] Swift 3 compatibility --- .swift-version | 1 + CHANGELOG.md | 7 +- README.md | 38 ++++------ TokenRow.podspec | 4 +- TokenRow/Example/Alamofire.swift | 73 ++++++++++--------- TokenRow/Example/AppDelegate.swift | 12 +-- .../Example/Example.xcodeproj/project.pbxproj | 66 ++++++++++------- TokenRow/Example/Podfile | 2 +- TokenRow/Example/Podfile.lock | 24 +++--- .../Example/TokenRowTests/TokenRowTests.swift | 6 +- TokenRow/Example/User.swift | 10 +-- TokenRow/Example/ViewController.swift | 24 +++--- .../Sources/CollectionViewTokenCell.swift | 52 +++++++------ TokenRow/Sources/String+TokenRow.swift | 6 +- TokenRow/Sources/TRCollectionViewCell.swift | 22 +++--- TokenRow/Sources/TRTableViewCell.swift | 10 +-- TokenRow/Sources/TableViewTokenCell.swift | 58 ++++++++------- TokenRow/Sources/TokenCell.swift | 48 ++++++------ TokenRow/Sources/TokenRow.swift | 22 +++--- 19 files changed, 255 insertions(+), 230 deletions(-) create mode 100644 .swift-version diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..9f55b2c --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +3.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index effeaa6..5a5716f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,13 @@ # Change Log All notable changes to TokenRow will be documented in this file. +### [1.1.0](https://github.com/EurekaCommunity/TokenRow/releases/tag/1.0.0) + + +* Swift 3 compatibility. + ### [1.0.0](https://github.com/EurekaCommunity/TokenRow/releases/tag/1.0.0) - + * This is the initial version. diff --git a/README.md b/README.md index d09329c..8e61e18 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

Build status Platform iOS -Swift 2 compatible +Swift 2 compatible CocoaPods compatible License: MIT @@ -54,13 +54,13 @@ form +++ Section() To see what you can customize have a look at the [Customization](#customization) section. ## Dependencies -* [Eureka] +* [Eureka] 2.x * [CLTokenInputView] which is a token view pod ## Requirements * iOS 8.0+ -* Xcode 7.3+ +* Xcode 8+ ## Getting involved @@ -91,17 +91,6 @@ To install TokenRow, simply add the following line to your Podfile: ```ruby pod 'TokenRow' ``` - ## TokenSearchable @@ -175,17 +164,16 @@ For example: ```swift row.getTokensForString = { [weak self, row] string in guard let me = self else { return nil } - Alamofire.Manager.sharedInstance.request(.GET, "https://api.github.com/search/users?q=\(string)&per_page=5") - .responseCollection({ (response: Response<[User], BackendError>) in - switch response.result { - case let .Success(value): - // update the filtered tokens and reload the tableView or collectionView - row.cell.filteredTokens = value - row.cell.reloadOptions() - case let .Failure(error): - print(error) - } - }) + Alamofire.SessionManager.default.request("https://api.github.com/search/users?q=\(text)&per_page=5") + .responseCollection(completionHandler: { (response: DataResponse<[User]>) in + switch response.result { + case let .success(value): + row.cell.filteredTokens = value + row.cell.reloadOptions() + case let .failure(error): + print(error) + } + }) return [] } ``` diff --git a/TokenRow.podspec b/TokenRow.podspec index 3af9d2e..59cb8ee 100644 --- a/TokenRow.podspec +++ b/TokenRow.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "TokenRow" - s.version = "1.0.0" + s.version = "1.1.0" s.summary = "An Eureka row that allows the user to select options into a token view." s.homepage = "https://github.com/EurekaCommunity/TokenRow" s.license = { type: 'MIT', file: 'LICENSE' } @@ -11,6 +11,6 @@ Pod::Spec.new do |s| s.requires_arc = true s.ios.source_files = 'TokenRow/Sources/**/*.{swift}' s.ios.frameworks = 'UIKit', 'Foundation' - s.dependency 'Eureka', '~> 1.0' + s.dependency 'Eureka', '~> 2.0.0-beta.1' s.dependency 'CLTokenInputView', '~> 2.0' end diff --git a/TokenRow/Example/Alamofire.swift b/TokenRow/Example/Alamofire.swift index 9285bb7..f402719 100644 --- a/TokenRow/Example/Alamofire.swift +++ b/TokenRow/Example/Alamofire.swift @@ -16,57 +16,58 @@ import Alamofire */ -public enum BackendError: ErrorType { - case Network(error: NSError) - case DataSerialization(reason: String) - case JSONSerialization(error: NSError) - case ObjectSerialization(reason: String) - case XMLSerialization(error: NSError) +public enum BackendError: Error { + case network(error: NSError) + case dataSerialization(reason: String) + case jsonSerialization(error: NSError) + case objectSerialization(reason: String) + case xmlSerialization(error: NSError) } public protocol ResponseObjectSerializable { - init?(response: NSHTTPURLResponse, representation: AnyObject) + init?(response: HTTPURLResponse, representation: AnyObject) } -extension Request { - public func responseObject(completionHandler: Response -> Void) -> Self { - let responseSerializer = ResponseSerializer { request, response, data, error in - guard error == nil else { return .Failure(.Network(error: error!)) } +extension DataRequest { + @discardableResult + public func responseObject(queue: DispatchQueue? = nil, completionHandler: @escaping (DataResponse) -> Void) -> Self { + let responseSerializer = DataResponseSerializer { request, response, data, error in + guard error == nil else { return .failure(BackendError.network(error: error! as NSError)) } - let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments) + let JSONResponseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments) let result = JSONResponseSerializer.serializeResponse(request, response, data, error) switch result { - case .Success(let value): + case .success(let value): if let response = response, - responseObject = T(response: response, representation: value) + let responseObject = T(response: response, representation: value as AnyObject) { - return .Success(responseObject) + return .success(responseObject) } else { - return .Failure(.ObjectSerialization(reason: "JSON could not be serialized into response object: \(value)")) + return .failure(BackendError.objectSerialization(reason: "JSON could not be serialized into response object: \(value)")) } - case .Failure(let error): - return .Failure(.JSONSerialization(error: error)) + case .failure(let error): + return .failure(BackendError.jsonSerialization(error: error as NSError)) } } - return response(responseSerializer: responseSerializer, completionHandler: completionHandler) + return response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler) } } public protocol ResponseCollectionSerializable { - static func collection(response response: NSHTTPURLResponse, representation: AnyObject) -> [Self] + static func collection(response: HTTPURLResponse, representation: AnyObject) -> [Self] } extension ResponseCollectionSerializable where Self: ResponseObjectSerializable { - static func collection(response response: NSHTTPURLResponse, representation: AnyObject) -> [Self] { + static func collection(response: HTTPURLResponse, representation: AnyObject) -> [Self] { var collection = [Self]() // check in items path - if let representation = representation.valueForKeyPath("items") as? [[String: AnyObject]] { + if let representation = representation.value(forKeyPath: "items") as? [[String: AnyObject]] { for itemRepresentation in representation { - if let item = Self(response: response, representation: itemRepresentation) { + if let item = Self(response: response, representation: itemRepresentation as AnyObject) { collection.append(item) } } @@ -76,26 +77,28 @@ extension ResponseCollectionSerializable where Self: ResponseObjectSerializable } } -extension Alamofire.Request { - public func responseCollection(completionHandler: Response<[T], BackendError> -> Void) -> Self { - let responseSerializer = ResponseSerializer<[T], BackendError> { request, response, data, error in - guard error == nil else { return .Failure(.Network(error: error!)) } +extension DataRequest { + @discardableResult + public func responseCollection(queue: DispatchQueue? = nil, + completionHandler: @escaping (DataResponse<[T]>) -> Void) -> Self { + let responseSerializer = DataResponseSerializer<[T]> { request, response, data, error in + guard error == nil else { return .failure(BackendError.network(error: error! as NSError)) } - let JSONSerializer = Request.JSONResponseSerializer(options: .AllowFragments) - let result = JSONSerializer.serializeResponse(request, response, data, error) + let JSONResponseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments) + let result = JSONResponseSerializer.serializeResponse(request, response, data, error) switch result { - case .Success(let value): + case .success(let value): if let response = response { - return .Success(T.collection(response: response, representation: value)) + return .success(T.collection(response: response, representation: value as AnyObject)) } else { - return .Failure(. ObjectSerialization(reason: "Response collection could not be serialized due to nil response")) + return .failure(BackendError.objectSerialization(reason: "JSON could not be serialized into response object: \(value)")) } - case .Failure(let error): - return .Failure(.JSONSerialization(error: error)) + case .failure(let error): + return .failure(BackendError.jsonSerialization(error: error as NSError)) } } - return response(responseSerializer: responseSerializer, completionHandler: completionHandler) + return response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler) } } diff --git a/TokenRow/Example/AppDelegate.swift b/TokenRow/Example/AppDelegate.swift index 576b659..3bd585c 100644 --- a/TokenRow/Example/AppDelegate.swift +++ b/TokenRow/Example/AppDelegate.swift @@ -13,30 +13,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/TokenRow/Example/Example.xcodeproj/project.pbxproj b/TokenRow/Example/Example.xcodeproj/project.pbxproj index 37d9371..d3d1e64 100644 --- a/TokenRow/Example/Example.xcodeproj/project.pbxproj +++ b/TokenRow/Example/Example.xcodeproj/project.pbxproj @@ -183,13 +183,13 @@ isa = PBXNativeTarget; buildConfigurationList = 28F828E91C4B714D00330CF4 /* Build configuration list for PBXNativeTarget "Example" */; buildPhases = ( - 6FEE7A2956C9764B58D94F5D /* 📦 Check Pods Manifest.lock */, + 6FEE7A2956C9764B58D94F5D /* [CP] Check Pods Manifest.lock */, 28F828C81C4B714D00330CF4 /* Sources */, 28F828C91C4B714D00330CF4 /* Frameworks */, 28F828CA1C4B714D00330CF4 /* Resources */, 287D0A811C4B7B55004566D6 /* Embed Frameworks */, - E8354FD93BFCEE73C23850C7 /* 📦 Embed Pods Frameworks */, - FAD44456F7AEB643F044FBD7 /* 📦 Copy Pods Resources */, + E8354FD93BFCEE73C23850C7 /* [CP] Embed Pods Frameworks */, + FAD44456F7AEB643F044FBD7 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -222,12 +222,12 @@ isa = PBXNativeTarget; buildConfigurationList = 8F7B2E411D82E2C500D5AD90 /* Build configuration list for PBXNativeTarget "TokenRowTests" */; buildPhases = ( - 9D01DBBB5723FF157F4C53EB /* 📦 Check Pods Manifest.lock */, + 9D01DBBB5723FF157F4C53EB /* [CP] Check Pods Manifest.lock */, 8F7B2E361D82E2C500D5AD90 /* Sources */, 8F7B2E371D82E2C500D5AD90 /* Frameworks */, 8F7B2E381D82E2C500D5AD90 /* Resources */, - 6BB818B4241595B40EB6DAF7 /* 📦 Embed Pods Frameworks */, - 79A974E4A67C8A878196FB57 /* 📦 Copy Pods Resources */, + 6BB818B4241595B40EB6DAF7 /* [CP] Embed Pods Frameworks */, + 79A974E4A67C8A878196FB57 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -246,17 +246,20 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; TargetAttributes = { 28F828CB1C4B714D00330CF4 = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; 28F828DF1C4B714D00330CF4 = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; TestTargetID = 28F828CB1C4B714D00330CF4; }; 8F7B2E391D82E2C500D5AD90 = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 0800; TestTargetID = 28F828CB1C4B714D00330CF4; }; }; @@ -309,14 +312,14 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 6BB818B4241595B40EB6DAF7 /* 📦 Embed Pods Frameworks */ = { + 6BB818B4241595B40EB6DAF7 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Embed Pods Frameworks"; + name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -324,29 +327,29 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-TokenRowTests/Pods-TokenRowTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 6FEE7A2956C9764B58D94F5D /* 📦 Check Pods Manifest.lock */ = { + 6FEE7A2956C9764B58D94F5D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - 79A974E4A67C8A878196FB57 /* 📦 Copy Pods Resources */ = { + 79A974E4A67C8A878196FB57 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -354,29 +357,29 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-TokenRowTests/Pods-TokenRowTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 9D01DBBB5723FF157F4C53EB /* 📦 Check Pods Manifest.lock */ = { + 9D01DBBB5723FF157F4C53EB /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Check Pods Manifest.lock"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; - E8354FD93BFCEE73C23850C7 /* 📦 Embed Pods Frameworks */ = { + E8354FD93BFCEE73C23850C7 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Embed Pods Frameworks"; + name = "[CP] Embed Pods Frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -384,14 +387,14 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - FAD44456F7AEB643F044FBD7 /* 📦 Copy Pods Resources */ = { + FAD44456F7AEB643F044FBD7 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "📦 Copy Pods Resources"; + name = "[CP] Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -477,8 +480,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -500,7 +505,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.2; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -521,8 +526,10 @@ 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_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -538,9 +545,10 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.2; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; VALIDATE_PRODUCT = YES; }; name = Release; @@ -549,12 +557,13 @@ isa = XCBuildConfiguration; baseConfigurationReference = B19E3C5587C8B604A9173418 /* Pods-Example.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.xmartlabs.Example; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -562,12 +571,13 @@ isa = XCBuildConfiguration; baseConfigurationReference = 95E39C43A4E429314B1C3D63 /* Pods-Example.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.xmartlabs.Example; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -580,6 +590,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.xmartlabs.ExampleUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; TEST_TARGET_NAME = Example; USES_XCTRUNNER = YES; }; @@ -593,6 +604,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.xmartlabs.ExampleUITests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_TARGET_NAME = Example; USES_XCTRUNNER = YES; }; @@ -602,6 +614,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = F3317486620E38E7A4823BCF /* Pods-TokenRowTests.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; INFOPLIST_FILE = TokenRowTests/Info.plist; @@ -609,6 +622,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.xmartlabs.TokenRowTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example"; }; name = Debug; @@ -617,6 +631,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = A58DE564DA68C5AC77D89095 /* Pods-TokenRowTests.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; INFOPLIST_FILE = TokenRowTests/Info.plist; @@ -624,6 +639,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.xmartlabs.TokenRowTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example"; }; name = Release; diff --git a/TokenRow/Example/Podfile b/TokenRow/Example/Podfile index 81021b8..5f8cb73 100755 --- a/TokenRow/Example/Podfile +++ b/TokenRow/Example/Podfile @@ -3,7 +3,7 @@ source 'https://github.com/CocoaPods/Specs.git' use_frameworks! def pods - pod 'Alamofire', '~> 3.5' + pod 'Alamofire', '~> 4.0' pod 'AlamofireImage' pod 'CLTokenInputView', '~> 2.0' pod 'TokenRow', :path => '../../' diff --git a/TokenRow/Example/Podfile.lock b/TokenRow/Example/Podfile.lock index 53e56e7..0edb7b4 100644 --- a/TokenRow/Example/Podfile.lock +++ b/TokenRow/Example/Podfile.lock @@ -1,15 +1,15 @@ PODS: - - Alamofire (3.5.0) - - AlamofireImage (2.5.0): - - Alamofire (~> 3.5) + - Alamofire (4.0.1) + - AlamofireImage (3.1.0): + - Alamofire (~> 4.0) - CLTokenInputView (2.3.0) - - Eureka (1.7.0) + - Eureka (2.0.0-beta.1) - TokenRow (1.0.0): - CLTokenInputView (~> 2.0) - - Eureka (~> 1.0) + - Eureka (~> 2.0.0-beta.1) DEPENDENCIES: - - Alamofire (~> 3.5) + - Alamofire (~> 4.0) - AlamofireImage - CLTokenInputView (~> 2.0) - TokenRow (from `../../`) @@ -19,12 +19,12 @@ EXTERNAL SOURCES: :path: ../../ SPEC CHECKSUMS: - Alamofire: b70a7352335f8ea5babd0a923eb7e8eacc67b877 - AlamofireImage: 2d34936e5201270bb17a316a786e90e83b4a249d + Alamofire: 7682d43245de14874acd142ec137b144aa1dd335 + AlamofireImage: bb8c8351c51cb1633bb6be69b6dbbaff37ce65b7 CLTokenInputView: 9dc1ffb7c9d2d81787e69a63c75bd97b0b2d1e76 - Eureka: 2020d9faeef7b7e9adeb9e3d8af779e5931c1897 - TokenRow: f856265d3812d70738ab8c924d00cae47556c7e6 + Eureka: d014adf16406745e1a78d5790ea37ed130a0a8e5 + TokenRow: 7362e08738e1ba31260a13f963d93e5115fd4568 -PODFILE CHECKSUM: 37c70237638a6796cca4d618cbb80b955770dd6a +PODFILE CHECKSUM: ae10cf141332d133506b562d6cf2f2ea98250b24 -COCOAPODS: 1.0.0 +COCOAPODS: 1.1.0.rc.2 diff --git a/TokenRow/Example/TokenRowTests/TokenRowTests.swift b/TokenRow/Example/TokenRowTests/TokenRowTests.swift index a6f8d4c..7819b2b 100644 --- a/TokenRow/Example/TokenRowTests/TokenRowTests.swift +++ b/TokenRow/Example/TokenRowTests/TokenRowTests.swift @@ -45,9 +45,9 @@ class TokenRowTests: XCTestCase { func testStringSearchable() { let string = "SoMe VeRy RarE StrINg" - XCTAssertTrue(string.contains("very")) - XCTAssertTrue(string.contains("STRING")) - XCTAssertFalse(string.contains("strange")) + XCTAssertTrue(string.contains(token: "very")) + XCTAssertTrue(string.contains(token: "STRING")) + XCTAssertFalse(string.contains(token: "strange")) } } diff --git a/TokenRow/Example/User.swift b/TokenRow/Example/User.swift index 4fe27d7..5627bfe 100644 --- a/TokenRow/Example/User.swift +++ b/TokenRow/Example/User.swift @@ -19,10 +19,10 @@ final class User: ResponseObjectSerializable, ResponseCollectionSerializable { return id } - required init?(response: NSHTTPURLResponse, representation: AnyObject) { - self.name = representation.valueForKeyPath("login") as! String - self.avatar = representation.valueForKeyPath("avatar_url") as? String - self.id = representation.valueForKeyPath("id") as! Int + required init?(response: HTTPURLResponse, representation: AnyObject) { + self.name = representation.value(forKeyPath: "login") as! String + self.avatar = representation.value(forKeyPath: "avatar_url") as? String + self.id = representation.value(forKeyPath: "id") as! Int } } @@ -36,7 +36,7 @@ extension User: TokenSearchable { } var identifier: NSObject { - return id + return id as NSObject } var displayString: String { diff --git a/TokenRow/Example/ViewController.swift b/TokenRow/Example/ViewController.swift index fbb6ed5..0d67129 100644 --- a/TokenRow/Example/ViewController.swift +++ b/TokenRow/Example/ViewController.swift @@ -14,7 +14,7 @@ import AlamofireImage class ViewController: FormViewController { - var timer: NSTimer? + var timer: Timer? override func viewDidLoad() { super.viewDidLoad() @@ -34,11 +34,11 @@ class ViewController: FormViewController { $0.title = "A title:" $0.options = ["Peter Schmeichel", "David de Gea", "Oliver Kahn", "Fabien Barthez", "Tim Howard", "Gianluigi Buffon"] }.cellSetup({ (cell, row) in - (cell.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset = UIEdgeInsetsZero + (cell.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset = .zero (cell.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumInteritemSpacing = 40 cell.customizeCollectionViewCell = { _, cvcell in - cvcell.label.textColor = UIColor.redColor() - cvcell.layer.borderColor = UIColor.redColor().CGColor + cvcell.label.textColor = UIColor.red + cvcell.layer.borderColor = UIColor.red.cgColor cvcell.layer.borderWidth = 1 cvcell.layer.cornerRadius = 4 } @@ -53,14 +53,14 @@ class ViewController: FormViewController { if me.timer != nil { me.invalidateTimer() } - me.timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: me, selector: #selector(ViewController.timerFired(_:)), userInfo: ["text": string, "row": row], repeats: false) + me.timer = Timer.scheduledTimer(timeInterval: 0.5, target: me, selector: #selector(ViewController.timerFired(_:)), userInfo: ["text": string, "row": row], repeats: false) return [] } }.cellSetup({ (cell, row) in cell.customizeTableViewCell = { (user: User, cell: TRTableViewCell) -> Void in - if let avatar = user.avatar, let url = NSURL(string: avatar) { - cell.imageView?.af_setImageWithURL(url, placeholderImage: UIImage(named: "profile_empty")) + if let avatar = user.avatar, let url = URL(string: avatar) { + cell.imageView?.af_setImage(withURL: url, placeholderImage: UIImage(named: "profile_empty")) } } }) @@ -71,18 +71,18 @@ class ViewController: FormViewController { timer = nil } - func timerFired(timer: NSTimer) { + func timerFired(_ timer: Timer) { if let dict = (timer.userInfo as? Dictionary), let text = dict["text"] as? String, let row = dict["row"] as? TokenTableRow { - Alamofire.Manager.sharedInstance.request(.GET, "https://api.github.com/search/users?q=\(text)&per_page=5") - .responseCollection({ (response: Response<[User], BackendError>) in + Alamofire.SessionManager.default.request("https://api.github.com/search/users?q=\(text)&per_page=5") + .responseCollection(completionHandler: { (response: DataResponse<[User]>) in switch response.result { - case let .Success(value): + case let .success(value): row.cell.filteredTokens = value row.cell.reloadOptions() - case let .Failure(error): + case let .failure(error): print(error) } }) diff --git a/TokenRow/Sources/CollectionViewTokenCell.swift b/TokenRow/Sources/CollectionViewTokenCell.swift index 2957d2b..851f3f1 100644 --- a/TokenRow/Sources/CollectionViewTokenCell.swift +++ b/TokenRow/Sources/CollectionViewTokenCell.swift @@ -15,32 +15,32 @@ import CLTokenInputView public protocol EurekaTokenCollectionViewCell { associatedtype T: TokenSearchable - func setupForToken(token: T) + func setupForToken(_ token: T) func sizeThatFits() -> CGSize } /** Cell that is used in a TokenTableRow. shows a UITableView with options. Generic parameters are: Value of Row and Type of the Cell to be shown in the UITableView that shows the options */ -public class CollectionTokenCell: TokenCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { +open class CollectionTokenCell: TokenCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout where CollectionViewCell: EurekaTokenCollectionViewCell, CollectionViewCell.T == T { /// callback that can be used to cuustomize the appearance of the UICollectionViewCell in the inputAccessoryView public var customizeCollectionViewCell: ((T, CollectionViewCell) -> Void)? /// UICollectionView that acts as inputAccessoryView. public lazy var collectionView: UICollectionView? = { - let collectionView = UICollectionView(frame: CGRectMake(0, 0, self.contentView.frame.width, 50), collectionViewLayout: self.collectionViewLayout) + let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: self.contentView.frame.width, height: 50), collectionViewLayout: self.collectionViewLayout) collectionView.showsHorizontalScrollIndicator = false collectionView.delegate = self collectionView.dataSource = self - collectionView.backgroundColor = UIColor.whiteColor() - collectionView.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: self.cellReuseIdentifier) + collectionView.backgroundColor = UIColor.white + collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: self.cellReuseIdentifier) return collectionView }() public var collectionViewLayout: UICollectionViewLayout = { var layout = UICollectionViewFlowLayout() - layout.scrollDirection = .Horizontal + layout.scrollDirection = .horizontal layout.minimumLineSpacing = 10 layout.minimumInteritemSpacing = 10 layout.sectionInset = UIEdgeInsetsMake(5, 5, 5, 5) @@ -51,16 +51,20 @@ public class CollectionTokenCell>).getTokensForString(text) { filteredTokens = newTokens } @@ -74,38 +78,38 @@ public class CollectionTokenCell Int { + open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return filteredTokens.count } - public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { - let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellReuseIdentifier, forIndexPath: indexPath) as! CollectionViewCell - if filteredTokens.count > indexPath.row { - let token = filteredTokens[indexPath.row] + open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellReuseIdentifier, for: indexPath) as! CollectionViewCell + if filteredTokens.count > (indexPath as NSIndexPath).row { + let token = filteredTokens[(indexPath as NSIndexPath).row] cell.setupForToken(token) customizeCollectionViewCell?(token, cell) } return cell } - public func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { - if filteredTokens.count > indexPath.row { - let token = filteredTokens[indexPath.row] + open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + if filteredTokens.count > (indexPath as NSIndexPath).row { + let token = filteredTokens[(indexPath as NSIndexPath).row] (row as! _TokenRow).addToken(token) cellResignFirstResponder() } } - public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { - let cell = CollectionViewCell(frame: CGRectZero) - if filteredTokens.count > indexPath.row { - let token = filteredTokens[indexPath.row] + open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + let cell = CollectionViewCell(frame: CGRect.zero) + if filteredTokens.count > (indexPath as NSIndexPath).row { + let token = filteredTokens[(indexPath as NSIndexPath).row] cell.setupForToken(token) } return cell.sizeThatFits() } - public func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { + open func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } -} \ No newline at end of file +} diff --git a/TokenRow/Sources/String+TokenRow.swift b/TokenRow/Sources/String+TokenRow.swift index 292550c..bb60ca5 100644 --- a/TokenRow/Sources/String+TokenRow.swift +++ b/TokenRow/Sources/String+TokenRow.swift @@ -11,9 +11,9 @@ import Foundation extension String: TokenSearchable { public var displayString: String { return self } - public var identifier: NSObject { return self } + public var identifier: NSObject { return self as NSObject } public func contains(token: String) -> Bool { - return self.lowercaseString.containsString(token.lowercaseString) + return self.lowercased().contains(token.lowercased()) } -} \ No newline at end of file +} diff --git a/TokenRow/Sources/TRCollectionViewCell.swift b/TokenRow/Sources/TRCollectionViewCell.swift index 802e3d0..682a1d5 100644 --- a/TokenRow/Sources/TRCollectionViewCell.swift +++ b/TokenRow/Sources/TRCollectionViewCell.swift @@ -10,7 +10,7 @@ import Foundation import Eureka /// Default cell for the inputAccessoryView of the TokenAccessoryRow -public class TRCollectionViewCell: UICollectionViewCell, EurekaTokenCollectionViewCell { +open class TRCollectionViewCell: UICollectionViewCell, EurekaTokenCollectionViewCell { public typealias T = Token public var label = UILabel() @@ -26,25 +26,25 @@ public class TRCollectionViewCell: UICollectionViewCell, } func initialize() { - label.font = UIFont.systemFontOfSize(13) + label.font = UIFont.systemFont(ofSize: 13) label.numberOfLines = 2 label.minimumScaleFactor = 0.8 label.adjustsFontSizeToFitWidth = true - label.textColor = UIColor.blueColor() + label.textColor = UIColor.blue contentView.addSubview(label) - contentView.backgroundColor = UIColor.whiteColor() + contentView.backgroundColor = UIColor.white label.translatesAutoresizingMaskIntoConstraints = false - contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-(4)-[label]-(4)-|", options: [], metrics: nil, views: ["label": label])) - contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[label]|", options: [], metrics: nil, views: ["label": label])) + contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(4)-[label]-(4)-|", options: [], metrics: nil, views: ["label": label])) + contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[label]|", options: [], metrics: nil, views: ["label": label])) } - public func setupForToken(token: T) { + open func setupForToken(_ token: T) { label.text = token.displayString } - public func sizeThatFits() -> CGSize { - label.frame = CGRectMake(0, 0, 180, 40) + open func sizeThatFits() -> CGSize { + label.frame = CGRect(x: 0, y: 0, width: 180, height: 40) label.sizeToFit() - return CGSizeMake(label.frame.width + 8, 40) + return CGSize(width: label.frame.width + 8, height: 40) } -} \ No newline at end of file +} diff --git a/TokenRow/Sources/TRTableViewCell.swift b/TokenRow/Sources/TRTableViewCell.swift index a95869e..5f9cc4e 100644 --- a/TokenRow/Sources/TRTableViewCell.swift +++ b/TokenRow/Sources/TRTableViewCell.swift @@ -10,7 +10,7 @@ import Foundation import Eureka /// Default cell for the table of the TokenTableCell -public class TRTableViewCell: UITableViewCell, EurekaTokenTableViewCell { +open class TRTableViewCell: UITableViewCell, EurekaTokenTableViewCell { public typealias T = Token override init(style: UITableViewCellStyle, reuseIdentifier: String?) { @@ -24,14 +24,14 @@ public class TRTableViewCell: UITableViewCell, EurekaTok } func initialize() { - textLabel?.font = UIFont.systemFontOfSize(16) + textLabel?.font = UIFont.systemFont(ofSize: 16) textLabel?.minimumScaleFactor = 0.8 textLabel?.adjustsFontSizeToFitWidth = true - textLabel?.textColor = UIColor.blueColor() - contentView.backgroundColor = UIColor.whiteColor() + textLabel?.textColor = UIColor.blue + contentView.backgroundColor = UIColor.white } - public func setupForToken(token: T) { + open func setupForToken(_ token: T) { textLabel?.text = token.displayString } } diff --git a/TokenRow/Sources/TableViewTokenCell.swift b/TokenRow/Sources/TableViewTokenCell.swift index 2b06bf7..08e8cfe 100644 --- a/TokenRow/Sources/TableViewTokenCell.swift +++ b/TokenRow/Sources/TableViewTokenCell.swift @@ -16,11 +16,11 @@ import CLTokenInputView public protocol EurekaTokenTableViewCell { associatedtype T: TokenSearchable - func setupForToken(token: T) + func setupForToken(_ token: T) } /// Cell that is used in a TokenTableRow. shows a UITableView with options. Generic parameters are: Value of Row and Type of the Cell to be shown in the UITableView that shows the options -public class TableTokenCell: TokenCell, UITableViewDelegate, UITableViewDataSource { +open class TableTokenCell: TokenCell, UITableViewDelegate, UITableViewDataSource where TableViewCell: EurekaTokenTableViewCell, TableViewCell.T == T { /// callback that can be used to cuustomize the appearance of the UICollectionViewCell in the inputAccessoryView public var customizeTableViewCell: ((T, TableViewCell) -> Void)? @@ -35,38 +35,42 @@ public class TableTokenCell>).getTokensForString(text) { filteredTokens = newTokens } @@ -80,29 +84,29 @@ public class TableTokenCell Int { + open func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return filteredTokens.count } - public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCellWithIdentifier(cellReuseIdentifier) as! TableViewCell - if filteredTokens.count > indexPath.row { - let token = filteredTokens[indexPath.row] + open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! TableViewCell + if filteredTokens.count > (indexPath as NSIndexPath).row { + let token = filteredTokens[(indexPath as NSIndexPath).row] cell.setupForToken(token) customizeTableViewCell?(token, cell) } return cell } - public func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { - if filteredTokens.count > indexPath.row { - let token = filteredTokens[indexPath.row] + open func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if filteredTokens.count > (indexPath as NSIndexPath).row { + let token = filteredTokens[(indexPath as NSIndexPath).row] (row as! _TokenRow).addToken(token) cellResignFirstResponder() } } - public func numberOfSectionsInTableView(tableView: UITableView) -> Int { + open func numberOfSections(in tableView: UITableView) -> Int { return 1 } -} \ No newline at end of file +} diff --git a/TokenRow/Sources/TokenCell.swift b/TokenRow/Sources/TokenCell.swift index b9ff9f0..22c6313 100644 --- a/TokenRow/Sources/TokenCell.swift +++ b/TokenRow/Sources/TokenCell.swift @@ -15,7 +15,7 @@ public protocol TokenCellProtocol { var tokenView: CLTokenInputView { get } } -public class TokenCell: Cell>, CLTokenInputViewDelegate, TokenCellProtocol, CellType { +open class TokenCell: Cell>, CLTokenInputViewDelegate, TokenCellProtocol, CellType { /// View that contains the tokens of this row lazy public var tokenView: CLTokenInputView = { [weak self] in @@ -36,20 +36,24 @@ public class TokenCell: Cell>, CLTokenInputViewDelega required public init(style: UITableViewCellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } - public override func cellCanBecomeFirstResponder() -> Bool { + open override func cellCanBecomeFirstResponder() -> Bool { return !row.isDisabled } - public override func canBecomeFirstResponder() -> Bool { - return tokenView.canBecomeFirstResponder() + open override var canBecomeFirstResponder: Bool { + return tokenView.canBecomeFirstResponder } - public override func becomeFirstResponder() -> Bool { + open override func becomeFirstResponder() -> Bool { return tokenView.becomeFirstResponder() } - public override func cellResignFirstResponder() -> Bool { + open override func cellResignFirstResponder() -> Bool { hideOptions() return tokenView.resignFirstResponder() } @@ -58,15 +62,15 @@ public class TokenCell: Cell>, CLTokenInputViewDelega return row as! TokenRowProtocol } - public override func setup() { + open override func setup() { super.setup() contentView.addSubview(tokenView) setupConstraints() - selectionStyle = .None - tokenView.backgroundColor = .clearColor() + selectionStyle = .none + tokenView.backgroundColor = .clear } - public override func update() { + open override func update() { // Not calling super on purpose as we do not want to use textlabel nor detailTextLabel tokenView.fieldName = row.title tokenView.placeholderText = tokenRow.placeholder @@ -75,10 +79,10 @@ public class TokenCell: Cell>, CLTokenInputViewDelega /** Constrinats for this cell should be set up here. Custom constraints should be added here in an override */ - public func setupConstraints() { + open func setupConstraints() { let views = ["tokenView": tokenView] - contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[tokenView]|", options: .AlignAllBaseline, metrics: nil, views: views)) - contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[tokenView]|", options: .AlignAllBaseline, metrics: nil, views: views)) + contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[tokenView]|", options: .alignAllLastBaseline, metrics: nil, views: views)) + contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[tokenView]|", options: .alignAllLastBaseline, metrics: nil, views: views)) } /// Should show the list of options @@ -88,17 +92,17 @@ public class TokenCell: Cell>, CLTokenInputViewDelega func hideOptions() {} /// Should reload the list of options - public func reloadOptions() {} + open func reloadOptions() {} - public func tokenInputView(aView:CLTokenInputView, didAddToken token:CLToken) { + open func tokenInputView(_ aView:CLTokenInputView, didAdd token:CLToken) { tokenRow.addToken(token.context!) } - public func tokenInputView(aView:CLTokenInputView, didRemoveToken token:CLToken) { + open func tokenInputView(_ aView:CLTokenInputView, didRemove token:CLToken) { tokenRow.removeToken(token.context!) } - public func tokenInputView(aView: CLTokenInputView, tokenForText text: String) -> CLToken? { + open func tokenInputView(_ aView: CLTokenInputView, tokenForText text: String) -> CLToken? { if filteredTokens.count > 0 { let matchingToken = filteredTokens[0] let match = CLToken() @@ -109,16 +113,16 @@ public class TokenCell: Cell>, CLTokenInputViewDelega return nil } - public func tokenInputViewDidBeginEditing(view: CLTokenInputView) { - formViewController()?.beginEditing(self) + open func tokenInputViewDidBeginEditing(_ view: CLTokenInputView) { + formViewController()?.beginEditing(of: self) } - public func tokenInputViewDidEndEditing(view: CLTokenInputView) { - formViewController()?.endEditing(self) + open func tokenInputViewDidEndEditing(_ view: CLTokenInputView) { + formViewController()?.endEditing(of: self) hideOptions() } - public func tokenInputView(view: CLTokenInputView, didChangeHeightTo height: CGFloat) { + open func tokenInputView(_ view: CLTokenInputView, didChangeHeightTo height: CGFloat) { self.height = { height } formViewController()?.tableView?.beginUpdates() formViewController()?.tableView?.endUpdates() diff --git a/TokenRow/Sources/TokenRow.swift b/TokenRow/Sources/TokenRow.swift index 048142f..c439696 100644 --- a/TokenRow/Sources/TokenRow.swift +++ b/TokenRow/Sources/TokenRow.swift @@ -20,7 +20,7 @@ public protocol TokenSearchable: Hashable { } /// Generic TokenRow. Concrete classes should subclass this one and specify generic parameters -public class _TokenRow> : Row, Cell> { +open class _TokenRow : Row where Cell: CellType, Cell: TokenCellProtocol, Cell: TypedCellType, Cell.Value == Set { public var options: [T] = [] public var placeholder: String? @@ -31,41 +31,41 @@ public class _TokenRow [T]? = { [weak self] searchString in + open lazy var getTokensForString: (String) -> [T]? = { [weak self] searchString in guard let me = self else { return nil } // return options that have not been chosen and that contain the searchString return me.options.filter { return me.value == nil || !me.value!.contains($0) - }.filter { $0.contains(searchString) } + }.filter { $0.contains(token: searchString) } } /// remove a token by its identifier - public func removeToken(tokenIdentifier: NSObject) { + open func removeToken(_ tokenIdentifier: NSObject) { if let token = value?.filter({ $0.identifier == tokenIdentifier }).first { removeToken(token) } } /// remove a token from the list of chosen tokens - public func removeToken(token: T) { + open func removeToken(_ token: T) { value?.remove(token) if let cltoken = cell.tokenView.allTokens.filter({ $0.context == token.identifier }).first { - cell.tokenView.removeToken(cltoken) + cell.tokenView.remove(cltoken) } } /// add a token to the list of chosen tokens by identifier - public func addToken(tokenIdentifier: NSObject) { + open func addToken(_ tokenIdentifier: NSObject) { if let token = options.filter({$0.identifier == tokenIdentifier}).first { addToken(token) } } /// add a token from the list of chosen tokens - public func addToken(token: T) { + open func addToken(_ token: T) { value?.insert(token) - cell.tokenView.addToken(CLToken(displayText: token.displayString, context: token.identifier)) + cell.tokenView.add(CLToken(displayText: token.displayString, context: token.identifier)) } } @@ -89,8 +89,8 @@ public final class TokenTableRow: _TokenRow