Livefrontで使用する10個のSwift拡張機能

こんにちは、Habr。翻訳は、オンラインコース「iOSDeveloper.Basic」の一部として作成されました



2日間の無料集中型「1行のコードなしでシンプルなアプリケーションを作成する」に皆さんを招待します。初日には、次のことがわかります。





1. Xcodeとは何ですか?

2.「画面の描画」方法

3.画面にボタンと入力フィールドを追加します。認証画面を作成しましょう。

4.アプリケーションの2番目の画面を作成し、認証ウィンドウからそれにトランジションを追加しましょう。こちらから

登録できます。






Swiftに独自のフレーバーを追加する





正直に言いましょう。SwiftおよびAppleフレームワークには、Appleデバイスに最適なソフトウェアを作成するために必要なすべての機能が備わっているわけではありません。幸い、Swiftは拡張機能をサポートしているため、機能を向上させるために必要な不足している部分を追加できます。





Swiftを初めて使用する場合は、先に進む前に、ドキュメント参照して拡張機能の詳細を確認してください





, . , .





- , , . 





, , -.





Xcode Playground, , GitHub.





10 , Livefront.





1. UIView —

UIView

import PlaygroundSupport
import UIKit

// Extension #1 - A helper method to add a view to another with top, left, bottom, and right constraints.
extension UIView {

    /// Add a subview, constrained to the specified top, left, bottom and right margins.
    ///
    /// - Parameters:
    ///   - view: The subview to add.
    ///   - top: Optional top margin constant.
    ///   - left: Optional left (leading) margin constant.
    ///   - bottom: Optional bottom margin constant.
    ///   - right: Optional right (trailing) margin constant.
    ///
    func addConstrained(subview: UIView,
                        top: CGFloat? = 0,
                        left: CGFloat? = 0,
                        bottom: CGFloat? = 0,
                        right: CGFloat? = 0) {
        subview.translatesAutoresizingMaskIntoConstraints = false
        addSubview(subview)

        if let top = top {
            subview.topAnchor.constraint(equalTo: topAnchor, constant: top).isActive = true
        }
        if let left = left {
            subview.leadingAnchor.constraint(equalTo: leadingAnchor, constant: left).isActive = true
        }
        if let bottom = bottom {
            subview.bottomAnchor.constraint(equalTo: bottomAnchor, constant: bottom).isActive = true
        }
        if let right = right {
            subview.trailingAnchor.constraint(equalTo: trailingAnchor, constant: right).isActive = true
        }
    }
}

// Implementation
class ViewController: UIViewController {

    let newView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBlue

        newView.backgroundColor = .systemTeal
        view.addConstrained(subview: newView, top: 50, left: 100, right: -100)
    }
    
}

let viewController = ViewController()
PlaygroundPage.current.liveView = viewController
      
      



, translatesAutoresizingMaskIntoConstraints



false



, , - . , , . , , . , .





2. - (UTC Date)

Date UTC

import Foundation

// Extension #2 - Create a date object from a date string with the UTC timezone.
//Inspired by: https://developer.apple.com/library/archive/qa/qa1480/_index.html
extension Date {
    /// Returns a date from the provided string.
    ///
    /// - Parameter utcString: The string used to create the date.
    ///
    /// - Returns: A date from the provided string.
    ///
    static func utcDate(from utcString: String) -> Date? {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(abbreviation: "UTC")!
        return formatter.date(from: utcString)
    }
}

// Implementation
let utcDateString = "2021-04-03T14:00:00.000Z"
let utcDate = Date.utcDate(from: utcDateString) //Playgrounds will show this in the machine's timezone.
print(utcDate!)
      
      



API REST UTC. Date



. , , dateFormat



, .





3. String () — URL-

URL-

import Foundation

// Extension #3 - Retrieves valid URLs from a given string.
//Credit - Thanks to Paul Hudson for the core functionality on this extension.
//Source - https://www.hackingwithswift.com/example-code/strings/how-to-detect-a-url-in-a-string-using-nsdatadetector
extension String {
    /// Searches through a string to find valid URLs.
    /// - Returns: An array of found URLs.
    func getURLs() -> [URL] {
        var foundUrls = [URL]()
        guard let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else {
            return foundUrls
        }

        let matches = detector.matches(
            in: self,
            options: [],
            range: NSRange(location: 0, length: self.utf16.count)
        )

        for match in matches {
            guard let range = Range(match.range, in: self),
                  let retrievedURL = URL(string: String(self[range])) else { continue }
            foundUrls.append(retrievedURL)
        }

        return foundUrls
    }
}

// Implementation
let unfilteredString = "To get the best search results, go to https://www.google.com, www.duckduckgo.com, or www.bing.com"
let urls = unfilteredString.getURLs()
      
      



- , URL . -, , URL- JSON-.





4. UIStackView —

subviews UIStackView

import UIKit

// Extension #4 - Removes all views from a UIStackView.
extension UIStackView {
    /// Removes all arranged subviews and their constraints from the view.
    func removeAllArrangedSubviews() {
        arrangedSubviews.forEach {
            self.removeArrangedSubview($0)
            NSLayoutConstraint.deactivate($0.constraints)
            $0.removeFromSuperview()
        }
    }
}

// Implementation
let view1 = UIView()
let view2 = UIView()
let view3 = UIView()

let stackView = UIStackView()

//Add subviews to stackView
stackView.addArrangedSubview(view1)
stackView.addArrangedSubview(view2)
stackView.addArrangedSubview(view3)

//Confirm stackView contains 3 views
stackView.arrangedSubviews.count    //3
//Remove views from stackView
stackView.removeAllArrangedSubviews()

//Confirm stackView doesn't contain any subviews now
stackView.arrangedSubviews.count    //0
      
      



, UIStackView



, , , . - .





5. Bundle —

import Foundation

// Extension #5 - retrieve the app version # and build #.
//Inspired by https://stackoverflow.com/questions/25965239/how-do-i-get-the-app-version-and-build-number-using-swift
extension Bundle {
    /// Retrieve the app version # from Bundle
    var releaseVersionNumber: String? {
        return infoDictionary?["CFBundleShortVersionString"] as? String
    }

    /// Retrieve the build version # from Bundle
    var buildVersionNumber: String? {
        return infoDictionary?["CFBundleVersion"] as? String
    }
}

// Implementation
let releaseVersionNumber = Bundle.main.releaseVersionNumber
let buildVersionNumber = Bundle.main.buildVersionNumber
      
      



, Bundle



. , , . .





6. —

Integer

import Foundation

// Extension #6 - Get the prior year as an integer
extension Calendar {
    /// Returns the prior year as an integer.
    ///
    /// - Returns: Returns last year's year as an integer.
    func priorYear() -> Int {
        guard let priorYear = date(byAdding: .year, value: -1, to: Date()) else {
            return component(.year, from: Date()) - 1
        }
        return component(.year, from: priorYear)
    }
}

//Implementation
let priorYearAsNumber = Calendar.current.priorYear()
      
      



. Integer.





7. UIStackView — Init

Init ()

import PlaygroundSupport
import UIKit

// Extension #7 - Make UIStackView creation a lot easier.
extension UIStackView {

    /// `UIStackView` convenience initializer for creating a stack view with arranged subviews, an
    /// axis and spacing.
    ///
    /// - Parameters:
    ///   - alignment: The alignment of the arranged subviews perpendicular to the stack view’s
    ///                axis.
    ///   - arrangedSubviews: The subviews to arrange in the `UIStackView`.
    ///   - axis: The axis that the subviews should be arranged around.
    ///   - distribution: The distribution of the arranged views along the stack view’s axis.
    ///   - spacing: The spacing to place between each arranged subview. Defaults to 0.
    ///
    convenience init(alignment: UIStackView.Alignment = .fill,
                     arrangedSubviews: [UIView],
                     axis: NSLayoutConstraint.Axis,
                     distribution: UIStackView.Distribution = .fill,
                     spacing: CGFloat = 0) {
        arrangedSubviews.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
        self.init(arrangedSubviews: arrangedSubviews)
        self.alignment = alignment
        self.axis = axis
        self.distribution = distribution
        self.spacing = spacing
    }
}

// Implementation
let view1 = UIView()
view1.backgroundColor = .systemPink
let view2 = UIView()
view2.backgroundColor = .systemOrange
let view3 = UIView()
view3.backgroundColor = .systemTeal

let stackView = UIStackView(alignment: .leading,
                            arrangedSubviews: [view1, view2, view3],
                            axis: .vertical,
                            distribution: .fill,
                            spacing: 20)



let view = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 500))
view.backgroundColor = .systemBlue
view.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false

NSLayoutConstraint.activate([
    view1.heightAnchor.constraint(equalToConstant: 50),
    view1.widthAnchor.constraint(equalToConstant: 150),
    view2.heightAnchor.constraint(equalToConstant: 50),
    view2.widthAnchor.constraint(equalToConstant: 150),
    view3.heightAnchor.constraint(equalToConstant: 50),
    view3.widthAnchor.constraint(equalToConstant: 150),
    stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
    stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])

PlaygroundPage.current.liveView = view
      
      



, UIStackView



, . . translatesAutoresizingMaskIntoConstraints



false



.





8. UIColor — Hex

Hex () UIColor

import UIKit

// Extension #8 - generates a string with the hex color value.
//Inspired by: https://stackoverflow.com/a/26341062
extension UIColor {
    // MARK: - Helper Functions
    /// Returns the hex string for this `UIColor`. For example: `#FFFFFF` or `#222222AB` if the alpha value is included.
    ///
    /// - Parameter includeAlpha: A boolean indicating if the alpha value should be included in the returned hex string.
    ///
    /// - Returns: The hex string for this `UIColor`. For example: `#FFFFFF` or
    ///            `#222222AB` if the alpha value is included.
    ///
    func hexString(includeAlpha: Bool = false) -> String {
        let components = cgColor.components
        let red: CGFloat = components?[0] ?? 0.0
        let green: CGFloat = components?[1] ?? 0.0
        let blue: CGFloat = components?[2] ?? 0.0
        let alpha: CGFloat = components?[3] ?? 0.0
        let hexString = String.init(
            format: "#%02lX%02lX%02lX%02lX",
            lroundf(Float(red * 255)),
            lroundf(Float(green * 255)),
            lroundf(Float(blue * 255)),
            lroundf(Float(alpha * 255))
        )
        return includeAlpha ? hexString : String(hexString.dropLast(2))
    }
}

// Implementation
let whiteColor = UIColor(displayP3Red: 1, green: 1, blue: 1, alpha: 1)

let whiteHexString = whiteColor.hexString() //#FFFFFF
let blackColor = UIColor(displayP3Red: 0, green: 0, blue: 0, alpha: 1)

let blackHexString = blackColor.hexString() //#000000
      
      



UIColor



String



. , . , RGB.





9. UIViewController —

,

import UIKit

// Extension #9
extension UIViewController {
    /// Gets a flag indicating whether or not the UI is in dark mode.
    public var isDarkMode: Bool {
        if #available(iOS 12.0, *) {
            return traitCollection.userInterfaceStyle == .dark
        }
        return false
    }
}
      
      



UIColors



, .label



, .systemBlue



.., , , , . , , .





10. UICollectionView — IndexPath

indexPath collectionView

import PlaygroundSupport
import UIKit

// Extension #10 - get the last valid indexPath in a UICollectionView.
extension UICollectionView {

    /// Validates whether an `IndexPath` is a valid index path for an item in a collection view.
    ///
    /// - Parameter indexPath: The index path to validate.
    /// - Returns: `true` if the index path represents an item in the collection view or false
    ///     otherwise.
    ///
    func isValid(_ indexPath: IndexPath) -> Bool {
        guard indexPath.section < numberOfSections,
              indexPath.item < numberOfItems(inSection: indexPath.section)
        else {
            return false
        }

        return true
    }

    /// Provides the last valid `indexPath` in the collection view.
    /// - Parameter section: The section used to provide the last `indexPath`.
    /// - Returns: the last valid `indexPath` in the collection view or nil if not a valid `indexPath`.
    func lastIndexPath(in section: Int) -> IndexPath? {
        let lastIndexPath = IndexPath(row: numberOfItems(inSection: section) - 1, section: section)
        guard isValid(lastIndexPath) else { return nil }
        return lastIndexPath
    }
}

// Implementation
class CollectionViewController: UICollectionViewController {

    let items = Array(1...100)

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
    }

    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
        cell.backgroundColor = .systemBlue
        return cell
    }
}

let collectionViewController = CollectionViewController(collectionViewLayout: UICollectionViewFlowLayout())
let lastIndexPath = collectionViewController.collectionView.lastIndexPath(in: 0)
lastIndexPath?.section  //0
lastIndexPath?.row      //99
PlaygroundPage.current.liveView = collectionViewController
      
      



, UICollectionView



, indexPath



. , , , UIKit. collectionView



; .





, . Swift . " Swift" , -.





() .





:









Swift










"iOS Developer. Basic"





« »








All Articles