The goal of this library is to provide handy features that didn’t make it to the Swift standard library (yet) due to many different reasons. Those could be that the Swift community wants to keep the standard library clean and manageable or simply hasn’t finished discussion on a specific feature yet.
If you like this, please also checkout HandyUIKit for handy UI features that we feel should have been part of the UIKit frameworks in the first place.
If you are upgrading from a previous major version of HandySwift (e.g. 1.x to 2.x) then checkout the releases section on GitHub and look out for the release notes of the last major releas(es) (e.g. 2.0.0) for an overview of the changes made. It’ll save you time as hints on how best to migrate are included there.
Apply a limiting range as the bounds of a Comparable.
Supports ClosedRange (a ... b), PartialRangeFrom (a...) and PartialRangeThrough (...b) as the limits.
let unicodeString = "Hello composed unicode symbols! 👨👩👧👦👨👨👦👦👩👩👧👧"
unicodeString[unicodeString.fullRange] // => same string
.encrypted(key:)
Encrypts this plain text String with the given key using AES.GCM and returns a base64 encoded representation of the encrypted data.
@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
let key = SymmetricKey(size: .bits256)
let plainText = "Harry Potter is a 🧙"
let encryptedString = try plainText.encrypted(key: key) // => "nz9LDkTNUEFj16Hrqvs4oCYeuIgV+nSP4OSqahkbtH62eJHHW664wC8NeFAMBPq7ZsY="
.decrypted(key:)
Decrypts this base64 encoded representation of encrypted data with the given key using AES.GCM and returns the decrypted plain text String.
@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
encryptedString.decrypt(key: key) // => "Harry Potter is a 🧙"
NSRangeExtension
init(_:in:)
Converting from NSRange to Range<String.Index> became simple in Swift 4:
let string = "Hello World!"
let nsRange = NSRange(location: 0, length: 10)
let swiftRange = Range(nsRange, in: string)
The opposite is now also possible with this extension:
let string = "Hello World!"
let swiftRange: Range<String.Index> = string.fullRange
let nsRange = NSRange(swiftRange, in: string)
ArrayExtension
.sample
Returns a random element within the array or nil if array empty.
Merges a given Dictionary into an existing Dictionary overriding existing values for matching keys.
var dict = ["A": "A value", "B": "Old B value"]
dict.merge(["B": "New B value", "C": "C value"])
dict // => ["A": "A value", "B": "New B value", "C": "C value"]
.merged(with: Dictionary)
Create new merged Dictionary with the given Dictionary merged into a Dictionary overriding existing values for matching keys.
let immutableDict = ["A": "A value", "B": "Old B value"]
immutableDict.merged(with: ["B": "New B value", "C": "C value"])
// => ["A": "A value", "B": "New B value", "C": "C value"]
DispatchTimeIntervalExtension
.timeInterval
Returns a TimeInterval object from a DispatchTimeInterval.
Simple protocol to make constructing and modifying objects with multiple properties more pleasant (functional, chainable, point-free). Supported by all NSObject subclasses by default.
struct Foo: Withable {
var bar: Int
var isEasy: Bool = false
}
let defaultFoo = Foo(bar: 5)
let customFoo = Foo(bar: 5).with { $0.isEasy = true }
defaultFoo.isEasy // => false
customFoo.isEasy // => true
Donation
HandySwift was brought to you by Cihat Gündüz in his free time. If you want to thank me and support the development of this project, please make a small donation on PayPal. In case you also like my other open source contributions and articles, please consider motivating me by becoming a sponsor on GitHub or a patron on Patreon.
Thank you very much for any donation, it really helps out a lot! 💯
Contributing
Contributions are welcome. Feel free to open an issue on GitHub with your ideas or implement an idea yourself and post a pull request. If you want to contribute code, please try to follow the same syntax and semantic in your commit messages (see rationale here). Also, please make sure to add an entry to the CHANGELOG.md file which explains your change.
License
This library is released under the MIT License. See LICENSE for details.
Installation • Usage • Donation • Issues • Contributing • License
HandySwift
The goal of this library is to provide handy features that didn’t make it to the Swift standard library (yet) due to many different reasons. Those could be that the Swift community wants to keep the standard library clean and manageable or simply hasn’t finished discussion on a specific feature yet.
If you like this, please also checkout HandyUIKit for handy UI features that we feel should have been part of the UIKit frameworks in the first place.
Usage
Feature Overview
Globals
Some global helpers.
delay(bySeconds:) { … }
Runs a given closure after a delay given in seconds. Dispatch queue can be set optionally, defaults to Main thread.
IntExtension
init(randomBelow:)
Initialize random Int value below given positive value.
.times
Repeat some code block a given number of times.
.timesMake
Makes array by adding closure’s return value n times.
ComparableExtension
clamped(to:)
Apply a limiting range as the bounds of a
Comparable. SupportsClosedRange(a ... b),PartialRangeFrom(a...) andPartialRangeThrough(...b) as thelimits.clamp(to:)
In-place
mutatingvariant ofclamped(to:)DoubleExtension
round(fractionDigits:rule:)
Rounds the value to an integral value using the specified fraction digits and rounding rule.
rounded(fractionDigits:rule:) -> Double
Returns this value rounded to an integral value using the specified fraction digits and rounding rule.
StringExtension
.stripped()
Returns string with whitespace characters stripped from start and end.
.isBlank
Checks if String contains any characters other than whitespace characters.
init(randomWithLength:allowedCharactersType:)
Get random numeric/alphabetic/alphanumeric String of given length.
.fullRange
Get the full
Rangeon aStringobject..encrypted(key:)
Encrypts this plain text
Stringwith the given key using AES.GCM and returns a base64 encoded representation of the encrypted data.@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *).decrypted(key:)
Decrypts this base64 encoded representation of encrypted data with the given key using AES.GCM and returns the decrypted plain text
String.@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)NSRangeExtension
init(_:in:)
Converting from
NSRangetoRange<String.Index>became simple in Swift 4:The opposite is now also possible with this extension:
ArrayExtension
.sample
Returns a random element within the array or nil if array empty.
.sample(size:)
Returns an array with
sizerandom elements or nil if array empty..combinations(with:)
Combines each element with each element of a given other array.
DictionaryExtension
init?(keys:values:)
Initializes a new
Dictionaryand fills it with keys and values arrays or returns nil if count of arrays differ..merge(Dictionary)
Merges a given
Dictionaryinto an existingDictionaryoverriding existing values for matching keys..merged(with: Dictionary)
Create new merged
Dictionarywith the givenDictionarymerged into aDictionaryoverriding existing values for matching keys.DispatchTimeIntervalExtension
.timeInterval
Returns a
TimeIntervalobject from aDispatchTimeInterval.TimeIntervalExtension
Unit based pseudo-initializers
Returns a
TimeIntervalobject with a given value in a the specified unit.Unit based getters
Returns a double value with the time interval converted to the specified unit.
SortedArray
The main purpose of this wrapper is to provide speed improvements for specific actions on sorted arrays.
init(array:) & .array
.index
Finds the lowest index matching the given predicate using binary search for an improved performance (
O(log n))..prefix(upTo:) / .prefix(through:)
.suffix(from:)
FrequencyTable
FrequencyTable(values: valuesArray) { valueToFrequencyClosure }
Initialize with values and closure.
.sample
Returns a random element with frequency-based probability within the array or nil if array empty.
.sample(size:)
Returns an array with
sizefrequency-based random elements or nil if array empty.Regex
Regexis a swifty regex engine built on top of theNSRegularExpressionAPI.init(_:options:)
Initialize with pattern and, optionally, options.
regex.matches(_:)
Checks whether regex matches string
regex.matches(in:)
Returns all matches
regex.firstMatch(in:)
Returns first match if any
regex.replacingMatches(in:with:count:)
Replaces all matches in a string with a template string, up to the a maximum of matches (count).
match.string
Returns the captured string
match.range
Returns the range of the captured string within the base string
match.captures
Returns the capture groups of a match
match.string(applyingTemplate:)
Replaces the matched string with a template string
Weak
Weakis a wrapper to store weak references to aWrappedinstance.Weak(_:)
Initialize with an object reference.
Accessing inner Reference
Access the inner wrapped reference with the
valueproperty.NilLiteralExpressible Conformance
Create a
Weakwrapper by assigning nil to the value.Unowned
Unownedis a wrapper to store unowned references to aWrappedinstance.Unowned(_:)
Initialize with an object reference.
Accessing inner Reference
Access the inner wrapped reference with the
valueproperty.CollectionExtension
[try:]
Returns an element with the specified index or nil if the element does not exist.
.sum()
Returns the sum of all elements. The return type is determined by the numeric elements, e.g. Int for [Int]. NOTE: Only available for
Numerictypes..average()
Returns the average of all elements as a Double value. NOTE: Only available for
IntandDoublecollections.Withable
Simple protocol to make constructing and modifying objects with multiple properties more pleasant (functional, chainable, point-free). Supported by all
NSObjectsubclasses by default.Donation
HandySwift was brought to you by Cihat Gündüz in his free time. If you want to thank me and support the development of this project, please make a small donation on PayPal. In case you also like my other open source contributions and articles, please consider motivating me by becoming a sponsor on GitHub or a patron on Patreon.
Thank you very much for any donation, it really helps out a lot! 💯
Contributing
Contributions are welcome. Feel free to open an issue on GitHub with your ideas or implement an idea yourself and post a pull request. If you want to contribute code, please try to follow the same syntax and semantic in your commit messages (see rationale here). Also, please make sure to add an entry to the
CHANGELOG.mdfile which explains your change.License
This library is released under the MIT License. See LICENSE for details.