[Программирование, Разработка под iOS, Swift] 10 расширений Swift, которые мы используем на Livefront (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Привет, Хабр. Перевод подготовлен в рамках онлайн-курса "iOS Developer. Basic".
Приглашаем всех желающих на бесплатный двухдневный интенсив «Создание простейшего приложения без единой строчки кода». В первый день узнаем:1. Что такое XCode?
2. Как "рисуются экраны"
3. Добавим на экраны кнопки и поля ввода. Создадим экран авторизации.
4. Создадим второй экран нашего приложения и добавим переход на него из окна авторизации.
Зарегистрироваться можно здесь.
Добавьте в 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"Участвовать в интенсиве «Создание простейшего приложения без единой строчки кода»
===========
Источник:
habr.com
===========
===========
Автор оригинала: Josh Rondestvedt
===========Похожие новости:
- [Big Data, Машинное обучение] Перспективные архитектуры для современных инфраструктур данных (перевод)
- [Python, SQL, Data Mining, R, Data Engineering] Звездные войны или подробный гайд по dplyr
- [Программирование, Kotlin] Глубокое обучение на Kotlin: альфа-версия KotlinDL (перевод)
- [Разработка под iOS, Разработка мобильных приложений, API, Браузеры, IT-компании] Инженер Google раскритиковал Apple за торможение развития веб-технологий
- [Тестирование веб-сервисов] Хрустальный шар опытного тестировщика (перевод)
- [Тестирование IT-систем, Python, Программирование, Машинное обучение] PyTest для машинного обучения — простой учебник на основе примеров (перевод)
- [Программирование, Алгоритмы, Учебный процесс в IT, Карьера в IT-индустрии] Вебинар от Яндекс.Практикума «Открытое алгоритмическое собеседование»: 12 мая в 19.30
- [Программирование, C++, Qt, Геоинформационные сервисы] Создаём плагин Qt GeoServices на примере ОС Аврора, OpenStreetMap и Sight Safari
- [Oracle, Программирование, Совершенный код, IT-стандарты] Часть 2. Идентификация событий происходящих в Oracle PL/SQL
- [Python, Программирование, Умный дом, Интернет вещей] Простой Telegram-бот для получения информации через MQTT
Теги для поиска: #_programmirovanie (Программирование), #_razrabotka_pod_ios (Разработка под iOS), #_swift, #_ios_development, #_swift, #_app_development, #_engineering, #_xcode, #_blog_kompanii_otus (
Блог компании OTUS
), #_programmirovanie (
Программирование
), #_razrabotka_pod_ios (
Разработка под iOS
), #_swift
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:48
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Привет, Хабр. Перевод подготовлен в рамках онлайн-курса "iOS Developer. Basic".
Приглашаем всех желающих на бесплатный двухдневный интенсив «Создание простейшего приложения без единой строчки кода». В первый день узнаем:1. Что такое XCode? 2. Как "рисуются экраны" 3. Добавим на экраны кнопки и поля ввода. Создадим экран авторизации. 4. Создадим второй экран нашего приложения и добавим переход на него из окна авторизации. Зарегистрироваться можно здесь. 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 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!) 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() 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 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 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() 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 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 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 } } 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 Узнать подробнее о курсе "iOS Developer. Basic"Участвовать в интенсиве «Создание простейшего приложения без единой строчки кода»
=========== Источник: habr.com =========== =========== Автор оригинала: Josh Rondestvedt ===========Похожие новости:
Блог компании OTUS ), #_programmirovanie ( Программирование ), #_razrabotka_pod_ios ( Разработка под iOS ), #_swift |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:48
Часовой пояс: UTC + 5