├── .gitignore
├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── SweeterSwift
├── SweeterSwift.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── SweeterSwift.xcscheme
│ └── project.pbxproj
├── SweeterSwift.xcworkspace
│ ├── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
│ └── contents.xcworkspacedata
├── SweeterSwiftTests
│ ├── BundleTests.swift
│ ├── StringTests.swift
│ ├── Info.plist
│ ├── NSAttributedStringTests.swift
│ ├── CodableTests.swift
│ └── SwiftTests.swift
├── SweeterSwift
│ ├── SweeterSwift.h
│ └── Info.plist
├── Podfile.lock
└── Podfile
├── Source
├── PrivacyInfo.xcprivacy
├── TimeInterval+Sweeter.swift
├── DateFormatter+Sweeter.swift
├── UIViewController+Sweeter.swift
├── UIStackView+Sweeter.swift
├── NSObject+Sweeter.swift
├── Bundle+Sweeter.swift
├── Codable+Sweeter.swift
├── UITextView+Sweeter.swift
├── String+Sweeter.swift
├── NSAttributedString+Sweeter.swift
├── UIApplication+Sweeter.swift
├── NSManagedObjectContext+Sweeter.swift
├── Swift+Sweeter.swift
└── UIView+Sweeter.swift
├── Package.swift
├── SweeterSwift.podspec
├── LICENSE.txt
├── CHANGELOG.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | Pods
2 |
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [yonat]
2 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwift.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwift.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwift.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: yonat
7 |
8 | ---
9 |
10 | **Description:**
11 | [description]
12 |
13 | **Problems I encountered when trying to implement this myself:**
14 | [if none, please submit a pull request.]
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: yonat
7 |
8 | ---
9 |
10 | **Description of the problem:**
11 | [description]
12 |
13 | **Minimal project that reproduces the problem (so I'll be able to figure out how to fix it):**
14 | [link to a Minimal Reproducible Example as described at https://ootips.org/yonat/repex ]
15 |
--------------------------------------------------------------------------------
/Source/PrivacyInfo.xcprivacy:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSPrivacyTracking
6 |
7 | NSPrivacyCollectedDataTypes
8 |
9 | NSPrivacyAccessedAPITypes
10 |
11 | NSPrivacyTrackingDomains
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwiftTests/BundleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BundleTests.swift
3 | //
4 | // Created by Yonat Sharon on 2019-06-29.
5 | // Copyright © 2019 Yonat Sharon. All rights reserved.
6 | //
7 |
8 | import SweeterSwift
9 | import XCTest
10 |
11 | class BundleTests: XCTestCase {
12 | func testBundle() {
13 | XCTAssertEqual(Bundle.main.name, "xctest")
14 | XCTAssertTrue(Bundle.main.infoString.contains(" "))
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwiftTests/StringTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringTests.swift
3 | //
4 | // Created by Yonat Sharon on 2019-06-29.
5 | // Copyright © 2019 Yonat Sharon. All rights reserved.
6 | //
7 |
8 | import SweeterSwift
9 | import XCTest
10 |
11 | class StringTests: XCTestCase {
12 | func testUnCamelCase() {
13 | XCTAssertEqual("winterIsComing".unCamelCased, "Winter Is Coming")
14 | XCTAssertEqual("winterIsComing".camelToSnakeCased, "winter_is_coming")
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Source/TimeInterval+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimeInterval+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import Foundation
8 |
9 | // swiftlint:disable no_magic_numbers
10 | public extension TimeInterval {
11 | static let minute: TimeInterval = 60
12 | static let hour: TimeInterval = 60 * minute
13 | static let day: TimeInterval = 24 * hour
14 | static let week: TimeInterval = 7 * day
15 | static let year: TimeInterval = 365.25 * day
16 | static let month: TimeInterval = year / 12
17 | }
18 |
--------------------------------------------------------------------------------
/Source/DateFormatter+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DateFormatter+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import Foundation
8 |
9 | public extension DateFormatter {
10 | /// Sweeter: Create a new formatter with format string.
11 | convenience init(format: String, timeZone: TimeZone = .current, locale: String? = nil) {
12 | self.init()
13 | dateFormat = format
14 | self.timeZone = timeZone
15 | if let locale = locale {
16 | self.locale = Locale(identifier: locale)
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwift/SweeterSwift.h:
--------------------------------------------------------------------------------
1 | //
2 | // SweeterSwift.h
3 | // SweeterSwift
4 | //
5 | // Created by Yonat Sharon on 29/06/2019.
6 | // Copyright © 2019 Yonat Sharon. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for SweeterSwift.
12 | FOUNDATION_EXPORT double SweeterSwiftVersionNumber;
13 |
14 | //! Project version string for SweeterSwift.
15 | FOUNDATION_EXPORT const unsigned char SweeterSwiftVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.6
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "SweeterSwift",
7 | platforms: [
8 | .iOS(.v9),
9 | ],
10 | products: [
11 | .library(name: "SweeterSwift", targets: ["SweeterSwift"]),
12 | ],
13 | dependencies: [],
14 | targets: [
15 | .target(name: "SweeterSwift", dependencies: [], path: "Source", resources: [.process("PrivacyInfo.xcprivacy")]),
16 | .testTarget(name: "SweeterSwiftTests", dependencies: ["SweeterSwift"], path: "SweeterSwift/SweeterSwiftTests"),
17 | ],
18 | swiftLanguageVersions: [.v5]
19 | )
20 |
--------------------------------------------------------------------------------
/Source/UIViewController+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import UIKit
8 |
9 | public extension UIViewController {
10 | /// Sweeter: Add child view controller pinned to specific places.
11 | /// Example: addConstrainedChild(pages, constrain: .bottomMargin, .top, .left, .right)
12 | func addConstrainedChild(_ viewController: UIViewController, constrain: NSLayoutConstraint.Attribute...) {
13 | addChild(viewController)
14 | view.addConstrainedSubview(viewController.view, constrainedAttributes: constrain)
15 | viewController.didMove(toParent: self)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Source/UIStackView+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIStackView+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import UIKit
8 |
9 | public extension UIStackView {
10 | /// Sweeter: Remove `subview` from the view hierarchy, not just the stack arrangement.
11 | func removeArrangedSubviewCompletely(_ subview: UIView) {
12 | removeArrangedSubview(subview)
13 | subview.removeFromSuperview()
14 | }
15 |
16 | /// Sweeter: Remove all arranged subviews from the view hierarchy, not just the stack arrangement.
17 | func removeAllArrangedSubviewsCompletely() {
18 | for subview in arrangedSubviews.reversed() {
19 | removeArrangedSubviewCompletely(subview)
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Source/NSObject+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import Foundation
8 |
9 | public extension NSObject {
10 | /// Sweeter: Post a local notification using `NotificationCenter.default`.
11 | func notify(_ notificationName: Notification.Name, userInfo: [AnyHashable: Any]? = nil) {
12 | NotificationCenter.default.post(name: notificationName, object: self, userInfo: userInfo)
13 | }
14 |
15 | /// Sweeter: Respond to a local notification from `NotificationCenter.default`.
16 | func observeNotification(name: Notification.Name, selector: Selector, object: Any? = nil) {
17 | NotificationCenter.default.addObserver(self, selector: selector, name: name, object: object)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/SweeterSwift.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = "SweeterSwift"
4 | s.version = "1.2.6"
5 | s.summary = "Extensions and syntactic sugar to enrich the Swift standard library, iOS frameworks, and SwifterSwift."
6 |
7 | s.homepage = "https://github.com/yonat/SweeterSwift"
8 | s.license = { :type => "MIT", :file => "LICENSE.txt" }
9 | s.author = { "Yonat Sharon" => "yonat@ootips.org" }
10 |
11 | s.swift_version = '4.2'
12 | s.swift_versions = ['4.2', '5.0']
13 | s.platform = :ios, "9.0"
14 | s.requires_arc = true
15 |
16 | s.source = { :git => "https://github.com/yonat/SweeterSwift.git", :tag => s.version }
17 | s.source_files = "Source/*.swift"
18 | s.resource_bundles = {'SweeterSwift' => ['Source/PrivacyInfo.xcprivacy']}
19 |
20 | end
21 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwift/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.2.2
19 | CFBundleVersion
20 | 41
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwiftTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Source/Bundle+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Bundle+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import Foundation
8 |
9 | public extension Bundle {
10 | /// Sweeter: app name with reasonable fallback to process name
11 | var name: String {
12 | return infoDictionary?["CFBundleDisplayName"] as? String
13 | ?? infoDictionary?["CFBundleName"] as? String
14 | ?? ProcessInfo.processInfo.processName
15 | }
16 |
17 | /// Sweeter: app name, version, and build number
18 | var infoString: String {
19 | let version = infoDictionary?["CFBundleShortVersionString"] as? String
20 | let build = infoDictionary?["CFBundleVersion"] as? String
21 |
22 | let nameAndVersion = [name, version].compact.joined(separator: " ")
23 | return [nameAndVersion, build].compact.joined(separator: " #")
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Source/Codable+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Codable+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import Foundation
8 |
9 | public extension Decodable {
10 | /// Sweeter: Create object from a dictionary
11 | init?(dictionary: [String: Any]) {
12 | guard let data = try? JSONSerialization.data(withJSONObject: dictionary, options: .prettyPrinted) else { return nil }
13 | guard let decodedSelf = try? JSONDecoder().decode(Self.self, from: data) else { return nil }
14 | self = decodedSelf
15 | }
16 | }
17 |
18 | public extension Encodable {
19 | /// Sweeter: Export object to a dictionary representation
20 | var dictionary: [String: Any]? {
21 | guard let data = try? JSONEncoder().encode(self) else { return nil }
22 | return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap { $0 as? [String: Any] }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Source/UITextView+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UITextView+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import UIKit
8 |
9 | public extension UITextView {
10 | /// Sweeter: Create a label with links, by using a `UITextView` to auto-detect links and simulate `UILabel` appearance.
11 | @available(iOS 9, *)
12 | @available(tvOS, unavailable)
13 | @available(macOS, unavailable)
14 | convenience init(simulatedLabelWithLinksInText: String, font: UIFont = UIFont.systemFont(ofSize: UIFont.labelFontSize)) {
15 | self.init()
16 | text = simulatedLabelWithLinksInText
17 | isEditable = false
18 | dataDetectorTypes = .link
19 | textAlignment = .center
20 | textContainerInset = .zero
21 | backgroundColor = .clear
22 | self.font = font
23 | constrain(.height, to: font.pointSize * 1.5) // swiftlint:disable:this no_magic_numbers
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/SweeterSwift/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - SweeterSwift (1.2.1)
3 | - SwiftFormat/CLI (0.48.1)
4 | - SwiftLint (0.41.0)
5 | - SwiftQuality (1.1.1):
6 | - SwiftFormat/CLI (= 0.48.1)
7 | - SwiftLint (= 0.41.0)
8 |
9 | DEPENDENCIES:
10 | - SweeterSwift (from `..`)
11 | - SwiftQuality (from `https://github.com/yonat/SwiftQuality`)
12 |
13 | SPEC REPOS:
14 | trunk:
15 | - SwiftFormat
16 | - SwiftLint
17 |
18 | EXTERNAL SOURCES:
19 | SweeterSwift:
20 | :path: ".."
21 | SwiftQuality:
22 | :git: https://github.com/yonat/SwiftQuality
23 |
24 | CHECKOUT OPTIONS:
25 | SwiftQuality:
26 | :commit: acf4031acdaf3e6f3e035ad6d6de9ab8b83f4e17
27 | :git: https://github.com/yonat/SwiftQuality
28 |
29 | SPEC CHECKSUMS:
30 | SweeterSwift: 266367986dec90ba53bf521eabe0210e22e80445
31 | SwiftFormat: 094c5e2e6c36dafdd128d04cff4a0a7d87492e73
32 | SwiftLint: c585ebd615d9520d7fbdbe151f527977b0534f1e
33 | SwiftQuality: fba6a2775b0e35f9d8c945fd0011c44c8b0e93bd
34 |
35 | PODFILE CHECKSUM: 2a19f03182702703782ea18706704da1e9dc9cc0
36 |
37 | COCOAPODS: 1.12.1
38 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Yonat Sharon
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/Source/String+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // String+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import Foundation
8 |
9 | extension String {
10 | /// Sweeter: Separate CamelCase into capitalized words.
11 | /// E.g., "winterIsComing" -> "Winter Is Coming"
12 | public var unCamelCased: String {
13 | return replacingCamelCase(with: "$1 $2").capitalized
14 | }
15 |
16 | /// Sweeter: Change CamelCase into snake_case
17 | /// E.g., "winterIsComing" -> "winter_is_coming"
18 | public var camelToSnakeCased: String {
19 | return replacingCamelCase(with: "$1_$2").lowercased()
20 | }
21 |
22 | func replacingCamelCase(with template: String) -> String {
23 | return String.camelCaseWordBoundaryRegex
24 | .stringByReplacingMatches(in: self, range: NSRange(startIndex..., in: self), withTemplate: template)
25 | }
26 |
27 | static let camelCaseWordBoundaryRegex: NSRegularExpression = {
28 | do {
29 | return try NSRegularExpression(pattern: "([a-z])([A-Z])")
30 | } catch {
31 | fatalError(error.localizedDescription)
32 | }
33 | }()
34 | }
35 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwiftTests/NSAttributedStringTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSAttributedStringTests.swift
3 | // swiftlint:disable no_magic_numbers
4 | //
5 | // Created by Yonat Sharon on 2019-06-29.
6 | // Copyright © 2019 Yonat Sharon. All rights reserved.
7 | //
8 |
9 | import SweeterSwift
10 | import XCTest
11 |
12 | class NSAttributedStringTests: XCTestCase {
13 | func testInitFromHTML() {
14 | let stringFromHTML = NSAttributedString(htmlString: "Text with bold and italic parts.")
15 | XCTAssertEqual(stringFromHTML?.string, "Text with bold and italic parts.")
16 | XCTAssertTrue(stringFromHTML?.traits(at: 12)?.contains(.traitBold) ?? false)
17 | XCTAssertTrue(stringFromHTML?.traits(at: 24)?.contains(.traitItalic) ?? false)
18 | }
19 |
20 | func testLinkAnchorTextToURL() {
21 | let stringWithAnchor = NSMutableAttributedString(string: "Text with anchor text to link")
22 | stringWithAnchor.link(anchorText: "anchor text", url: "https://ootips.org")
23 | XCTAssertNotNil(stringWithAnchor.attributes(at: 12, effectiveRange: nil)[.link])
24 | }
25 | }
26 |
27 | extension NSAttributedString {
28 | func traits(at index: Int) -> UIFontDescriptor.SymbolicTraits? {
29 | return (attributes(at: index, effectiveRange: nil)[.font] as? UIFont)?.fontDescriptor.symbolicTraits
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Source/NSAttributedString+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSAttributedString+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import Foundation
8 |
9 | public extension NSAttributedString {
10 | /// Sweeter: Create attributed string from HTML
11 | convenience init?(htmlString: String, defaultAttributes: [NSAttributedString.Key: Any]? = nil) {
12 | guard let data = htmlString.data(using: .utf8) else { return nil }
13 | let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
14 | .documentType: NSAttributedString.DocumentType.html,
15 | .characterEncoding: String.Encoding.utf8.rawValue,
16 | .defaultAttributes: defaultAttributes ?? [:],
17 | ]
18 |
19 | try? self.init(data: data, options: options, documentAttributes: nil)
20 | }
21 | }
22 |
23 | public extension NSMutableAttributedString {
24 | /// Sweeter: Make part of the string into a link.
25 | ///
26 | /// - Parameters:
27 | /// - url: link address.
28 | /// - anchorText: substring to make into a link.
29 | func link(anchorText: String, url: String) {
30 | guard let urlObject = URL(string: url) else { return }
31 | let anchorRange = mutableString.range(of: anchorText, options: [.caseInsensitive, .diacriticInsensitive, .widthInsensitive])
32 | guard NSNotFound != anchorRange.location else { return }
33 | addAttribute(.link, value: urlObject, range: anchorRange)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Source/UIApplication+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIApplication+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import UIKit
8 |
9 | public extension UIApplication {
10 | /// Sweeter: `keyWindow` for scene-based apps
11 | var legacyKeyWindow: UIWindow? {
12 | if #available(iOS 13, *) {
13 | return windows.first { $0.isKeyWindow }
14 | } else {
15 | return keyWindow
16 | }
17 | }
18 |
19 | /// Sweeter: Returns the currently top-most view controller.
20 | class func topViewController(base: UIViewController? = UIApplication.shared.legacyKeyWindow?.rootViewController) -> UIViewController? {
21 | if let nav = base as? UINavigationController {
22 | return topViewController(base: nav.visibleViewController)
23 | }
24 | if let tab = base as? UITabBarController {
25 | if let selected = tab.selectedViewController {
26 | return topViewController(base: selected)
27 | }
28 | }
29 | if let presented = base?.presentedViewController {
30 | return topViewController(base: presented)
31 | }
32 | return base
33 | }
34 |
35 | /// Sweeter: Show `viewController` over the top-most view controller.
36 | class func present(_ viewController: UIViewController, animated: Bool = true, completion: (() -> Void)? = nil) {
37 | DispatchQueue.main.async {
38 | topViewController()?.present(viewController, animated: animated, completion: completion)
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/SweeterSwift/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '9.3'
2 | use_frameworks!
3 |
4 | pod 'SweeterSwift', :path => '..'
5 | pod 'SwiftQuality', :git => 'https://github.com/yonat/SwiftQuality'
6 |
7 | def quality_scripts
8 | script_phase :name => 'SwiftFormat',
9 | :execution_position => :before_compile,
10 | :script => 'if [ "Debug" == "${CONFIGURATION}" ]; then "${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat" --swiftversion ${SWIFT_VERSION} --config "${PODS_ROOT}/SwiftQuality/.swiftformat" "${SRCROOT}/.." ; fi'
11 |
12 | script_phase :name => 'SwiftLintAutocorrect',
13 | :execution_position => :before_compile,
14 | :script => 'if [ "Debug" == "${CONFIGURATION}" ]; then "${PODS_ROOT}/SwiftLint/swiftlint" autocorrect --config "${PODS_ROOT}/SwiftQuality/.swiftlint.yml" --path "${SRCROOT}/.." ; fi'
15 |
16 | script_phase :name => 'SwiftLint',
17 | :execution_position => :after_compile,
18 | :script => 'if [ "Debug" == "${CONFIGURATION}" ]; then "${PODS_ROOT}/SwiftLint/swiftlint" --config "${PODS_ROOT}/SwiftQuality/.swiftlint.yml" --path "${SRCROOT}/.." ; fi'
19 | end
20 |
21 | target 'SweeterSwift' do
22 | quality_scripts
23 | end
24 |
25 | target 'SweeterSwiftTests' do
26 | quality_scripts
27 | end
28 |
29 | # Workaround for Xcode 15 error DT_TOOLCHAIN_DIR cannot be used to evaluate LIBRARY_SEARCH_PATHS
30 | post_install do |installer|
31 | installer.aggregate_targets.each do |target|
32 | target.xcconfigs.each do |variant, xcconfig|
33 | xcconfig_path = target.client_root + target.xcconfig_relative_path(variant)
34 | IO.write(xcconfig_path, IO.read(xcconfig_path).gsub("DT_TOOLCHAIN_DIR", "TOOLCHAIN_DIR"))
35 | end
36 | end
37 | installer.pods_project.targets.each do |target|
38 | target.build_configurations.each do |config|
39 | if config.base_configuration_reference.is_a? Xcodeproj::Project::Object::PBXFileReference
40 | xcconfig_path = config.base_configuration_reference.real_path
41 | IO.write(xcconfig_path, IO.read(xcconfig_path).gsub("DT_TOOLCHAIN_DIR", "TOOLCHAIN_DIR"))
42 | end
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwiftTests/CodableTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CodableTests.swift
3 | // swiftlint:disable no_magic_numbers
4 | //
5 | // Created by Yonat Sharon on 2019-06-29.
6 | // Copyright © 2019 Yonat Sharon. All rights reserved.
7 | //
8 |
9 | import SweeterSwift
10 | import XCTest
11 |
12 | struct CodableTestStruct: Codable {
13 | var number: Int
14 | var string: String
15 | var flag: Bool
16 | var optionalFloat: Float?
17 | }
18 |
19 | class CodableTests: XCTestCase {
20 | let testStruct = CodableTestStruct(number: 42, string: "How many roads", flag: true)
21 | let testDictionary: [String: Any] = [
22 | "number": 42,
23 | "string": "How many roads",
24 | "flag": true,
25 | ]
26 |
27 | func testInitFromDictionary() throws {
28 | let structFromDictionary = try XCTUnwrap(CodableTestStruct(dictionary: testDictionary))
29 | XCTAssertEqual(structFromDictionary.number, 42)
30 | XCTAssertEqual(structFromDictionary.string, "How many roads")
31 | XCTAssertEqual(structFromDictionary.flag, true)
32 | XCTAssertNil(structFromDictionary.optionalFloat)
33 | }
34 |
35 | func testSaveToDictionary() throws {
36 | let dictionaryFromStruct = try XCTUnwrap(testStruct.dictionary)
37 | XCTAssertEqual(dictionaryFromStruct["number"] as? Int, 42)
38 | XCTAssertEqual(dictionaryFromStruct["string"] as? String, "How many roads")
39 | XCTAssertEqual(dictionaryFromStruct["flag"] as? Bool, true)
40 | XCTAssertNil(dictionaryFromStruct["optionalFloat"])
41 | }
42 |
43 | func testCodableNameConflict() throws {
44 | let testDecodableStruct = TestDecodableStruct(dictionary: ["number": 1, "string": "Sweeter"])
45 | XCTAssertEqual(testDecodableStruct?.number, 42)
46 | XCTAssertEqual(testDecodableStruct?.string, "Override Sweeter init")
47 | }
48 | }
49 |
50 | struct TestDecodableStruct {
51 | var number: Int
52 | var string: String
53 | }
54 |
55 | extension TestDecodableStruct: Decodable {}
56 |
57 | extension TestDecodableStruct {
58 | init?(dictionary: [String: Any]) {
59 | self.init(number: 42, string: "Override Sweeter init")
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6 |
7 | ## [1.2.6] - 2023-08-19
8 |
9 | ### Fixed
10 | - fix privacy manifest PrivacyInfo.xcprivacy.
11 |
12 | ## [1.2.2] - 2023-08-19
13 |
14 | ### Added
15 | - add privacy manifest PrivacyInfo.xcprivacy.
16 |
17 | ## [1.2.1] - 2022-04-07
18 |
19 | ### Fixed
20 | - fix crash on iOS 14 when using Xcode 13.3. (thanks tylerjames!)
21 |
22 | ## [1.2.0] - 2022-02-01
23 |
24 | ### Added
25 | - add to `NSManagedObjectContext.printAllObjects()` optional variadic parameter `entityName`.
26 | - add `NSManagedObjectContext.deleteAllObjects()`.
27 |
28 | ## [1.1.5] - 2021-05-15
29 |
30 | ### Fixed
31 | - fix #3 tvOS build error.
32 |
33 | ## [1.1.4] - 2020-09-21
34 |
35 | ### Added
36 | - add `UIApplication.shared.legacyKeyWindow` to get `keyWindow` for scene-based apps.
37 |
38 | ## [1.1.3] - 2020-02-23
39 |
40 | ### Changed
41 | - rename `Decodable.init(from:)` to `Decodable.init(dictionary:)` to avoid clash with R.swift .
42 |
43 | ## [1.1.2] - 2020-02-07
44 |
45 | ### Fixed
46 | - fix build error when importing using spm.
47 |
48 | ## [1.1.1] - 2020-02-05
49 |
50 | ### Fixed
51 | - fix crash on third-party code that doesn't implement default constructor for classes derived from NSObject.
52 |
53 | ## [1.1.0] - 2020-02-03
54 |
55 | ### Added
56 | - add optional `identifier` parameter to `UIView.constrain`.
57 | - add `weak(self, in: MyClass.foo)` to avoid retain cycles when passing a member function as an @escaping closure.
58 |
59 | ## [1.0.5] - 2019-09-21
60 |
61 | ### Fixed
62 | - mark `simulatedLabelWithLinksInText` unavailable in tvOS, so that interface builder will not show an erroneous error.
63 |
64 | ## [1.0.4] - 2019-09-16
65 |
66 | ### Added
67 | - add operator =? to assign iff right side is not nil (useful for wrapping old UIView classes in new SwiftUI wrappers).
68 |
69 | ## [1.0.2] - 2019-08-22
70 |
71 | ### Added
72 | - support Swift Package Manager.
73 |
74 | ## [1.0.1] - 2019-07-23
75 |
76 | ### Added
77 | - optional priority for UIView constraints.
78 |
79 | ## [1.0.0]
80 |
81 | ### Added
82 | - initial release.
83 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwiftTests/SwiftTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftTests.swift
3 | // swiftlint:disable no_magic_numbers
4 | //
5 | // Created by Yonat Sharon on 2019-06-29.
6 | // Copyright © 2019 Yonat Sharon. All rights reserved.
7 | //
8 |
9 | import SweeterSwift
10 | import UIKit
11 | import XCTest
12 |
13 | enum SwiftTestEnum: CaseIterable {
14 | case first, second, third, fourth, fifth, sixth
15 | }
16 |
17 | class SwiftTests: XCTestCase {
18 | func testEnumIndex() {
19 | XCTAssertEqual(SwiftTestEnum.first.index, 0)
20 | XCTAssertEqual(SwiftTestEnum.third.index, 2)
21 | XCTAssertEqual(SwiftTestEnum.sixth.index, 5)
22 | }
23 |
24 | func testCompactSequence() {
25 | let arrayOfOptionals: [Int?] = [0, 1, nil, 2, nil, nil, 3]
26 | XCTAssertEqual(arrayOfOptionals.compact, [0, 1, 2, 3])
27 | }
28 |
29 | func testWeakSelfInMemberFunction() {
30 | class Foo: DefaultConstructible {
31 | static var refCount = 0
32 |
33 | func foo() {}
34 | func fooWithParam(n: Int) {}
35 | func fooWithReturn() -> String { "" }
36 | func fooWithParamAndReturn(array: [Character]) -> Double { 0 }
37 |
38 | lazy var fooRef = weak(self, in: Foo.foo)
39 | lazy var fooWithParamRef = weak(self, in: Foo.fooWithParam)
40 | lazy var fooWithReturnRef = weak(self, in: Foo.fooWithReturn)
41 | lazy var fooWithParamAndReturnRef = weak(self, in: Foo.fooWithParamAndReturn)
42 |
43 | required init() {
44 | fooRef()
45 | fooWithParamRef(7)
46 | _ = fooWithReturn()
47 | _ = fooWithParamAndReturnRef([])
48 | Foo.refCount += 1
49 | }
50 |
51 | deinit {
52 | Foo.refCount -= 1
53 | }
54 | }
55 |
56 | XCTAssertEqual(Foo.refCount, 0)
57 |
58 | for _ in 0 ..< 3 {
59 | let aFoo = Foo()
60 | aFoo.foo()
61 | XCTAssertEqual(Foo.refCount, 1)
62 | }
63 |
64 | XCTAssertEqual(Foo.refCount, 0)
65 | }
66 |
67 | func testOptionableValue() {
68 | let optionalStepper: UIStepper? = UIStepper()
69 | optionalStepper?.value = 42
70 | XCTAssertEqual(optionalStepper?.value, 42)
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Source/NSManagedObjectContext+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSManagedObjectContext+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import CoreData
8 |
9 | public extension NSManagedObjectContext {
10 | /// Sweeter: Names of all entities in the object model associated with the receiver
11 | var allEntityNames: [String] {
12 | return persistentStoreCoordinator?.managedObjectModel.entities.compactMap(\.name) ?? []
13 | }
14 |
15 | /// Sweeter: Delete all objects, or all objects of specific entity name(s).
16 | func deleteAllObjects(entityName: String...) throws {
17 | let entityNames = entityName.isEmpty ? allEntityNames : entityName
18 | for entityName in entityNames {
19 | let deleteFetch = NSFetchRequest(entityName: entityName)
20 | let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
21 | try execute(deleteRequest)
22 | }
23 | }
24 |
25 | /// Sweeter: Dump contents to console - for debugging
26 | func printAllObjects(entityName: String...) {
27 | let entityNames = entityName.isEmpty ? allEntityNames : entityName
28 | for entityName in entityNames {
29 | guard let objects = try? fetch(NSFetchRequest(entityName: entityName)) else { continue }
30 | print("== \(entityName) (\(objects.count)) ==")
31 | for object in objects {
32 | print(String(describing: object))
33 | }
34 | }
35 | }
36 |
37 | /// Sweeter: Create a copy of the store for backup or for using later as initial setup
38 | func backupStore() {
39 | guard let persistentStoreCoordinator = persistentStoreCoordinator else { return }
40 | guard let sourceStore = persistentStoreCoordinator.persistentStores.first else { return }
41 | let backupCoordinator = NSPersistentStoreCoordinator(managedObjectModel: persistentStoreCoordinator.managedObjectModel)
42 |
43 | let intermediateStoreOptions = (sourceStore.options ?? [:]).merging([NSReadOnlyPersistentStoreOption: true], uniquingKeysWith: { $1 })
44 | guard let intermediateStore = try? backupCoordinator.addPersistentStore(
45 | ofType: sourceStore.type,
46 | configurationName: sourceStore.configurationName,
47 | at: sourceStore.url,
48 | options: intermediateStoreOptions
49 | ) else { return }
50 |
51 | let backupStoreOptions: [AnyHashable: Any] = [
52 | NSReadOnlyPersistentStoreOption: true,
53 | // Disable write-ahead logging so that the entire store will be
54 | // contained in a single file. No need to handle -wal/-shm files.
55 | // https://developer.apple.com/library/content/qa/qa1809/_index.html
56 | NSSQLitePragmasOption: ["journal_mode": "DELETE"],
57 | // Minimize file size
58 | NSSQLiteManualVacuumOption: true,
59 | ]
60 |
61 | let basename = sourceStore.url?.deletingPathExtension().lastPathComponent ?? "store"
62 | let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last ?? URL(fileURLWithPath: ".")
63 | let backupURL = documentsDirectory.appendingPathComponent("\(basename)-backup.sqlite")
64 | print("Backed up store to " + backupURL.path)
65 | _ = try? backupCoordinator.migratePersistentStore(intermediateStore, to: backupURL, options: backupStoreOptions, withType: NSSQLiteStoreType)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Source/Swift+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Swift+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-21.
5 | //
6 |
7 | public extension CaseIterable where Self: Equatable {
8 | /// Sweeter: Index of current case in `allCases`.
9 | var index: Int {
10 | let all = Array(Self.allCases)
11 | return all.firstIndex(of: self)! // swiftlint:disable:this force_unwrapping
12 | }
13 | }
14 |
15 | // from https://gist.github.com/siejkowski/a2b187800f2e28b53c96
16 |
17 | public extension Sequence where Element: Optionable {
18 | /// Sweeter: Shorthand for `compactMap { $0 }`.
19 | var compact: [Element.Wrapped] {
20 | return compactMap { $0.value }
21 | }
22 | }
23 |
24 | public protocol Optionable {
25 | associatedtype Wrapped
26 | var value: Wrapped? { get }
27 | }
28 |
29 | // extension for Optional provides the implementations for Optional enum
30 | extension Optional: Optionable {
31 | public var value: Wrapped? { return self }
32 | }
33 |
34 | infix operator =?: AssignmentPrecedence
35 |
36 | /// Sweeter: Assign iff right side is not nil.
37 | public func =? (lhs: inout T, rhs: T?) {
38 | if nil != rhs, let rhs = rhs {
39 | lhs = rhs
40 | }
41 | }
42 |
43 | public protocol DefaultConstructible {
44 | init()
45 | }
46 |
47 | extension Optional: DefaultConstructible {
48 | public init() {
49 | self = .none
50 | }
51 | }
52 |
53 | extension IntegerLiteralType: DefaultConstructible {}
54 | extension BooleanLiteralType: DefaultConstructible {}
55 | extension FloatLiteralType: DefaultConstructible {}
56 | extension StringLiteralType: DefaultConstructible {}
57 | extension Array: DefaultConstructible {}
58 | extension Dictionary: DefaultConstructible {}
59 | extension Set: DefaultConstructible {}
60 |
61 | // based on https://sveinhal.github.io/2016/03/16/retain-cycles-function-references/
62 |
63 | /// Sweeter: Pass a member function as an @escaping closure without retaining its object.
64 | ///
65 | /// Example: `var closure = weak(self, in: MyClass.someFunction)`
66 | public func weak(_ instance: T, in classFunction: @escaping (T) -> () -> Void) -> () -> Void {
67 | return { [weak instance] in
68 | guard let instance = instance else { return }
69 | classFunction(instance)()
70 | }
71 | }
72 |
73 | /// Sweeter: Pass a member function as an @escaping closure without retaining its object.
74 | ///
75 | /// Example: `var closure = weak(self, in: MyClass.someFunction)`
76 | public func weak(_ instance: T, in classFunction: @escaping (T) -> (U) -> Void) -> (U) -> Void {
77 | return { [weak instance] arguments in
78 | guard let instance = instance else { return }
79 | classFunction(instance)(arguments)
80 | }
81 | }
82 |
83 | /// Sweeter: Pass a member function as an @escaping closure without retaining its object.
84 | ///
85 | /// Example: `var closure = weak(self, in: MyClass.someFunction)`
86 | public func weak(_ instance: T, in classFunction: @escaping (T) -> () -> V) -> () -> V {
87 | return { [weak instance] in
88 | guard let instance = instance else { return V() }
89 | return classFunction(instance)()
90 | }
91 | }
92 |
93 | /// Sweeter: Pass a member function as an @escaping closure without retaining its object.
94 | ///
95 | /// Example: `var closure = weak(self, in: MyClass.someFunction)`
96 | public func weak(_ instance: T, in classFunction: @escaping (T) -> (U) -> V) -> (U) -> V {
97 | return { [weak instance] arguments in
98 | guard let instance = instance else { return V() }
99 | return classFunction(instance)(arguments)
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwift.xcodeproj/xcshareddata/xcschemes/SweeterSwift.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/Source/UIView+Sweeter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Sweeter.swift
3 | //
4 | // Created by Yonat Sharon on 2019-02-08.
5 | //
6 |
7 | import UIKit
8 |
9 | public extension UIView {
10 | /// Sweeter: Set constant attribute. Example: `constrain(.width, to: 17)`
11 | @discardableResult func constrain(
12 | _ at: NSLayoutConstraint.Attribute,
13 | to: CGFloat = 0,
14 | ratio: CGFloat = 1,
15 | relation: NSLayoutConstraint.Relation = .equal,
16 | priority: UILayoutPriority = .required,
17 | identifier: String? = nil
18 | ) -> NSLayoutConstraint {
19 | let constraint = NSLayoutConstraint(
20 | item: self, attribute: at, relatedBy: relation,
21 | toItem: nil, attribute: .notAnAttribute, multiplier: ratio, constant: to
22 | )
23 | constraint.priority = priority
24 | constraint.identifier = identifier
25 | addConstraintWithoutConflict(constraint)
26 | return constraint
27 | }
28 |
29 | /// Sweeter: Pin subview at a specific place. Example: `constrain(label, at: .top)`
30 | @discardableResult func constrain(
31 | _ subview: UIView,
32 | at: NSLayoutConstraint.Attribute,
33 | diff: CGFloat = 0,
34 | ratio: CGFloat = 1,
35 | relation: NSLayoutConstraint.Relation = .equal,
36 | priority: UILayoutPriority = .required,
37 | identifier: String? = nil
38 | ) -> NSLayoutConstraint {
39 | let constraint = NSLayoutConstraint(
40 | item: subview, attribute: at, relatedBy: relation,
41 | toItem: self, attribute: at, multiplier: ratio, constant: diff
42 | )
43 | constraint.priority = priority
44 | constraint.identifier = identifier
45 | addConstraintWithoutConflict(constraint)
46 | return constraint
47 | }
48 |
49 | /// Sweeter: Pin two subviews to each other. Example:
50 | ///
51 | /// `constrain(label, at: .leading, to: textField)`
52 | ///
53 | /// `constrain(textField, at: .top, to: label, at: .bottom, diff: 8)`
54 | @discardableResult func constrain(
55 | _ subview: UIView,
56 | at: NSLayoutConstraint.Attribute,
57 | to subview2: UIView,
58 | at at2: NSLayoutConstraint.Attribute = .notAnAttribute,
59 | diff: CGFloat = 0,
60 | ratio: CGFloat = 1,
61 | relation: NSLayoutConstraint.Relation = .equal,
62 | priority: UILayoutPriority = .required,
63 | identifier: String? = nil
64 | ) -> NSLayoutConstraint {
65 | let at2real = at2 == .notAnAttribute ? at : at2
66 | let constraint = NSLayoutConstraint(
67 | item: subview, attribute: at, relatedBy: relation,
68 | toItem: subview2, attribute: at2real, multiplier: ratio, constant: diff
69 | )
70 | constraint.priority = priority
71 | constraint.identifier = identifier
72 | addConstraintWithoutConflict(constraint)
73 | return constraint
74 | }
75 |
76 | /// Sweeter: Add subview pinned to specific places. Example: `addConstrainedSubview(button, constrain: .centerX, .centerY)`
77 | @discardableResult func addConstrainedSubview(_ subview: UIView, constrain: NSLayoutConstraint.Attribute...) -> [NSLayoutConstraint] {
78 | return addConstrainedSubview(subview, constrainedAttributes: constrain)
79 | }
80 |
81 | @discardableResult internal func addConstrainedSubview(_ subview: UIView, constrainedAttributes: [NSLayoutConstraint.Attribute]) -> [NSLayoutConstraint] {
82 | subview.translatesAutoresizingMaskIntoConstraints = false
83 | addSubview(subview)
84 | return constrainedAttributes.map { self.constrain(subview, at: $0) }
85 | }
86 |
87 | internal func addConstraintWithoutConflict(_ constraint: NSLayoutConstraint) {
88 | removeConstraints(constraints.filter {
89 | constraint.firstItem === $0.firstItem
90 | && constraint.secondItem === $0.secondItem
91 | && constraint.firstAttribute == $0.firstAttribute
92 | && constraint.secondAttribute == $0.secondAttribute
93 | })
94 | addConstraint(constraint)
95 | }
96 |
97 | /// Sweeter: Search the view hierarchy recursively for a subview that conforms to `predicate`
98 | func viewInHierarchy(frontFirst: Bool = true, where predicate: (UIView) -> Bool) -> UIView? {
99 | if predicate(self) { return self }
100 | let views = frontFirst ? subviews.reversed() : subviews
101 | for subview in views {
102 | if let found = subview.viewInHierarchy(frontFirst: frontFirst, where: predicate) {
103 | return found
104 | }
105 | }
106 | return nil
107 | }
108 |
109 | /// Sweeter: Search the view hierarchy recursively for a subview with `aClass`
110 | func viewWithClass(_ aClass: T.Type, frontFirst: Bool = true) -> T? {
111 | return viewInHierarchy(frontFirst: frontFirst, where: { $0 is T }) as? T
112 | }
113 |
114 | /// Sweeter: The color used to tint the view, as inherited from its superviews.
115 | var actualTintColor: UIColor {
116 | var tintedView: UIView? = self
117 | while let currentView = tintedView, nil == currentView.tintColor {
118 | tintedView = currentView.superview
119 | }
120 | return tintedView?.tintColor ?? UIColor(red: 0, green: 0.5, blue: 1, alpha: 1) // swiftlint:disable:this no_magic_numbers
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SweeterSwift
2 |
3 |
4 | [![Swift Version][swift-image]][swift-url]
5 | [![Build Status][travis-image]][travis-url]
6 | [![License][license-image]][license-url]
7 | [](https://img.shields.io/cocoapods/v/SweeterSwift.svg)
8 | [](http://cocoapods.org/pods/SweeterSwift)
9 | [](http://makeapullrequest.com)
10 |
11 | Extensions and syntactic sugar to enrich the Swift standard library, iOS frameworks, and [SwifterSwift](https://github.com/SwifterSwift/SwifterSwift).
12 |
13 | ## Installation
14 |
15 | ### CocoaPods:
16 |
17 | ```ruby
18 | pod 'SweeterSwift'
19 | ```
20 |
21 | ### Swift Package Manager:
22 |
23 | ```swift
24 | dependencies: [
25 | .package(url: "https://github.com/yonat/SweeterSwift", from: "1.2.6")
26 | ]
27 | ```
28 |
29 | ## Usage
30 |
31 | * [Auto Layout](#auto-layout)
32 | * [Bundle](#bundle)
33 | * [Codable](#codable)
34 | * [DateFormatter](#dateformatter)
35 | * [NotificationCenter](#notificationcenter)
36 | * [NSAttributedString](#nsattributedstring)
37 | * [NSManagedObjectContext](#nsmanagedobjectcontext)
38 | * [String](#string)
39 | * [Swift Standard Library](#swift-standard-library)
40 | * [TimeInterval](#timeinterval)
41 | * [UIApplication](#uiapplication)
42 | * [UILabel / UITextView](#uilabel-uitextview)
43 | * [UIStackView](#uistackview)
44 | * [UIView](#uiview)
45 |
46 |
47 | ### Auto Layout
48 |
49 | Add button at the center of view:
50 |
51 | ```swift
52 | view.addConstrainedSubview(button, constrain: .centerX, .centerY)
53 | ```
54 |
55 | Put label over textField:
56 |
57 | ```swift
58 | view.constrain(label, at: .leading, to: textField)
59 | view.constrain(textField, at: .top, to: label, at: .bottom, diff: 8)
60 | ```
61 |
62 | Add child view controller covering all but the bottom margin:
63 |
64 | ```swift
65 | addConstrainedChild(vc, constrain: .bottomMargin, .top, .left, .right)
66 | ```
67 |
68 | ### Bundle
69 |
70 | App name with reasonable fallback to process name:
71 |
72 | ```swift
73 | let appName = Bundle.main.name
74 | ```
75 |
76 | App info string with name, version, and build number:
77 |
78 | ```swift
79 | let appInfo = Bundle.main.infoString // "MyApp 1.0 #42"
80 | ```
81 |
82 | ### Codable
83 |
84 | Create object from a dictionary:
85 |
86 | ```swift
87 | let decodableObject = MyDecodableClass(dictionary: aDictionary)
88 | ```
89 |
90 | Export object to a dictionary:
91 |
92 | ```swift
93 | let aDictionary = encodableObject.dictionary
94 | ```
95 |
96 | ### DateFormatter
97 |
98 | Create with format:
99 |
100 | ```swift
101 | let dateFormatter = DateFormatter(format: "cccc, MMMM dd")
102 | ```
103 |
104 | ### NotificationCenter
105 |
106 | Post a local notification using `NotificationCenter.default`:
107 |
108 | ```swift
109 | notify(notificationName, userInfo: infoDictionary)
110 | ```
111 |
112 | Respond to a local notification from `NotificationCenter.default`:
113 |
114 | ```swift
115 | observeNotification(notificationName, selector: #selector(someFunc))
116 | ```
117 |
118 | ### NSAttributedString
119 |
120 | Create from HTML:
121 |
122 | ```swift
123 | let attributedString = NSAttributedString(htmlString: "Hello, world!")
124 | ```
125 |
126 | Turn a substring into a link:
127 |
128 | ```swift
129 | mutableAttributedString.link(anchorText: "Hello", url: "https://ootips.org")
130 | ```
131 |
132 | ### NSManagedObjectContext
133 |
134 | Dump contents to console for debugging:
135 |
136 | ```swift
137 | managedObjectContext.printAllObjects()
138 | ```
139 |
140 | Create a copy of the store for backup or for using later as initial setup:
141 |
142 | ```swift
143 | managedObjectContext.backupStore()
144 | ```
145 |
146 | ### String
147 |
148 | Separate CamelCase into capitalized words:
149 |
150 | ```swift
151 | let words = "winterIsComing".unCamelCased // "Winter Is Coming"
152 | ```
153 |
154 | Change CamelCase into snake_case:
155 |
156 | ```swift
157 | let key = "winterIsComing".camelToSnakeCased // "winter_is_coming"
158 | ```
159 |
160 | ### Swift Standard Library
161 |
162 | Index of current enum case in `allCases`:
163 |
164 | ```swift
165 | let index = MyEnum.someCase.index
166 | ```
167 |
168 | Unwrap collection, shorthand for `compactMap { $0 }`:
169 |
170 | ```swift
171 | let nonOptionals = optionalsCollection.compact
172 | ```
173 |
174 | Avoid retain cycles when passing a member function as an @escaping closure:
175 |
176 | ```swift
177 | var closure = weak(self, in: MyClass.someFunction)
178 | ```
179 |
180 | ### TimeInterval
181 |
182 | Standard time intervals:
183 |
184 | ```swift
185 | let myInterval: TimeInterval = .year + .month + .week + .day + .hour + .minute
186 | ```
187 |
188 | ### UIApplication
189 |
190 | Find the top-most view controller:
191 |
192 | ```swift
193 | let topVC = UIApplication.topViewController()
194 | ```
195 |
196 | Present modal over the top view controller:
197 |
198 | ```swift
199 | UIApplication.present(modalVC)
200 | ```
201 |
202 | ### UILabel / UITextView
203 |
204 | Create a label with links by using a `UITextView` to auto-detect links and simulate `UILabel` appearance:
205 |
206 | ```swift
207 | let hyperlinkedLabel = UITextView(simulatedLabelWithLinksInText: "More at https://ootips.org")
208 | ```
209 |
210 | ### UIStackView
211 |
212 | Remove an arranged subview from the view hierarchy, not just the stack arrangement:
213 |
214 | ```swift
215 | stackView.removeArrangedSubviewCompletely(subview)
216 | ```
217 |
218 | Remove all arranged subviews from the view hierarchy, not just the stack arrangement:
219 |
220 | ```swift
221 | stackView.removeAllArrangedSubviewsCompletely()
222 | ```
223 |
224 | ### UIView
225 |
226 | Search the view hierarchy recursively for a subview that meets a condition:
227 |
228 | ```swift
229 | let blueSubview = view.viewInHierarchy(where { $0.backgroundColor == .blue })
230 | ```
231 |
232 | Search the view hierarchy recursively for a subview with a specific class:
233 |
234 | ```swift
235 | let button = view.viewWithClass(UIButton.self)
236 | ```
237 |
238 |
239 | ## Meta
240 |
241 | [@yonatsharon](https://twitter.com/yonatsharon)
242 |
243 | [https://github.com/yonat/SweeterSwift](https://github.com/yonat/SweeterSwift)
244 |
245 | [swift-image]:https://img.shields.io/badge/swift-5.0-orange.svg
246 | [swift-url]: https://swift.org/
247 | [license-image]: https://img.shields.io/badge/License-MIT-blue.svg
248 | [license-url]: LICENSE.txt
249 | [travis-image]: https://img.shields.io/travis/dbader/node-datadog-metrics/master.svg?style=flat-square
250 | [travis-url]: https://travis-ci.org/dbader/node-datadog-metrics
251 |
--------------------------------------------------------------------------------
/SweeterSwift/SweeterSwift.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 51;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 07284F5B590A0ED462322095 /* Pods_SweeterSwiftTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC2984858EBCDD93C0E95C87 /* Pods_SweeterSwiftTests.framework */; };
11 | 860DDA0DD3CCFF0B1A997E00 /* Pods_SweeterSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A1861DE58465E6B65F6095D /* Pods_SweeterSwift.framework */; };
12 | DC7BD85722C7C4FB0046FFFA /* SweeterSwift.h in Headers */ = {isa = PBXBuildFile; fileRef = DC7BD84922C7C4FB0046FFFA /* SweeterSwift.h */; settings = {ATTRIBUTES = (Public, ); }; };
13 | DC7BD86722C7C7B00046FFFA /* SwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD86622C7C7B00046FFFA /* SwiftTests.swift */; };
14 | DC7BD86922C7C7B00046FFFA /* SweeterSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC7BD84622C7C4FB0046FFFA /* SweeterSwift.framework */; };
15 | DC7BD88222C7CA1E0046FFFA /* NSAttributedString+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87422C7CA1E0046FFFA /* NSAttributedString+Sweeter.swift */; };
16 | DC7BD88322C7CA1E0046FFFA /* DateFormatter+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87522C7CA1E0046FFFA /* DateFormatter+Sweeter.swift */; };
17 | DC7BD88422C7CA1E0046FFFA /* String+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87622C7CA1E0046FFFA /* String+Sweeter.swift */; };
18 | DC7BD88522C7CA1E0046FFFA /* UIApplication+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87722C7CA1E0046FFFA /* UIApplication+Sweeter.swift */; };
19 | DC7BD88622C7CA1E0046FFFA /* UITextView+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87822C7CA1E0046FFFA /* UITextView+Sweeter.swift */; };
20 | DC7BD88722C7CA1E0046FFFA /* NSManagedObjectContext+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87922C7CA1E0046FFFA /* NSManagedObjectContext+Sweeter.swift */; };
21 | DC7BD88822C7CA1E0046FFFA /* Bundle+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87A22C7CA1E0046FFFA /* Bundle+Sweeter.swift */; };
22 | DC7BD88922C7CA1E0046FFFA /* Codable+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87B22C7CA1E0046FFFA /* Codable+Sweeter.swift */; };
23 | DC7BD88A22C7CA1E0046FFFA /* Swift+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87C22C7CA1E0046FFFA /* Swift+Sweeter.swift */; };
24 | DC7BD88B22C7CA1E0046FFFA /* UIViewController+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87D22C7CA1E0046FFFA /* UIViewController+Sweeter.swift */; };
25 | DC7BD88C22C7CA1E0046FFFA /* UIStackView+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87E22C7CA1E0046FFFA /* UIStackView+Sweeter.swift */; };
26 | DC7BD88D22C7CA1E0046FFFA /* NSObject+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD87F22C7CA1E0046FFFA /* NSObject+Sweeter.swift */; };
27 | DC7BD88E22C7CA1E0046FFFA /* TimeInterval+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD88022C7CA1E0046FFFA /* TimeInterval+Sweeter.swift */; };
28 | DC7BD88F22C7CA1E0046FFFA /* UIView+Sweeter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD88122C7CA1E0046FFFA /* UIView+Sweeter.swift */; };
29 | DC7BD89122C7DAF70046FFFA /* NSAttributedStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD89022C7DAF70046FFFA /* NSAttributedStringTests.swift */; };
30 | DC7BD89322C7DC620046FFFA /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD89222C7DC620046FFFA /* StringTests.swift */; };
31 | DC7BD89522C7EA2B0046FFFA /* BundleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD89422C7EA2B0046FFFA /* BundleTests.swift */; };
32 | DC7BD89722C7EAC40046FFFA /* CodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7BD89622C7EAC40046FFFA /* CodableTests.swift */; };
33 | /* End PBXBuildFile section */
34 |
35 | /* Begin PBXContainerItemProxy section */
36 | DC7BD86A22C7C7B00046FFFA /* PBXContainerItemProxy */ = {
37 | isa = PBXContainerItemProxy;
38 | containerPortal = DC7BD83D22C7C4FB0046FFFA /* Project object */;
39 | proxyType = 1;
40 | remoteGlobalIDString = DC7BD84522C7C4FB0046FFFA;
41 | remoteInfo = SweeterSwift;
42 | };
43 | /* End PBXContainerItemProxy section */
44 |
45 | /* Begin PBXFileReference section */
46 | 2CCD433E24A0BDB1106A3D61 /* Pods-SweeterSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SweeterSwift.debug.xcconfig"; path = "Target Support Files/Pods-SweeterSwift/Pods-SweeterSwift.debug.xcconfig"; sourceTree = ""; };
47 | 7E30926EC2BD4FB85BB3108B /* Pods-SweeterSwiftTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SweeterSwiftTests.release.xcconfig"; path = "Target Support Files/Pods-SweeterSwiftTests/Pods-SweeterSwiftTests.release.xcconfig"; sourceTree = ""; };
48 | 841073221FF5B2AF5BB49742 /* Pods-SweeterSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SweeterSwift.release.xcconfig"; path = "Target Support Files/Pods-SweeterSwift/Pods-SweeterSwift.release.xcconfig"; sourceTree = ""; };
49 | 8A1861DE58465E6B65F6095D /* Pods_SweeterSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SweeterSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
50 | DC7BD84622C7C4FB0046FFFA /* SweeterSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SweeterSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
51 | DC7BD84922C7C4FB0046FFFA /* SweeterSwift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SweeterSwift.h; sourceTree = ""; };
52 | DC7BD84A22C7C4FB0046FFFA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
53 | DC7BD86422C7C7B00046FFFA /* SweeterSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SweeterSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
54 | DC7BD86622C7C7B00046FFFA /* SwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTests.swift; sourceTree = ""; };
55 | DC7BD86822C7C7B00046FFFA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
56 | DC7BD87422C7CA1E0046FFFA /* NSAttributedString+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Sweeter.swift"; sourceTree = ""; };
57 | DC7BD87522C7CA1E0046FFFA /* DateFormatter+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Sweeter.swift"; sourceTree = ""; };
58 | DC7BD87622C7CA1E0046FFFA /* String+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Sweeter.swift"; sourceTree = ""; };
59 | DC7BD87722C7CA1E0046FFFA /* UIApplication+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Sweeter.swift"; sourceTree = ""; };
60 | DC7BD87822C7CA1E0046FFFA /* UITextView+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITextView+Sweeter.swift"; sourceTree = ""; };
61 | DC7BD87922C7CA1E0046FFFA /* NSManagedObjectContext+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Sweeter.swift"; sourceTree = ""; };
62 | DC7BD87A22C7CA1E0046FFFA /* Bundle+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Bundle+Sweeter.swift"; sourceTree = ""; };
63 | DC7BD87B22C7CA1E0046FFFA /* Codable+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Codable+Sweeter.swift"; sourceTree = ""; };
64 | DC7BD87C22C7CA1E0046FFFA /* Swift+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Swift+Sweeter.swift"; sourceTree = ""; };
65 | DC7BD87D22C7CA1E0046FFFA /* UIViewController+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Sweeter.swift"; sourceTree = ""; };
66 | DC7BD87E22C7CA1E0046FFFA /* UIStackView+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStackView+Sweeter.swift"; sourceTree = ""; };
67 | DC7BD87F22C7CA1E0046FFFA /* NSObject+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSObject+Sweeter.swift"; sourceTree = ""; };
68 | DC7BD88022C7CA1E0046FFFA /* TimeInterval+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TimeInterval+Sweeter.swift"; sourceTree = ""; };
69 | DC7BD88122C7CA1E0046FFFA /* UIView+Sweeter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Sweeter.swift"; sourceTree = ""; };
70 | DC7BD89022C7DAF70046FFFA /* NSAttributedStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedStringTests.swift; sourceTree = ""; };
71 | DC7BD89222C7DC620046FFFA /* StringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = ""; };
72 | DC7BD89422C7EA2B0046FFFA /* BundleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BundleTests.swift; sourceTree = ""; };
73 | DC7BD89622C7EAC40046FFFA /* CodableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableTests.swift; sourceTree = ""; };
74 | DC7BD89822C7F68A0046FFFA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; };
75 | DC7BD89922C7F68A0046FFFA /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = CHANGELOG.md; path = ../CHANGELOG.md; sourceTree = ""; };
76 | EB5626A87EBAC9FB4EE89466 /* Pods-SweeterSwiftTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SweeterSwiftTests.debug.xcconfig"; path = "Target Support Files/Pods-SweeterSwiftTests/Pods-SweeterSwiftTests.debug.xcconfig"; sourceTree = ""; };
77 | FC2984858EBCDD93C0E95C87 /* Pods_SweeterSwiftTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SweeterSwiftTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
78 | /* End PBXFileReference section */
79 |
80 | /* Begin PBXFrameworksBuildPhase section */
81 | DC7BD84322C7C4FB0046FFFA /* Frameworks */ = {
82 | isa = PBXFrameworksBuildPhase;
83 | buildActionMask = 2147483647;
84 | files = (
85 | 860DDA0DD3CCFF0B1A997E00 /* Pods_SweeterSwift.framework in Frameworks */,
86 | );
87 | runOnlyForDeploymentPostprocessing = 0;
88 | };
89 | DC7BD86122C7C7B00046FFFA /* Frameworks */ = {
90 | isa = PBXFrameworksBuildPhase;
91 | buildActionMask = 2147483647;
92 | files = (
93 | DC7BD86922C7C7B00046FFFA /* SweeterSwift.framework in Frameworks */,
94 | 07284F5B590A0ED462322095 /* Pods_SweeterSwiftTests.framework in Frameworks */,
95 | );
96 | runOnlyForDeploymentPostprocessing = 0;
97 | };
98 | /* End PBXFrameworksBuildPhase section */
99 |
100 | /* Begin PBXGroup section */
101 | A973AB6F69C64733BFAD39F4 /* Frameworks */ = {
102 | isa = PBXGroup;
103 | children = (
104 | 8A1861DE58465E6B65F6095D /* Pods_SweeterSwift.framework */,
105 | FC2984858EBCDD93C0E95C87 /* Pods_SweeterSwiftTests.framework */,
106 | );
107 | name = Frameworks;
108 | sourceTree = "";
109 | };
110 | D50430A535E3B884148CE11D /* Pods */ = {
111 | isa = PBXGroup;
112 | children = (
113 | 2CCD433E24A0BDB1106A3D61 /* Pods-SweeterSwift.debug.xcconfig */,
114 | 841073221FF5B2AF5BB49742 /* Pods-SweeterSwift.release.xcconfig */,
115 | EB5626A87EBAC9FB4EE89466 /* Pods-SweeterSwiftTests.debug.xcconfig */,
116 | 7E30926EC2BD4FB85BB3108B /* Pods-SweeterSwiftTests.release.xcconfig */,
117 | );
118 | path = Pods;
119 | sourceTree = "";
120 | };
121 | DC7BD83C22C7C4FB0046FFFA = {
122 | isa = PBXGroup;
123 | children = (
124 | DC7BD89822C7F68A0046FFFA /* README.md */,
125 | DC7BD89922C7F68A0046FFFA /* CHANGELOG.md */,
126 | DC7BD87322C7CA1E0046FFFA /* Source */,
127 | DC7BD84822C7C4FB0046FFFA /* SweeterSwift */,
128 | DC7BD86522C7C7B00046FFFA /* SweeterSwiftTests */,
129 | DC7BD84722C7C4FB0046FFFA /* Products */,
130 | D50430A535E3B884148CE11D /* Pods */,
131 | A973AB6F69C64733BFAD39F4 /* Frameworks */,
132 | );
133 | sourceTree = "";
134 | };
135 | DC7BD84722C7C4FB0046FFFA /* Products */ = {
136 | isa = PBXGroup;
137 | children = (
138 | DC7BD84622C7C4FB0046FFFA /* SweeterSwift.framework */,
139 | DC7BD86422C7C7B00046FFFA /* SweeterSwiftTests.xctest */,
140 | );
141 | name = Products;
142 | sourceTree = "";
143 | };
144 | DC7BD84822C7C4FB0046FFFA /* SweeterSwift */ = {
145 | isa = PBXGroup;
146 | children = (
147 | DC7BD84922C7C4FB0046FFFA /* SweeterSwift.h */,
148 | DC7BD84A22C7C4FB0046FFFA /* Info.plist */,
149 | );
150 | path = SweeterSwift;
151 | sourceTree = "";
152 | };
153 | DC7BD86522C7C7B00046FFFA /* SweeterSwiftTests */ = {
154 | isa = PBXGroup;
155 | children = (
156 | DC7BD86822C7C7B00046FFFA /* Info.plist */,
157 | DC7BD89022C7DAF70046FFFA /* NSAttributedStringTests.swift */,
158 | DC7BD89222C7DC620046FFFA /* StringTests.swift */,
159 | DC7BD89422C7EA2B0046FFFA /* BundleTests.swift */,
160 | DC7BD89622C7EAC40046FFFA /* CodableTests.swift */,
161 | DC7BD86622C7C7B00046FFFA /* SwiftTests.swift */,
162 | );
163 | path = SweeterSwiftTests;
164 | sourceTree = "";
165 | };
166 | DC7BD87322C7CA1E0046FFFA /* Source */ = {
167 | isa = PBXGroup;
168 | children = (
169 | DC7BD87422C7CA1E0046FFFA /* NSAttributedString+Sweeter.swift */,
170 | DC7BD87522C7CA1E0046FFFA /* DateFormatter+Sweeter.swift */,
171 | DC7BD87622C7CA1E0046FFFA /* String+Sweeter.swift */,
172 | DC7BD87722C7CA1E0046FFFA /* UIApplication+Sweeter.swift */,
173 | DC7BD87822C7CA1E0046FFFA /* UITextView+Sweeter.swift */,
174 | DC7BD87922C7CA1E0046FFFA /* NSManagedObjectContext+Sweeter.swift */,
175 | DC7BD87A22C7CA1E0046FFFA /* Bundle+Sweeter.swift */,
176 | DC7BD87B22C7CA1E0046FFFA /* Codable+Sweeter.swift */,
177 | DC7BD87C22C7CA1E0046FFFA /* Swift+Sweeter.swift */,
178 | DC7BD87D22C7CA1E0046FFFA /* UIViewController+Sweeter.swift */,
179 | DC7BD87E22C7CA1E0046FFFA /* UIStackView+Sweeter.swift */,
180 | DC7BD87F22C7CA1E0046FFFA /* NSObject+Sweeter.swift */,
181 | DC7BD88022C7CA1E0046FFFA /* TimeInterval+Sweeter.swift */,
182 | DC7BD88122C7CA1E0046FFFA /* UIView+Sweeter.swift */,
183 | );
184 | name = Source;
185 | path = ../Source;
186 | sourceTree = "";
187 | };
188 | /* End PBXGroup section */
189 |
190 | /* Begin PBXHeadersBuildPhase section */
191 | DC7BD84122C7C4FB0046FFFA /* Headers */ = {
192 | isa = PBXHeadersBuildPhase;
193 | buildActionMask = 2147483647;
194 | files = (
195 | DC7BD85722C7C4FB0046FFFA /* SweeterSwift.h in Headers */,
196 | );
197 | runOnlyForDeploymentPostprocessing = 0;
198 | };
199 | /* End PBXHeadersBuildPhase section */
200 |
201 | /* Begin PBXNativeTarget section */
202 | DC7BD84522C7C4FB0046FFFA /* SweeterSwift */ = {
203 | isa = PBXNativeTarget;
204 | buildConfigurationList = DC7BD85A22C7C4FB0046FFFA /* Build configuration list for PBXNativeTarget "SweeterSwift" */;
205 | buildPhases = (
206 | AC9CF0C9D911503A4E51014E /* [CP] Check Pods Manifest.lock */,
207 | DC7BD84122C7C4FB0046FFFA /* Headers */,
208 | 7BBF9EB03B2533D86CBFA454 /* [CP-User] SwiftFormat */,
209 | 7527C9AF64CED71731CB051B /* [CP-User] SwiftLintAutocorrect */,
210 | DC7BD84222C7C4FB0046FFFA /* Sources */,
211 | DC7BD84322C7C4FB0046FFFA /* Frameworks */,
212 | DC7BD84422C7C4FB0046FFFA /* Resources */,
213 | 6FDE19AE23F9D318D0EA3D82 /* [CP-User] SwiftLint */,
214 | );
215 | buildRules = (
216 | );
217 | dependencies = (
218 | );
219 | name = SweeterSwift;
220 | productName = SweeterSwift;
221 | productReference = DC7BD84622C7C4FB0046FFFA /* SweeterSwift.framework */;
222 | productType = "com.apple.product-type.framework";
223 | };
224 | DC7BD86322C7C7B00046FFFA /* SweeterSwiftTests */ = {
225 | isa = PBXNativeTarget;
226 | buildConfigurationList = DC7BD86E22C7C7B00046FFFA /* Build configuration list for PBXNativeTarget "SweeterSwiftTests" */;
227 | buildPhases = (
228 | 47346164AA5A56B45FEABEA5 /* [CP] Check Pods Manifest.lock */,
229 | ADC0E09EF1516A58D8F1F414 /* [CP-User] SwiftFormat */,
230 | 6A6825C739C7214D6DBED9E2 /* [CP-User] SwiftLintAutocorrect */,
231 | DC7BD86022C7C7B00046FFFA /* Sources */,
232 | DC7BD86122C7C7B00046FFFA /* Frameworks */,
233 | DC7BD86222C7C7B00046FFFA /* Resources */,
234 | E8D61AEAE019F1BE39F833AE /* [CP-User] SwiftLint */,
235 | 6BEE5A36F2607305F11A6C5D /* [CP] Embed Pods Frameworks */,
236 | );
237 | buildRules = (
238 | );
239 | dependencies = (
240 | DC7BD86B22C7C7B00046FFFA /* PBXTargetDependency */,
241 | );
242 | name = SweeterSwiftTests;
243 | productName = SweeterSwiftTests;
244 | productReference = DC7BD86422C7C7B00046FFFA /* SweeterSwiftTests.xctest */;
245 | productType = "com.apple.product-type.bundle.unit-test";
246 | };
247 | /* End PBXNativeTarget section */
248 |
249 | /* Begin PBXProject section */
250 | DC7BD83D22C7C4FB0046FFFA /* Project object */ = {
251 | isa = PBXProject;
252 | attributes = {
253 | LastSwiftUpdateCheck = 1020;
254 | LastUpgradeCheck = 1020;
255 | ORGANIZATIONNAME = "Yonat Sharon";
256 | TargetAttributes = {
257 | DC7BD84522C7C4FB0046FFFA = {
258 | CreatedOnToolsVersion = 10.2.1;
259 | };
260 | DC7BD86322C7C7B00046FFFA = {
261 | CreatedOnToolsVersion = 10.2.1;
262 | };
263 | };
264 | };
265 | buildConfigurationList = DC7BD84022C7C4FB0046FFFA /* Build configuration list for PBXProject "SweeterSwift" */;
266 | compatibilityVersion = "Xcode 9.3";
267 | developmentRegion = en;
268 | hasScannedForEncodings = 0;
269 | knownRegions = (
270 | en,
271 | );
272 | mainGroup = DC7BD83C22C7C4FB0046FFFA;
273 | productRefGroup = DC7BD84722C7C4FB0046FFFA /* Products */;
274 | projectDirPath = "";
275 | projectRoot = "";
276 | targets = (
277 | DC7BD84522C7C4FB0046FFFA /* SweeterSwift */,
278 | DC7BD86322C7C7B00046FFFA /* SweeterSwiftTests */,
279 | );
280 | };
281 | /* End PBXProject section */
282 |
283 | /* Begin PBXResourcesBuildPhase section */
284 | DC7BD84422C7C4FB0046FFFA /* Resources */ = {
285 | isa = PBXResourcesBuildPhase;
286 | buildActionMask = 2147483647;
287 | files = (
288 | );
289 | runOnlyForDeploymentPostprocessing = 0;
290 | };
291 | DC7BD86222C7C7B00046FFFA /* Resources */ = {
292 | isa = PBXResourcesBuildPhase;
293 | buildActionMask = 2147483647;
294 | files = (
295 | );
296 | runOnlyForDeploymentPostprocessing = 0;
297 | };
298 | /* End PBXResourcesBuildPhase section */
299 |
300 | /* Begin PBXShellScriptBuildPhase section */
301 | 47346164AA5A56B45FEABEA5 /* [CP] Check Pods Manifest.lock */ = {
302 | isa = PBXShellScriptBuildPhase;
303 | buildActionMask = 2147483647;
304 | files = (
305 | );
306 | inputFileListPaths = (
307 | );
308 | inputPaths = (
309 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
310 | "${PODS_ROOT}/Manifest.lock",
311 | );
312 | name = "[CP] Check Pods Manifest.lock";
313 | outputFileListPaths = (
314 | );
315 | outputPaths = (
316 | "$(DERIVED_FILE_DIR)/Pods-SweeterSwiftTests-checkManifestLockResult.txt",
317 | );
318 | runOnlyForDeploymentPostprocessing = 0;
319 | shellPath = /bin/sh;
320 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/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# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
321 | showEnvVarsInLog = 0;
322 | };
323 | 6A6825C739C7214D6DBED9E2 /* [CP-User] SwiftLintAutocorrect */ = {
324 | isa = PBXShellScriptBuildPhase;
325 | buildActionMask = 2147483647;
326 | files = (
327 | );
328 | name = "[CP-User] SwiftLintAutocorrect";
329 | runOnlyForDeploymentPostprocessing = 0;
330 | shellPath = /bin/sh;
331 | shellScript = "if [ \"Debug\" == \"${CONFIGURATION}\" ]; then \"${PODS_ROOT}/SwiftLint/swiftlint\" autocorrect --config \"${PODS_ROOT}/SwiftQuality/.swiftlint.yml\" --path \"${SRCROOT}/..\" ; fi";
332 | };
333 | 6BEE5A36F2607305F11A6C5D /* [CP] Embed Pods Frameworks */ = {
334 | isa = PBXShellScriptBuildPhase;
335 | buildActionMask = 2147483647;
336 | files = (
337 | );
338 | inputFileListPaths = (
339 | "${PODS_ROOT}/Target Support Files/Pods-SweeterSwiftTests/Pods-SweeterSwiftTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
340 | );
341 | name = "[CP] Embed Pods Frameworks";
342 | outputFileListPaths = (
343 | "${PODS_ROOT}/Target Support Files/Pods-SweeterSwiftTests/Pods-SweeterSwiftTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
344 | );
345 | runOnlyForDeploymentPostprocessing = 0;
346 | shellPath = /bin/sh;
347 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-SweeterSwiftTests/Pods-SweeterSwiftTests-frameworks.sh\"\n";
348 | showEnvVarsInLog = 0;
349 | };
350 | 6FDE19AE23F9D318D0EA3D82 /* [CP-User] SwiftLint */ = {
351 | isa = PBXShellScriptBuildPhase;
352 | buildActionMask = 2147483647;
353 | files = (
354 | );
355 | name = "[CP-User] SwiftLint";
356 | runOnlyForDeploymentPostprocessing = 0;
357 | shellPath = /bin/sh;
358 | shellScript = "if [ \"Debug\" == \"${CONFIGURATION}\" ]; then \"${PODS_ROOT}/SwiftLint/swiftlint\" --config \"${PODS_ROOT}/SwiftQuality/.swiftlint.yml\" --path \"${SRCROOT}/..\" ; fi";
359 | };
360 | 7527C9AF64CED71731CB051B /* [CP-User] SwiftLintAutocorrect */ = {
361 | isa = PBXShellScriptBuildPhase;
362 | buildActionMask = 2147483647;
363 | files = (
364 | );
365 | name = "[CP-User] SwiftLintAutocorrect";
366 | runOnlyForDeploymentPostprocessing = 0;
367 | shellPath = /bin/sh;
368 | shellScript = "if [ \"Debug\" == \"${CONFIGURATION}\" ]; then \"${PODS_ROOT}/SwiftLint/swiftlint\" autocorrect --config \"${PODS_ROOT}/SwiftQuality/.swiftlint.yml\" --path \"${SRCROOT}/..\" ; fi";
369 | };
370 | 7BBF9EB03B2533D86CBFA454 /* [CP-User] SwiftFormat */ = {
371 | isa = PBXShellScriptBuildPhase;
372 | buildActionMask = 2147483647;
373 | files = (
374 | );
375 | name = "[CP-User] SwiftFormat";
376 | runOnlyForDeploymentPostprocessing = 0;
377 | shellPath = /bin/sh;
378 | shellScript = "if [ \"Debug\" == \"${CONFIGURATION}\" ]; then \"${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat\" --swiftversion ${SWIFT_VERSION} --config \"${PODS_ROOT}/SwiftQuality/.swiftformat\" \"${SRCROOT}/..\" ; fi";
379 | };
380 | AC9CF0C9D911503A4E51014E /* [CP] Check Pods Manifest.lock */ = {
381 | isa = PBXShellScriptBuildPhase;
382 | buildActionMask = 2147483647;
383 | files = (
384 | );
385 | inputFileListPaths = (
386 | );
387 | inputPaths = (
388 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
389 | "${PODS_ROOT}/Manifest.lock",
390 | );
391 | name = "[CP] Check Pods Manifest.lock";
392 | outputFileListPaths = (
393 | );
394 | outputPaths = (
395 | "$(DERIVED_FILE_DIR)/Pods-SweeterSwift-checkManifestLockResult.txt",
396 | );
397 | runOnlyForDeploymentPostprocessing = 0;
398 | shellPath = /bin/sh;
399 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/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# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
400 | showEnvVarsInLog = 0;
401 | };
402 | ADC0E09EF1516A58D8F1F414 /* [CP-User] SwiftFormat */ = {
403 | isa = PBXShellScriptBuildPhase;
404 | buildActionMask = 2147483647;
405 | files = (
406 | );
407 | name = "[CP-User] SwiftFormat";
408 | runOnlyForDeploymentPostprocessing = 0;
409 | shellPath = /bin/sh;
410 | shellScript = "if [ \"Debug\" == \"${CONFIGURATION}\" ]; then \"${PODS_ROOT}/SwiftFormat/CommandLineTool/swiftformat\" --swiftversion ${SWIFT_VERSION} --config \"${PODS_ROOT}/SwiftQuality/.swiftformat\" \"${SRCROOT}/..\" ; fi";
411 | };
412 | E8D61AEAE019F1BE39F833AE /* [CP-User] SwiftLint */ = {
413 | isa = PBXShellScriptBuildPhase;
414 | buildActionMask = 2147483647;
415 | files = (
416 | );
417 | name = "[CP-User] SwiftLint";
418 | runOnlyForDeploymentPostprocessing = 0;
419 | shellPath = /bin/sh;
420 | shellScript = "if [ \"Debug\" == \"${CONFIGURATION}\" ]; then \"${PODS_ROOT}/SwiftLint/swiftlint\" --config \"${PODS_ROOT}/SwiftQuality/.swiftlint.yml\" --path \"${SRCROOT}/..\" ; fi";
421 | };
422 | /* End PBXShellScriptBuildPhase section */
423 |
424 | /* Begin PBXSourcesBuildPhase section */
425 | DC7BD84222C7C4FB0046FFFA /* Sources */ = {
426 | isa = PBXSourcesBuildPhase;
427 | buildActionMask = 2147483647;
428 | files = (
429 | DC7BD88422C7CA1E0046FFFA /* String+Sweeter.swift in Sources */,
430 | DC7BD88322C7CA1E0046FFFA /* DateFormatter+Sweeter.swift in Sources */,
431 | DC7BD88C22C7CA1E0046FFFA /* UIStackView+Sweeter.swift in Sources */,
432 | DC7BD88D22C7CA1E0046FFFA /* NSObject+Sweeter.swift in Sources */,
433 | DC7BD88522C7CA1E0046FFFA /* UIApplication+Sweeter.swift in Sources */,
434 | DC7BD88222C7CA1E0046FFFA /* NSAttributedString+Sweeter.swift in Sources */,
435 | DC7BD88922C7CA1E0046FFFA /* Codable+Sweeter.swift in Sources */,
436 | DC7BD88A22C7CA1E0046FFFA /* Swift+Sweeter.swift in Sources */,
437 | DC7BD88F22C7CA1E0046FFFA /* UIView+Sweeter.swift in Sources */,
438 | DC7BD88E22C7CA1E0046FFFA /* TimeInterval+Sweeter.swift in Sources */,
439 | DC7BD88622C7CA1E0046FFFA /* UITextView+Sweeter.swift in Sources */,
440 | DC7BD88822C7CA1E0046FFFA /* Bundle+Sweeter.swift in Sources */,
441 | DC7BD88B22C7CA1E0046FFFA /* UIViewController+Sweeter.swift in Sources */,
442 | DC7BD88722C7CA1E0046FFFA /* NSManagedObjectContext+Sweeter.swift in Sources */,
443 | );
444 | runOnlyForDeploymentPostprocessing = 0;
445 | };
446 | DC7BD86022C7C7B00046FFFA /* Sources */ = {
447 | isa = PBXSourcesBuildPhase;
448 | buildActionMask = 2147483647;
449 | files = (
450 | DC7BD89722C7EAC40046FFFA /* CodableTests.swift in Sources */,
451 | DC7BD89122C7DAF70046FFFA /* NSAttributedStringTests.swift in Sources */,
452 | DC7BD89522C7EA2B0046FFFA /* BundleTests.swift in Sources */,
453 | DC7BD89322C7DC620046FFFA /* StringTests.swift in Sources */,
454 | DC7BD86722C7C7B00046FFFA /* SwiftTests.swift in Sources */,
455 | );
456 | runOnlyForDeploymentPostprocessing = 0;
457 | };
458 | /* End PBXSourcesBuildPhase section */
459 |
460 | /* Begin PBXTargetDependency section */
461 | DC7BD86B22C7C7B00046FFFA /* PBXTargetDependency */ = {
462 | isa = PBXTargetDependency;
463 | target = DC7BD84522C7C4FB0046FFFA /* SweeterSwift */;
464 | targetProxy = DC7BD86A22C7C7B00046FFFA /* PBXContainerItemProxy */;
465 | };
466 | /* End PBXTargetDependency section */
467 |
468 | /* Begin XCBuildConfiguration section */
469 | DC7BD85822C7C4FB0046FFFA /* Debug */ = {
470 | isa = XCBuildConfiguration;
471 | buildSettings = {
472 | ALWAYS_SEARCH_USER_PATHS = NO;
473 | CLANG_ANALYZER_NONNULL = YES;
474 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
475 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
476 | CLANG_CXX_LIBRARY = "libc++";
477 | CLANG_ENABLE_MODULES = YES;
478 | CLANG_ENABLE_OBJC_ARC = YES;
479 | CLANG_ENABLE_OBJC_WEAK = YES;
480 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
481 | CLANG_WARN_BOOL_CONVERSION = YES;
482 | CLANG_WARN_COMMA = YES;
483 | CLANG_WARN_CONSTANT_CONVERSION = YES;
484 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
485 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
486 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
487 | CLANG_WARN_EMPTY_BODY = YES;
488 | CLANG_WARN_ENUM_CONVERSION = YES;
489 | CLANG_WARN_INFINITE_RECURSION = YES;
490 | CLANG_WARN_INT_CONVERSION = YES;
491 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
492 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
493 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
494 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
495 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
496 | CLANG_WARN_STRICT_PROTOTYPES = YES;
497 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
498 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
499 | CLANG_WARN_UNREACHABLE_CODE = YES;
500 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
501 | CODE_SIGN_IDENTITY = "iPhone Developer";
502 | COPY_PHASE_STRIP = NO;
503 | CURRENT_PROJECT_VERSION = 41;
504 | DEBUG_INFORMATION_FORMAT = dwarf;
505 | ENABLE_STRICT_OBJC_MSGSEND = YES;
506 | ENABLE_TESTABILITY = YES;
507 | GCC_C_LANGUAGE_STANDARD = gnu11;
508 | GCC_DYNAMIC_NO_PIC = NO;
509 | GCC_NO_COMMON_BLOCKS = YES;
510 | GCC_OPTIMIZATION_LEVEL = 0;
511 | GCC_PREPROCESSOR_DEFINITIONS = (
512 | "DEBUG=1",
513 | "$(inherited)",
514 | );
515 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
516 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
517 | GCC_WARN_UNDECLARED_SELECTOR = YES;
518 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
519 | GCC_WARN_UNUSED_FUNCTION = YES;
520 | GCC_WARN_UNUSED_VARIABLE = YES;
521 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
522 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
523 | MTL_FAST_MATH = YES;
524 | ONLY_ACTIVE_ARCH = YES;
525 | SDKROOT = iphoneos;
526 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
527 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
528 | SWIFT_VERSION = 5.0;
529 | VERSIONING_SYSTEM = "apple-generic";
530 | VERSION_INFO_PREFIX = "";
531 | };
532 | name = Debug;
533 | };
534 | DC7BD85922C7C4FB0046FFFA /* Release */ = {
535 | isa = XCBuildConfiguration;
536 | buildSettings = {
537 | ALWAYS_SEARCH_USER_PATHS = NO;
538 | CLANG_ANALYZER_NONNULL = YES;
539 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
540 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
541 | CLANG_CXX_LIBRARY = "libc++";
542 | CLANG_ENABLE_MODULES = YES;
543 | CLANG_ENABLE_OBJC_ARC = YES;
544 | CLANG_ENABLE_OBJC_WEAK = YES;
545 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
546 | CLANG_WARN_BOOL_CONVERSION = YES;
547 | CLANG_WARN_COMMA = YES;
548 | CLANG_WARN_CONSTANT_CONVERSION = YES;
549 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
550 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
551 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
552 | CLANG_WARN_EMPTY_BODY = YES;
553 | CLANG_WARN_ENUM_CONVERSION = YES;
554 | CLANG_WARN_INFINITE_RECURSION = YES;
555 | CLANG_WARN_INT_CONVERSION = YES;
556 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
557 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
558 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
559 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
560 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
561 | CLANG_WARN_STRICT_PROTOTYPES = YES;
562 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
563 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
564 | CLANG_WARN_UNREACHABLE_CODE = YES;
565 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
566 | CODE_SIGN_IDENTITY = "iPhone Developer";
567 | COPY_PHASE_STRIP = NO;
568 | CURRENT_PROJECT_VERSION = 41;
569 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
570 | ENABLE_NS_ASSERTIONS = NO;
571 | ENABLE_STRICT_OBJC_MSGSEND = YES;
572 | GCC_C_LANGUAGE_STANDARD = gnu11;
573 | GCC_NO_COMMON_BLOCKS = YES;
574 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
575 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
576 | GCC_WARN_UNDECLARED_SELECTOR = YES;
577 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
578 | GCC_WARN_UNUSED_FUNCTION = YES;
579 | GCC_WARN_UNUSED_VARIABLE = YES;
580 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
581 | MTL_ENABLE_DEBUG_INFO = NO;
582 | MTL_FAST_MATH = YES;
583 | SDKROOT = iphoneos;
584 | SWIFT_COMPILATION_MODE = wholemodule;
585 | SWIFT_OPTIMIZATION_LEVEL = "-O";
586 | SWIFT_VERSION = 5.0;
587 | VALIDATE_PRODUCT = YES;
588 | VERSIONING_SYSTEM = "apple-generic";
589 | VERSION_INFO_PREFIX = "";
590 | };
591 | name = Release;
592 | };
593 | DC7BD85B22C7C4FB0046FFFA /* Debug */ = {
594 | isa = XCBuildConfiguration;
595 | baseConfigurationReference = 2CCD433E24A0BDB1106A3D61 /* Pods-SweeterSwift.debug.xcconfig */;
596 | buildSettings = {
597 | CODE_SIGN_IDENTITY = "";
598 | CODE_SIGN_STYLE = Automatic;
599 | DEFINES_MODULE = YES;
600 | DYLIB_COMPATIBILITY_VERSION = 1;
601 | DYLIB_CURRENT_VERSION = 41;
602 | DYLIB_INSTALL_NAME_BASE = "@rpath";
603 | INFOPLIST_FILE = SweeterSwift/Info.plist;
604 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
605 | LD_RUNPATH_SEARCH_PATHS = (
606 | "$(inherited)",
607 | "@executable_path/Frameworks",
608 | "@loader_path/Frameworks",
609 | );
610 | PRODUCT_BUNDLE_IDENTIFIER = com.roysharon.SweeterSwift;
611 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
612 | SKIP_INSTALL = YES;
613 | TARGETED_DEVICE_FAMILY = "1,2";
614 | };
615 | name = Debug;
616 | };
617 | DC7BD85C22C7C4FB0046FFFA /* Release */ = {
618 | isa = XCBuildConfiguration;
619 | baseConfigurationReference = 841073221FF5B2AF5BB49742 /* Pods-SweeterSwift.release.xcconfig */;
620 | buildSettings = {
621 | CODE_SIGN_IDENTITY = "";
622 | CODE_SIGN_STYLE = Automatic;
623 | DEFINES_MODULE = YES;
624 | DYLIB_COMPATIBILITY_VERSION = 1;
625 | DYLIB_CURRENT_VERSION = 41;
626 | DYLIB_INSTALL_NAME_BASE = "@rpath";
627 | INFOPLIST_FILE = SweeterSwift/Info.plist;
628 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
629 | LD_RUNPATH_SEARCH_PATHS = (
630 | "$(inherited)",
631 | "@executable_path/Frameworks",
632 | "@loader_path/Frameworks",
633 | );
634 | PRODUCT_BUNDLE_IDENTIFIER = com.roysharon.SweeterSwift;
635 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
636 | SKIP_INSTALL = YES;
637 | TARGETED_DEVICE_FAMILY = "1,2";
638 | };
639 | name = Release;
640 | };
641 | DC7BD86C22C7C7B00046FFFA /* Debug */ = {
642 | isa = XCBuildConfiguration;
643 | baseConfigurationReference = EB5626A87EBAC9FB4EE89466 /* Pods-SweeterSwiftTests.debug.xcconfig */;
644 | buildSettings = {
645 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
646 | CODE_SIGN_STYLE = Automatic;
647 | INFOPLIST_FILE = SweeterSwiftTests/Info.plist;
648 | LD_RUNPATH_SEARCH_PATHS = (
649 | "$(inherited)",
650 | "@executable_path/Frameworks",
651 | "@loader_path/Frameworks",
652 | );
653 | PRODUCT_BUNDLE_IDENTIFIER = com.roysharon.SweeterSwiftTests;
654 | PRODUCT_NAME = "$(TARGET_NAME)";
655 | TARGETED_DEVICE_FAMILY = "1,2";
656 | };
657 | name = Debug;
658 | };
659 | DC7BD86D22C7C7B00046FFFA /* Release */ = {
660 | isa = XCBuildConfiguration;
661 | baseConfigurationReference = 7E30926EC2BD4FB85BB3108B /* Pods-SweeterSwiftTests.release.xcconfig */;
662 | buildSettings = {
663 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
664 | CODE_SIGN_STYLE = Automatic;
665 | INFOPLIST_FILE = SweeterSwiftTests/Info.plist;
666 | LD_RUNPATH_SEARCH_PATHS = (
667 | "$(inherited)",
668 | "@executable_path/Frameworks",
669 | "@loader_path/Frameworks",
670 | );
671 | PRODUCT_BUNDLE_IDENTIFIER = com.roysharon.SweeterSwiftTests;
672 | PRODUCT_NAME = "$(TARGET_NAME)";
673 | TARGETED_DEVICE_FAMILY = "1,2";
674 | };
675 | name = Release;
676 | };
677 | /* End XCBuildConfiguration section */
678 |
679 | /* Begin XCConfigurationList section */
680 | DC7BD84022C7C4FB0046FFFA /* Build configuration list for PBXProject "SweeterSwift" */ = {
681 | isa = XCConfigurationList;
682 | buildConfigurations = (
683 | DC7BD85822C7C4FB0046FFFA /* Debug */,
684 | DC7BD85922C7C4FB0046FFFA /* Release */,
685 | );
686 | defaultConfigurationIsVisible = 0;
687 | defaultConfigurationName = Release;
688 | };
689 | DC7BD85A22C7C4FB0046FFFA /* Build configuration list for PBXNativeTarget "SweeterSwift" */ = {
690 | isa = XCConfigurationList;
691 | buildConfigurations = (
692 | DC7BD85B22C7C4FB0046FFFA /* Debug */,
693 | DC7BD85C22C7C4FB0046FFFA /* Release */,
694 | );
695 | defaultConfigurationIsVisible = 0;
696 | defaultConfigurationName = Release;
697 | };
698 | DC7BD86E22C7C7B00046FFFA /* Build configuration list for PBXNativeTarget "SweeterSwiftTests" */ = {
699 | isa = XCConfigurationList;
700 | buildConfigurations = (
701 | DC7BD86C22C7C7B00046FFFA /* Debug */,
702 | DC7BD86D22C7C7B00046FFFA /* Release */,
703 | );
704 | defaultConfigurationIsVisible = 0;
705 | defaultConfigurationName = Release;
706 | };
707 | /* End XCConfigurationList section */
708 | };
709 | rootObject = DC7BD83D22C7C4FB0046FFFA /* Project object */;
710 | }
711 |
--------------------------------------------------------------------------------