diff --git a/DateTextField.xcodeproj/project.pbxproj b/DateTextField.xcodeproj/project.pbxproj index 9551a56..32b03da 100644 --- a/DateTextField.xcodeproj/project.pbxproj +++ b/DateTextField.xcodeproj/project.pbxproj @@ -231,7 +231,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0830; - LastUpgradeCheck = 0920; + LastUpgradeCheck = 0930; ORGANIZATIONNAME = "Beau Nouvelle"; TargetAttributes = { 2DF001511EBEFB75000157E1 = { @@ -380,7 +380,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -403,7 +403,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.pearpi.DateTextField; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -449,6 +449,7 @@ 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; @@ -456,6 +457,7 @@ 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; @@ -506,6 +508,7 @@ 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; @@ -513,6 +516,7 @@ 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; @@ -552,7 +556,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.pearpi.DateTextFieldDemo; PRODUCT_NAME = "DateTextField Demo"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; }; name = Debug; @@ -566,7 +570,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.pearpi.DateTextFieldDemo; PRODUCT_NAME = "DateTextField Demo"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; SWIFT_VERSION = 4.0; }; name = Release; diff --git a/DateTextField.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/DateTextField.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/DateTextField.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/DateTextField.xcodeproj/xcshareddata/xcschemes/DateTextField.xcscheme b/DateTextField.xcodeproj/xcshareddata/xcschemes/DateTextField.xcscheme index 20ab360..85ecdf8 100644 --- a/DateTextField.xcodeproj/xcshareddata/xcschemes/DateTextField.xcscheme +++ b/DateTextField.xcodeproj/xcshareddata/xcschemes/DateTextField.xcscheme @@ -1,6 +1,6 @@ @@ -37,7 +36,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/DateTextField.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme b/DateTextField.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme index c4c25c2..1dab14a 100644 --- a/DateTextField.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme +++ b/DateTextField.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme @@ -1,6 +1,6 @@ @@ -46,7 +45,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/DateTextField/DateTextField.swift b/DateTextField/DateTextField.swift index 3eb9102..bcf7e43 100644 --- a/DateTextField/DateTextField.swift +++ b/DateTextField/DateTextField.swift @@ -14,21 +14,21 @@ protocol DateTextFieldDelegate: class { } public class DateTextField: UITextField { - - public enum format: String { + + public enum Format: String { case monthYear = "MM'$'yyyy" case dayMonthYear = "dd'*'MM'$'yyyy" case monthDayYear = "MM'$'dd'*'yyyy" } - + // MARK: - Properties private let digitOnlyRegex = try! NSRegularExpression(pattern: "[^0-9]+", options: NSRegularExpression.Options(rawValue: 0)) private let dateFormatter = DateFormatter() - - public var dateFormat = format.dayMonthYear + + public var dateFormat = Format.dayMonthYear public var separator: String = " / " weak var customDelegate: DateTextFieldDelegate? - + /// Parses the `text` property into a `Date` and returns if successful. public var date: Date? { get { @@ -46,70 +46,70 @@ public class DateTextField: UITextField { } } } - + // MARK: - Lifecycle override init(frame: CGRect) { super.init(frame: frame) setup() } - + required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } - + private func setup() { super.delegate = self keyboardType = .numberPad autocorrectionType = .no } - + func numberOnlyString(with string: String) -> String { - return digitOnlyRegex.stringByReplacingMatches(in: string, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, string.count), withTemplate: "") + return digitOnlyRegex.stringByReplacingMatches(in: string, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSRange(location: 0, length: string.count), withTemplate: "") } - + } // MARK: - UITextFieldDelegate extension DateTextField: UITextFieldDelegate { - + public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - + if string.count == 0 { customDelegate?.dateDidChange(dateTextField: self) return true } - + guard let swiftRange = textField.text?.getRange(from: range) else { return false } guard let replacedString = textField.text?.replacingCharacters(in: swiftRange, with: string) else { return false } - + // Because you never know what people will paste in here, and some emoji have numbers present. let emojiFreeString = replacedString.stringByRemovingEmoji() let numbersOnly = numberOnlyString(with: emojiFreeString) - + switch dateFormat { case .monthYear: guard numbersOnly.count <= 6 else { return false } - let splitString = split(string: numbersOnly, format: [2,4]) + let splitString = split(string: numbersOnly, format: [2, 4]) textField.text = final(day: "", month: splitString.count > 0 ? splitString[0] : "", year: splitString.count > 1 ? splitString[1] : "") case .dayMonthYear: guard numbersOnly.count <= 8 else { return false } - let splitString = split(string: numbersOnly, format: [2,2,4]) + let splitString = split(string: numbersOnly, format: [2, 2, 4]) textField.text = final(day: splitString.count > 0 ? splitString[0] : "", month: splitString.count > 1 ? splitString[1] : "", year: splitString.count > 2 ? splitString[2] : "") case .monthDayYear: guard numbersOnly.count <= 8 else { return false } - let splitString = split(string: numbersOnly, format: [2,2,4]) + let splitString = split(string: numbersOnly, format: [2, 2, 4]) textField.text = final(day: splitString.count > 1 ? splitString[1] : "", month: splitString.count > 0 ? splitString[0] : "", year: splitString.count > 2 ? splitString[2] : "") } customDelegate?.dateDidChange(dateTextField: self) return false } - + func split(string: String, format: [Int]) -> [String] { - + var mutableString = string var splitString = [String]() - + for item in format { if mutableString.count == 0 { break @@ -123,17 +123,17 @@ extension DateTextField: UITextFieldDelegate { mutableString.removeSubrange(Range(uncheckedBounds: (mutableString.startIndex, mutableString.endIndex))) } } - + return splitString } - + func final(day: String, month: String, year: String) -> String { - + var dateString = dateFormat.rawValue dateString = dateString.replacingOccurrences(of: "dd", with: day) dateString = dateString.replacingOccurrences(of: "MM", with: month) dateString = dateString.replacingOccurrences(of: "yyyy", with: year) - + if day.count >= 2 { dateString = dateString.replacingOccurrences(of: "*", with: separator) } else { @@ -144,15 +144,15 @@ extension DateTextField: UITextFieldDelegate { } else { dateString = dateString.replacingOccurrences(of: "$", with: "") } - + return dateString.replacingOccurrences(of: "'", with: "") } - + } // MARK: - String Extension extension String { - + fileprivate func getRange(from nsRange: NSRange) -> Range? { guard let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex), @@ -162,11 +162,11 @@ extension String { else { return nil } return from ..< to } - + fileprivate func stringByRemovingEmoji() -> String { return String(self.filter { !$0.isEmoji() }) } - + } // MARK: - Character Extension @@ -176,4 +176,3 @@ extension Character { || Character(UnicodeScalar(UInt32(0x2100))!) <= self && self <= Character(UnicodeScalar(UInt32(0x26ff))!) } } - diff --git a/DateTextFieldTests/DateTextFieldTests.swift b/DateTextFieldTests/DateTextFieldTests.swift index 5635b34..5e90082 100644 --- a/DateTextFieldTests/DateTextFieldTests.swift +++ b/DateTextFieldTests/DateTextFieldTests.swift @@ -10,27 +10,27 @@ import XCTest @testable import DateTextField class DateTextFieldTests: XCTestCase { - + override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. } - + override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } - + func testExample() { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct results. } - + func testPerformanceExample() { // This is an example of a performance test case. self.measure { // Put the code you want to measure the time of here. } } - + } diff --git a/Demo/AppDelegate.swift b/Demo/AppDelegate.swift index 55a848a..52bbdad 100644 --- a/Demo/AppDelegate.swift +++ b/Demo/AppDelegate.swift @@ -13,7 +13,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true @@ -41,6 +40,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } - } - diff --git a/Demo/ViewController.swift b/Demo/ViewController.swift index f09a8fa..2d12a75 100644 --- a/Demo/ViewController.swift +++ b/Demo/ViewController.swift @@ -10,11 +10,11 @@ import UIKit import DateTextField class ViewController: UIViewController { - + @IBOutlet weak var dateTextField: DateTextField! @IBOutlet weak var displayDate: UILabel! @IBOutlet weak var formatTypeSegmentedControl: UISegmentedControl! - + override func viewDidLoad() { super.viewDidLoad() dateTextField.becomeFirstResponder() @@ -29,9 +29,9 @@ class ViewController: UIViewController { displayDate.text = formatter.string(from: dateTextField.date!) } } - + @IBAction func dateFormatChanged(_ sender: UISegmentedControl) { - + switch sender.selectedSegmentIndex { case 0: dateTextField.placeholder = "MM/YYYY" @@ -48,7 +48,6 @@ class ViewController: UIViewController { default: preconditionFailure("Selected index not handled") } - + } } -