All the reusable code that we need in each project

Overview

SwiftyUtils

CI Status Language CocoaPods Compatible Carthage compatible Platform

SwiftyUtils groups all the reusable code that we need to ship in each project. This framework contains:

  • Extensions
  • Protocols
  • Structs
  • Subclasses

Working on iOS, macOS, tvOS, and watchOS, everything has been made to be easy to use! 🎉

Contents

Check out the repository to find examples / tests for each feature.

Swift, Foundation and CoreGraphics extensions:

SwiftUI:

SwiftUI Extension:

UIKit Extensions:

UIKit Protocols:

AppKit Extensions:

Protocols:

PropertyWrappers:

Others:

Swift, Foundation and CoreGraphics Extensions

Array extension

Safely access to an element:

var array = [1, 2, 3]
print(array[safe: 0]) // Optional(1)
print(array[safe: 10]) // nil

Find all the index of an object:

var array = [1, 2, 3, 1]
print(array.indexes(of: 1)) // [0,3]

Get index of first / last occurrence of an object:

var array = [1, 2, 3, 1]
print(array.firstIndex(of: 1)) // Optional(0)
print(array.lastIndex(of: 1)) // Optional(3)

Remove an object:

var array = [1, 2, 3]
myArray.remove(object: 2)
print(myArray) // [1, 3]
myArray.remove(objects: [1, 3])
print(myArray) // []

Remove all the duplicates:

var array = [0, 0, 1, 1, 2]
array.removeDuplicates()
print(array) // [0,1,2]

let array = [0, 0, 1, 1, 2]
let newArray.removedDuplicates()
print(newArray) // [0,1,2]

Remove all instances of an item:

var array = [0, 0, 1, 1, 2]
array.removeAll(0)
print(array) // [1,1,2]

let array = [0, 0, 1, 1, 2]
let newArray = array.removedAll(0)
print(newArray) // [1,1,2]

Check if an array is a subset of another array:

var array = [1, 2, 3]
print(array.contains([1, 2])) // true
print(array.contains([5])) // false

Determine if an array contains an object:

var array = [1, 2, 3]
print(array.contains(1)) // true
print(array.contains(11)) // false

Get intersection and union of two arrays:

var myArray = [1, 2, 3]
print(array.intersection(for: [1, 5, 3])) // [1, 3]
print(array.union(values: [5, 6])) // [1, 2, 3, 5, 6]

Get difference between two arrays:

var array = [1, 2, 3]
print(array.difference(with: [1])) // [2, 3]

Split into chunk of a specific size:

var array = [1, 2, 3, 4]
print(array.split(intoChunksOf: 2)) // [[1, 2], [3, 4]]

Bundle extension

Get bundle information:

Bundle.main.appName
Bundle(url: url)?.appName

Bundle.main.displayName
Bundle(url: url)?.displayName

Bundle.main.appVersion
Bundle(url: url)?.appVersion

Bundle.main.appBuild
Bundle(url: url)?.appBuild

Bundle.main.bundleId
Bundle(url: url)?.bundleId

Bundle.main.schemes
Bundle(url: url)?.schemes

Bundle.main.mainScheme
Bundle(url: url)?.mainScheme

Bundle.main.isInTestFlight
Bundle(url: url)?.isInTestFlight

CGFloat extension

Create a CGFloat from a Float or an Integer:

let imageViewTop = 15.f

CGPoint extension

Add two CGPoint:

var point1 = CGPoint(x: 10, y: 10)
let point2 = CGPoint(x: 10, y: 10)
print(point1 + point2) // CGPoint(x: 20, y: 20)

point1 += point2
print(point1) // CGPoint(x: 20, y: 20)

Substract two CGPoint:

var point1 = CGPoint(x: 10, y: 10)
let point2 = CGPoint(x: 10, y: 10)
print(point1 - point2) // CGPoint(x: 0, y: 0)

point1 -= point2
print(point1) // CGPoint(x: 0, y: 0)

Multiply a CGPoint with a scalar:

var point1 = CGPoint(x: 10, y: 10)
print(point1 * 2) // CGPoint(x: 20, y: 20)

point1 *= 2
print(point1) // CGPoint(x: 20, y: 20)

CGRect extension

Get the origin's x and y coordinates:

aRect.x // instead of aRect.origin.x
aRect.y // instead of aRect.origin.y

Change one property of a CGRect:

let rect = CGRect(x: 10, y: 20, width: 30, height: 40) 
let widerRect = rect.with(width: 100) // x: 10, y: 20, width: 100, height: 40
let tallerRect = rect.with(height: 100) // x: 10, y: 20, width: 30, height: 100
let rectAtAnotherPosition = rect.with(x: 100).with(y: 200) // x: 100, y: 200, width: 30, height: 40
let rectWithAnotherSize = rect.with(size: CGSize(width: 200, height: 200)) // x: 10, y: 20, width: 200, height: 200
let rectAtYetAnotherPosition = rect.with(origin: CGPoint(x: 100, y: 100)) // x: 100, y: 100, width: 30, height: 40

CGSize extension

Add two CGSize:

var size1 = CGSize(width: 10, height: 10)
let size2 = CGSize(width: 10, height: 10)
print(size1 + size2) // CGSize(width: 20, height: 20)

size1 += size2
print(size1) // CGSize(width: 20, height: 20)

Substract two CGSize:

var size1 = CGSize(width: 10, height: 10)
let size2 = CGSize(width: 10, height: 10)
print(size1 - size2) // CGSize(width: 0, height: 0)

size1 -= size2
print(size1) // CGSize(width: 0, height: 0)

Multiply a CGSize with a scalar:

var size1 = CGSize(x: 10, y: 10)
print(size1 * 2) // CGSize(width: 20, height: 20)

size1 *= 2
print(size1) // CGSize(width: 20, height: 20)

Color extension

Create colors with HEX values:

let myUIColor = UIColor(hex: "233C64") // Equals 35,60,100,1
let myNSColor = NSColor(hex: "233C64") // Equals 35,60,100,1

Access to individual color value:

let myColor = UIColor(red: 120, green: 205, blue: 44, alpha: 0.3)
print(myColor.redComponent) // 120
print(myColor.greenComponent) // 205
print(myColor.blueComponent) // 44
print(myColor.alpha) // 0.3

Get lighter or darker variants of colors instances:

let color = UIColor(red: 0.5, green: 0.5, blue: 1.0, alpha: 1.0)
let lighter = color.lighter(amount: 0.5)
let darker = color.darker(amount: 0.5)
// OR
let lighter = color.lighter()
let darker = color.darker()

let color = NSColor(red: 0.5, green: 0.5, blue: 1.0, alpha: 1.0)
let lighter = color.lighter(amount: 0.5)
let lighter = color.lighter()
// OR
let darker = color.darker(amount: 0.5)
let darker = color.darker()

Data Extension

Initialize from hex string:

let hexString = "6261736520313020697320736F2062617369632E206261736520313620697320776865726520697427732061742C20796F2E"
let data = Data(hexString: hexString)

Get hex string from data:

let data = Data(...)
let string = data.toHexString()
// string = "6261736520313020697320736F2062617369632E206261736520313620697320776865726520697427732061742C20796F2E" if using previous example value

Get UInt8 Array from data:

let data = Data(...)
let array = data.bytesArray

Map Data to Dictionary:

let dictionary = try data.toDictionary()

Date extension

Initialize from string:

let format = "yyyy/MM/dd"
let string = "2015/03/11"
print(Date(fromString: string, format: format)) // Optional("2015/03/11 00:00:00 +0000")

Convert date to string:

let now = Date()
print(now.string())
print(now.string(dateStyle: .medium, timeStyle: .medium))
print(now.string(format: "yyyy/MM/dd HH:mm:ss"))

See how much time passed:

let now = Date()
let later = Date(timeIntervalSinceNow: -100000)
print(later.days(since: now)) // 1.15740740782409
print(later.hours(since: now)) // 27.7777777733571
print(later.minutes(since: now)) // 1666.66666641732
print(later.seconds(since: now)) // 99999.999984026

Check if a date is in future or past:

let later = Date(timeIntervalSinceNow: -100000)
print(now.isInFuture) // true
print(now.isInPast) // false

Dictionary extension

Check if a key exists in the dictionary:

let dic = ["one": 1, "two": 2]
print(dic.has(key: "one")) // True
print(dic.has(key: "1")) // False

Map Dictionary to Data:

let data = try dictionary.toData()

Easily get union of two dictionaries:

let dic1 = ["one": 1, "two": 2]
let dic2 = ["one": 1, "four": 4]

let dic3 = dic1.union(values: dic2)
print(dic3) // ["one": 1, "two": 2, "four": 4]

map a dictionary:

let dic = ["a": 1, "b": 2, "c": 3]
let result = dic.map { key, value in
	return (key.uppercased(), "\(value * 2)")
}
print(dic) // ["A": "2, "B": "4", "C": "6"]

flatMap a dictionary:

let dic = ["a": 1, "b": 2, "c": 3]
let result = dic.flatMap { key, value -> (String, String)? in
	if value % 2 == 0 {
	 	return nil
	}
	return (key.uppercased(), "\(value * 2)")
}
print(dic) // ["A": "2, "C": "6"]

Get difference of two dictionaries:

let dic1 = ["one": 1, "two": 2]
let dic2 = ["one": 1, "four": 4]
difference(with: dic1, dic2) // ["two": 2, "four": 4]

Merge several dictionaries:

let dic1 = ["one": 1, "two": 2]
let dic2 = ["three": 3, "four": 4]
var finalDic = [String: Int]()
finalDic.merge(with: dic1, dic2)
print(finalDic) // ["one": 1, "two": 2, "three": 3, "four": 4]

Double extension

Get the time interval for a number of milliseconds, seconds, hour, or days:

print(1.second) // 1
print(1.minute) // 60
print(1.hour) // 3600
print(1.2.seconds) // 1.2
print(1.5.minutes) // 90.0
print(1.5.hours) // 5400.0
print(1.3.milliseconds) // 0.0013
print(0.5.day) // 43200
print(1.day) // 86400
print(2.day) // 172800

Formatted value with the locale currency:

print(Double(3.24).formattedPrice) // "$3.24"
print(Double(10).formattedPrice) // "$10.00"

FileManager extension

Get documents directory url following the os:

FileManager.document
// OR
FileManager.default.document

Create a new directory:

FileManager.createDirectory(at: directoryUrl)
// OR
FileManager.default.createDirectory(at: directoryUrl)

Delete contents of temporary directory

FileManager.removeTemporaryFiles()
// OR
FileManager.default.removeTemporaryFiles()

Delete contents of documents directory

FileManager.removeDocumentFiles()
// OR
FileManager.default.removeDocumentFiles()

Int extension

var myNumber = -33
print(myNumber.isEven) // false
print(myNumber.isOdd) // true
print(myNumber.isPositive) // false
print(myNumber.isNegative) // true
print(myNumber.digits) // 2

Round to the nearest / nearest down / nearest up:

var value = 17572
print(value.nearestDozens) // 17570
print(value.nearestHundreds) // 17600
print(value.nearestThousands) // 18000
print(value.nearest(to: 1000) // 18000

value = 17578
print(value.nearestBelowDozens) // 17570
print(value.nearestBelowHundreds) // 17500
print(value.nearestBelowThousands) // 17000
print(value.nearestBelow(to: 1000) // 17000

value = 17442
print(value.nearestUpDozens) // 17450
print(value.nearestUpHundreds) // 17500)
print(value.nearestUpThousands) // 18000
print(value.nearestUp(to: 1000) // 18000

Formatted value with the locale currency:

print(10.formattedPrice) // "$10.00"

MutableCollection extension

Sorts the mutable collection in place using KeyPath:

var articles = [Article(title: "B"), Article(title: "C"), Article(title: "A")]
articles.sort(by: \.title) // [A, B, C]
articles.sort(by: \.title, order: >) // [C, B, A]

NotificationCenter extension

Post a notification from a specific queue:

NotificationCenter.default.postNotification("aNotification", queue: DispatchQueue.main) 
NotificationCenter.default.postNotification("aNotification", object: aObject queue: DispatchQueue.main)
NotificationCenter.default.postNotification("aNotification", object: aObject userInfo: userInfo queue: DispatchQueue.main)

NSAttributedString extension

Check if an attribute is applied on the desired substring:

let text = "Hello"
let attrString = NSMutableAttributedString(text: "Hello world")
attrString = attrString.underlined(occurences: text)
attrString.isAttributeActivated(.underlineStyle, appliedOn: text, value: 1) // true

NSLayoutConstraint extension

No available for watchOS

Apply a multiplier to a constraint (currently working only for width and height):

let view = UIView(CGRect(x: 0, y: 0, width: 100, height: 200))
let constraint = NSLayoutConstraint(item: view, attribute: .width, ...)
constraint.apply(multiplier: 0.5, toView: superview)
print(constraint.constants) // 50

let constraint = NSLayoutConstraint(item: view, attribute: .height, ...)
constraint.apply(multiplier0.5, toView: superview)
print(constraint.constants) // 100

NSMutableAttributedString extension

Colorize each occurence:

let attrStr: NSMutableAttributedString = NSMutableAttributedString.colored(inText: "hello world", color: .yellow, occurences: "llo")

// OR

let attrStr: NSMutableAttributedString = NSMutableAttributedString(string: "Hello world")
attrStr.color(.yellow, occurences: "llo")

Colorize everything after an occurence:

let attrStr = NSMutableAttributedString.colored(inText: "Hello world", color: .yellow, afterOcurrence: "llo")

// OR

let attrStr = NSMutableAttributedString(string: "Hello world")
attrStr.color(.yellow, afterOcurrence: "llo")

Strike each occurence:

let attrStr: NSMutableAttributedString = NSMutableAttributedString.struck(inText: "Hello world", occurences: "llo")

// OR

let attrStr = NSMutableAttributedString(string: "Hello world")
attrStr.strike(occurences: "llo")

Strike everything after an occurence:

let attrStr: NSMutableAttributedString = NSMutableAttributedString.struck(inText: "Hello world", afterOcurrence: "llo")

// OR

let attrStr = NSMutableAttributedString(string: "Hello world")
attrStr.strike(ocurrences: "llo")

Underline each occurence:

let attrStr: NSMutableAttributedString = NSMutableAttributedString.underlined(inText: "Hello world", occurences: "llo")

// OR

let attrStr = NSMutableAttributedString(string: "Hello world")
attrStr.underline(occurences: "llo")

Underline everything after an occurence:

let attrStr: NSMutableAttributedString = NSMutableAttributedString.underlined(inText: "Hello world", afterOcurrence: "llo")

// OR

let attrStr = NSMutableAttributedString(string: "Hello world")
attrStr.underline(afterOcurrence: "llo")

Use custom font for each occurence:

let font = UIFont.boldSystemFont(ofSize: 15)
let attrStr: NSMutableAttributedString = NSMutableAttributedString.font(inText: "hello world", font: font, occurences: "llo")

// OR

let attrStr: NSMutableAttributedString = NSMutableAttributedString(string: "Hello world")
attrStr.font(font, occurences: "llo")

Custom font for everything after an occurence:

let font = UIFont.boldSystemFont(ofSize: 15)
let attrStr = NSMutableAttributedString.colored(inText: "Hello world", font: font, afterOcurrence: "llo")

// OR

let attrStr = NSMutableAttributedString(string: "Hello world")
attrStr.font(font, afterOcurrence: "llo")

NSObject extension

Get the class name of a NSObject:

#if !os(macOS)
	let vc = NSViewController()
	print(vc.className) // NSViewController
#else
	let vc = UIViewController()
	print(vc.className) // UIViewController
	print(UIViewController.className) // UIViewController
#endif

NSRange extension

Range after an occurence:

let string = "Hello world"
let range = NSRange(text: string, afterOccurence: "llo")
print(range) // location: 3, length: 8

Range of string:

let string = "Hello world"
let stringToFind = "ello wo"
let range = NSRange(textToFind: stringToFind, in: string)
print(range) // location: 1, length: 7

ReusableFormatters

Reuse your formatter to avoid heavy allocation:

SUDateFormatter.shared
SUNumberFormatter.shared
SUByteCountFormatter.shared
SUDateComponentsFormatter.shared
SUDateIntervalFormatter.shared
SUEnergyFormatter.shared
SUMassFormatter.shared

Sequence extension

Sort a sequence using keyPath:

let articles = [Article(title: "B"), Article(title: "C"), Article(title: "A")]
var sortedArticles = articles.sorted(by: \.title) // [A, B, C]
sortedArticles = articles.sorted(by: \.title, order: >) // [C, B, A]

String extension

Access with subscript:

var string = "hello world"
print(string[0]) // h
print(string[2]) // l
print(string[1...3]) // ell

Check if it contains a string:

let string = "Hello world"
print (string.contains(text: "hello")) // true
print (string.contains(text: "hellooooo")) // false

Check if it's a number:

var string = "4242"
print(string.isNumber) // true

var string = "test"
print(string.isNumber) // false

Check if it's a valid email:

var string = "[email protected]"
print(string.isEmail) // true
var string = "test@"
print(string.isEmail) // false

Check if it's a valid IP address:

let ip4 = "1.2.3.4"
let ip6 = "fc00::"
let notIPAtAll = "i'll bribe you to say i'm an ip address!"

ip4.isIP4Address //true
ip4.isIP6Address //false
ip4.isIPAddress //true

ip6.isIP4Address //false
ip6.isIP6Address //true
ip6.isIPAddress //true

notIPAtAll.isIP4Address //false
notIPAtAll.isIP6Address //false
notIPAtAll.isIPAddress //false

Uncamelize a string:

var camelString = "isCamelled"
print(camelString.uncamelize) // is_camelled

Capitalize the first letter:

var string = "hello world"
string = string.capitalizedFirst
print(string)// Hello world

Trimmed spaces and new lines:

var string = " I'  am a    test  \n  "
print(string.trimmed()) // I'am a test

Truncated to have a limit of characters:

var string = "0123456789aaaa"
print(string.truncate(limit: 10)) // 0123456789...

Split string in chunks of n elements:

let string = "abcd"
print(string.split(intoChunksOf: 2)) // ["ab", "cd"]

Timer extension

Schedule timer every seconds:

var count = 0
Timer.every(1.second, fireImmediately: true) { timer in // fireImmediately is an optional parameter, defaults to false
    print("Will print every second")
    if count == 3 {
        timer.invalidate()
    }
    count++
}

Schedule timer after a certain delay:

Timer.after(2.seconds) { _ in
    print("Prints this 2 seconds later in main queue")
}

Manual scheduling a timer:

let timer = Timer.new(every: 2.seconds) { _ in
    print("Prints this 2 seconds later in main queue")
}
timer.start(onRunLoop: RunLoop.current, modes: RunLoopMode.defaultRunLoopMode)

Manual scheduling a timer with a delay:

let timer = Timer.new(after: 2.seconds) { _ in
    print("Prints this 2 seconds later in main queue")
}
timer.start(onRunLoop: RunLoop.current, modes: RunLoopMode.defaultRunLoopMode)

URL extension

Get query parameters from URL:

let url = URL(string: "http://example.com/api?v=1.1&q=google")
let queryParameters = url?.queryParameters
print(queryParameters?["v"]) // 1.1
print(queryParameters?["q"]) // google
print(queryParameters?["other"]) // nil

Add skip backup attributes to you URL:

let url = URL(string: "/path/to/your/file")        
url?.addSkipBackupAttribute() // File at url won't be backupped!

UserDefaults extension

Get and set values from UserDefaults with subscripts:

let Defaults = UserDefaults.standard
Defaults["userName"] = "test"
print(Defaults["userName"]) // test

Check if the UserDefaults has a key:

UserDefaults.has(key: "aKey")
// OR
UserDefaults.standard.has(key: "aKey")

Remove all values in UserDefaults:

UserDefaults.standard.removeAll()

SwiftUI

UIElementPreview

Generate automatically multiple previews including:

  • Default sized preview or dedicated preview device
  • A preview with Dark Mode enabled
  • Each localization of our project applied to a preview
  • Different dynamic type sizes applied
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        UIElementPreview(ContentView(),
                         previewLayout: .sizeThatFits, // default is `.device`
                         previewDevices: ["iPhone SE"], // default is iPhone SE and iPhone XS Max. Note: it won't be used if `previewLayout` is `.sizeThatFits`
                         dynamicTypeSizes:[.extraSmall] // default is: .extraSmall, .large, .extraExtraExtraLarge
                        )
    }
}

SwiftUI Extensions

Binding extension

Pass an interactive value that’ll act as a preview stand-in for a binding:

struct MyButton: View {
    @Binding var isSelected: Bool
    // ...
}

struct MyButton_Previews: PreviewProvider {
    static var previews: some View {
        MyButton(isSelected: .mock(true))
    }
}

UIKit Extensions

UIAlertController extension

Create a custom UIAlertController:

let alertController1 = UIAlertController(title: "Title",
                                        message: "Message")
                          
let alertController2 = UIAlertController(title: "Title",
                                        message: "Message",
                                        defaultActionButtonTitle: "Cancel")
                                                      
let alertController3 = UIAlertController(title: "Title",
                                        message: "Message",
                                        defaultActionButtonTitle: "Cancel",
                                        defaultActionButtonStyle: .cancel) 
                                        
let alertController1 = UIAlertController(title: "Title",
                                        message: "Message",
                                        defaultActionButtonTitle: "Cancel",
                                        defaultActionButtonStyle: .cancel,
                                        tintColor: .blue)

Show an UIAlertController:

alertController.show()
alertController.show(animated: false)
alertController.show(animated: true, completion: {
    print("Presented")
})

Add an action to the UIAlertController:

alertController.addAction(title: "ActionTitle")

alertController.addAction(title: "ActionTitle",
                          style: .destructive)
                          
alertController.addAction(title: "ActionTitle",
                          style: .destructive,
                          isEnabled: false)
                          
alertController.addAction(title: "ActionTitle",
                          style: .destructive,
                          isEnabled: false,
                          handler: nil)

UIApplication extension

Get the current view controller display:

UIApplication.shared.topViewController() // Using UIWindow's rootViewController as baseVC
UIApplication.shared.topViewController(from: baseVC) // topVC from the base view controller

Get the app delegate:

UIApplication.delegate(AppDelegate.self)

Open app settings:

UIApplication.shared.openAppSettings()

Open app review page:

let url = URL(string: "https://itunes.apple.com/app/{APP_ID}?action=write-review")
UIApplication.shared.openAppStoreReviewPage(url)

UIButton extension

Add right image with custom offset to button:

let button = UIButton(frame: .zero)
button.addRightImage(image, offset: 16)

UICollectionView extension

Register and dequeue safely your UICollectionViewCell:

// 1. Make your `UICollectionCell` conforms to `Reusable` (class-based) or `NibReusable` (nib-based)
final class ReusableClassCollectionViewCell: UICollectionViewCell, Reusable {}
// 2. Register your cell:
collectionView.register(cellType: ReusableClassCollectionViewCell.self)
// 3. Dequeue your cell:
let cell: ReusableClassCollectionViewCell = collectionView.dequeueReusableCell(at: indexPath)

Register and dequeue safely your UICollectionReusableView:

// 1. Make your `UICollectionReusableView` conforms to `Reusable` (class-based) or `NibReusable` (nib-based)
final class ReusableNibCollectionReusableView: UICollectionReusableView, NibReusable
// 2. Register your cell:
collectionView.register(supplementaryViewType: ReusableNibCollectionReusableView.self, ofKind: UICollectionView.elementKindSectionHeader)
// 3. Dequeue your cell:
let header: ReusableNibCollectionReusableView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: indexPath)

UICollectionViewCell extension

Apply a corner radius to the cell:

let cell = UICollectionViewCell()
cell.applyCornerRadius(10)

Animate when cell is highlighted:

class MyCollectionViewCell: UICollectionViewCell {
    // ...
    override var isHighlighted: Bool {
        willSet {
            self.animate(scale: newValue, options: .curveEaseInOut) // Note that the animation is customisable, but all parameters as default value
        }
    }
    // ...
}

UIFont extension

Obtains a font that scale to support Dynamic Type:

let font = UIFont.dynamicStyle(.body, traits: .traitsBold)

UIDevice extension

Access to your device information:

print(UIDevice.idForVendor) // 104C9F7F-7403-4B3E-B6A2-C222C82074FF
print(UIDevice.systemName()) // iPhone OS
print(UIDevice.systemVersion()) // 9.0
print(UIDevice.deviceName) // iPhone Simulator / iPhone 6 Wifi
print(UIDevice.deviceLanguage) // en
print(UIDevice.isPhone) // true or false
print(UIDevice.isPad) // true or false

Check your system version:

print(UIDevice.isVersion(8.1)) // false
print(UIDevice.isVersionOrLater(8.1)) // true
print(UIDevice.isVersionOrEarlier(8.1)) // false

Force device orientation:

UIDevice.forceRotation(.portrait)
UIDevice.current.forceRotation(.portrait)

UIImage extension

Create an image from a color:

let image = UIImage(color: .green)

Fill an image with a color:

let image = UIImage(named: "image")
let greenImage = image.filled(with: .green)

Combined an image with another:

let image = UIImage(named: "image")
let image2 = UIImage(named: "image2")
let combinedImage = image.combined(with: image2)

Change the rendering mode:

var image = UIImage(named: "image")
image = image.template // imageWithRenderingMode(.alwaysTemplate)
image = image.original // imageWithRenderingMode(.alwaysOriginal)

UILabel extension

Configure a dynamic text style to the label:

label.configureDynamicStyle(.body, traits: .traitBold)

Detect if a label text is truncated:

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 30, height: 40))
label.text = "I will be truncated :("
print(label.isTruncated()) // true

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 30, height: 40))
label.text = ":)"
print(label.isTruncated()) // false

Customize label line height:

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 30, height: 40))
label.setText("A long multiline text")
label.setLineHeight(0.9)

Customize the label truncated text (replace the default ...):

let label = UILabel(frame: CGRect(x: 0, y: 0, width: 30, height: 40))
label.setText("I will be truncated :(", truncatedText: ".")
print(label.text) // I wi.

UIScreen extension

Get the screen orientation:

if UIInterfaceOrientationIsPortrait(UIScreen.currentOrientation) {
    // Portrait
} else {
    // Landscape
}

Get the screen size:

print(UIScreen.size) // CGSize(375.0, 667.0) on iPhone6
print(UIScreen.width) // 375.0 on iPhone6
print(UIScreen.height) // 667.0 on iPhone6
print(UIScreen.heightWithoutStatusBar) // 647.0 on iPhone6

Get the status bar height:

print(UIScreen.statusBarHeight) // 20.0 on iPhone6

UISlider extension

Get the value where the user tapped using an UITapGestureRecognizer:

let slider = UISlider(frame: .zero)
slider.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(sliderTapped(_:))))

func sliderTapped(sender: UITapGestureRecognizer) {
    let value = slider.value(for: sender)
}

UIStoryboard extension

Get the application's main storyboard:

let storyboard = UIStoryboard.main

UISwitch extension

Toggle UISwitch:

let aSwitch = UISwitch(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
aSwitch.toggle()
print(aSwitch.isOn) // true

aSwitch.toggle(animated: false)

UITableView

Register and dequeue safely your UITableViewCell:

// 1. Make your `UITableViewCell` conforms to `Reusable` (class-based) or `NibReusable` (nib-based)
final class ReusableClassTableViewCell: UITableViewCell, Reusable {}
// 2. Register your cell:
tableView.register(cellType: ReusableClassTableViewCell.self)
// 3. Dequeue your cell:
let cell: ReusableClassTableViewCell = tableView.dequeueReusableCell(at: indexPath)

Register and dequeue safely your UITableViewHeaderFooterView:

// 1. Make your `UITableViewHeaderFooterView` conforms to `Reusable` (class-based) or `NibReusable` (nib-based)
final class ReusableClassHeaderFooterView: UITableViewHeaderFooterView, Reusable {}
// 2. Register your header or footer:
tableView.register(headerFooterViewType: ReusableClassHeaderFooterView.self)
// 3. Dequeue your header or footer:
let cell: ReusableClassHeaderFooterView = tableView.dequeueReusableHeaderFooterView()

UITextField extension

Configure a dynamic text style to the textfield:

textField.configureDynamicStyle(.body, traits: .traitBold)

Modify clear button image:

let clearButtonImage = UIImage(named: "clear_button")
let textField = UITextField()
textField.setClearButton(with: clearButtonImage)

Modify placeholder's color:

let textField = UITextField()
// set `placeholder` or `attributedPlaceholder`
textField.setPlaceHolderTextColor(.blue)

UITextView extension

Configure a dynamic text style to the textfield:

textView.configureDynamicStyle(.body, traits: .traitBold)

UIView extension

Change the frame of the view easily:

let aView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
aView.x += 100 // move  to right
aView.y += 100 // move downwards
aView.width -= 10 // make the view narrower
aView.height -= 10 // make the view shorter 

Apply a corner radius to the view:

let view = UIView()
view.applyCornerRadius(10)
view.applyCornerRadius(20, maskedCorners: [.layerMaxXMaxYCorner])

Find the ViewController which contains this view:

let parent: UIViewController? = aView.parentViewController

Find a subview using its `accessibilityIdentifier, useful to tests private outlets:

aView.findView(forIdentifier: "accessibilityIdentifier")

Find the first subview corresponding to a specific type:

let scrollView: UIScrollView? = aView.findView()

Add a SwiftUI View as a subview:

aView.addSubSwiftUIView(SwiftUIView())

Automates your localizables:

aView.translateSubviews()

It will iterate on all the subviews of the view, and use the text / placeholder as key in NSLocalizedString. By settings your localizable key in your xib / storyboard, all yours string will be automatically translated just by calling the above method.

Add constraints between a view and its superview:

aView.addConstraints() // Add constraints to all edges with zero insets
aView.addConstraints(to: [.top, .bottom]) // Add constraints to top and bottom edges with zero insets
aView.addConstraints(to: [.top, .left], insets: UIEdgeInsets(top: 10, left: 20, bottom: 0, right: 0)) // Add constraints to top and left edges with custom insets

UIViewController extension

Generate a Xcode preview for any view controllers:

@available(iOS 13, *)
struct MyViewPreview: PreviewProvider {
    static var previews: some View {
        MyViewController().preview
    }
}

Reset the navigation stack by deleting previous view controllers:

let navController = UINavigationController()
navController.pushViewController(vc1, animated: true)
navController.pushViewController(vc2, animated: true)
navController.pushViewController(vc3, animated: true)
vc3.removePreviousControllers(animated: true)
print(navController.viewControllers) // [vc3]

Check if ViewController is onscreen and not hidden:

let viewController = UIViewController()
print(viewController.isVisible) // false

Check if ViewController is presented modally:

let viewController = UIViewController()
print(viewController.isModal)

Open Safari modally:

let url = URL(string: "https://www.apple.com")
vc.openSafariVC(url: url, delegate: self)

Add a child view controller to another controller:

vc.addChildController(childVC, subview: vc.view, animated: true, duration: 0.35, options: [.curveEaseInOut, .transitionCrossDissolve])

Add a child view controller to a container view:

vc.addChildController(childVC, in: containerView)

Remove a child view controller:

vc.removeChildController(childVC)

Add a SwiftUI View as a child of the input UIView:

vc.addSubSwiftUIView(SwiftUIView(), to: vc.view)

UIKit Protocols:

NibLoadable

Make your UIView subclasses conform to this protocol to instantiate them from their NIB safely. Note: Be sure that your UIView is based on a Nib, and is used as the Xib's root view.

class NibLoadableView: UIView, NibLoadable {
    // ...
}

let view = NibLoadableView.loadFromNib()

NibOwnerLoadable

Make your UIView subclasses conform to this protocol to instantiate them from their Xib's File Owner safely. Note: Be sure that your UIView is based on a Nib, and is used as the Xib's File's Owner.

class NibLoadableView: UIView, NibOwnerLoadable {
    // ...
    
    required init?(coder aDecoder: NSCoder) {
      super.init(coder: aDecoder)
      self.loadNibContent()
    }

}

// Then use it directly from another xib or whatever...

AppKit, Cocoa Extensions

NSView extension

Change the frame of the view easily

let aView = NSView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
aView.x += 100 // move  to right
aView.y += 100 // move downwards
aView.width -= 10 // make the view narrower
aView.height -= 10 // make the view shorter 

Automates your localizables

aView.convertLocalizables()

It will iterate on all the subviews of the view, and use the text / placeholder as key in NSLocalizedString. By settings your localizable key in your xib / storyboard, all yours string will be automatically translated just by calling the above method.

Protocols

Injectable

Protocol to do ViewController Data Injection with Storyboards and Segues in Swift. Inspired from Nastasha's blog:

class RedPillViewController: UIViewController, Injectable {

    @IBOutlet weak private var mainLabel: UILabel!

    // the type matches the IOU's type
    typealias T = String

    // this is my original dependency (IOU)
    // I can now make this private!
    private var mainText: String!

    override func viewDidLoad() {
        super.viewDidLoad()

        // this will crash if the IOU is not set
        assertDependencies()

        // using the IOU if needed here,
        // but using it later is fine as well
        mainLabel.text = mainText
    }

    // Injectable Implementation
    func inject(text: T) {
        mainText = text
    }

    func assertDependencies() {
        assert(mainText != nil)
    }
}

// ViewController that will inject data...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    switch segueIdentifierForSegue(segue) {
    case .TheRedPillExperience
        let redPillVC = segue.destinationViewController as? RedPillViewController
        redPillVC?.inject("😈")
    case .TheBluePillExperience:
        let bluePillVC = segue.destinationViewController as? BluePillViewController
        bluePillVC?.inject("👼")
    }
}

Occupiable

The following use cases works for String Array, Dictionary, and Set

isEmpty / isNotEmpty

No optional types only

var string = "Hello world"
print(string.isNotEmpty) // true
print(string.isEmpty) // false

isNilOrEmpty

Optional types only

let string: String? = ""
print(string.isNilOrEmpty) // true

Then

Syntactic sugar for Swift initializers:

let label = UILabel().then {
    $0.textAlignment = .Center
    $0.textColor = .blackColor()
    $0.text = "Hello, World!"
}

PropertyWrappers

UserDefaultsBacked

Type safe access to UserDefaults with support for default values.

struct SettingsViewModel {
    @UserDefaultsBacked(key: "search-page-size", defaultValue: 20)
    var numberOfSearchResultsPerPage: Int

    @UserDefaultsBacked(key: "signature")
    var messageSignature: String?
}

Others

UnitTesting

Grand Central Dispatch sugar syntax:

Detect if UITests are running:

if UnitTesting.isRunning {
  // tests are running
} else {
  // everything is fine, move along
}

Measure tests performance:

func testPerformance() {
  let measurement = measure {
    // run operation
  }
}

UITesting

Detect if UITests are running:

if UITesting.isRunning {
  // tests are running
} else {
  // everything is fine, move along
}

Shell Utility

(macOS only)

Runs a command on a system shell and provides the return code for success, STDOUT, and STDERR.

STDOUT as one continuous String:

let (rCode, stdOut, stdErr) = SystemUtility.shell(["ls", "-l", "/"])
// rCode = 0 (which is "true" in shell)
// stdOut = "total 13\ndrwxrwxr-x+ 91 root  admin  2912 Feb 11 01:24 Applications" ...  etc
// stdErr = [""]

STDOUT as array of Strings separated by newlines:

let (rCode, stdOut, stdErr) = SystemUtility.shellArrayOut(["ls", "-l", "/"])
// rCode = 0 (which is "true" in shell)
// stdOut = ["total 13", "drwxrwxr-x+ 91 root  admin  2912 Feb 11 01:24 Applications" ...  etc]
// stdErr = [""]

Installation

  • Xcode 8 and later
  • Swift 3.0
  • iOS 8.0 or later
  • macOS 10.10 or later
  • tvOS 9.0 or later
  • watchOS 2.0 or later

Manually

Copy the SwiftyUtils folder into your Xcode project. (Make sure you add the files to your target(s))

CocoaPods

Add pod SwiftyUtils to your Podfile.

Carthage

Add github "tbaranes/SwiftyUtils" to your Cartfile.

Swift Package Manager

You can use The Swift Package Manager to install SwiftyUtils by adding the proper description to your Package.swift file:

import PackageDescription

let package = Package(
    dependencies: [
        .Package(url: "https://github.com/tbaranes/SwiftyUtils.git", majorVersion: 0)
    ]
)

Feedback

  • If you found a bug, open an issue
  • If you have a feature request, open an issue
  • If you want to contribute, submit a pull request

Contact

License

SwiftyUtils is under the MIT license. See the LICENSE file for more information. dic.testAll

Comments
  • Added UIView, NSView and CGRect extensions

    Added UIView, NSView and CGRect extensions

    I added some things that make dealing with positions and sizes easier. e.g. you can easily change a view's position by setting its x and y properties.

    opened by Sweeper777 24
  • I can't install version 3.0.0

    I can't install version 3.0.0

    I am using Swift 4.2 so I guess I should install version 3.0.0, right?

    So I did this in Podfile:

    pod 'SwiftyUtils', '3.0.0'
    

    and did pod update.

    And this error popped up:

    [!] CocoaPods could not find compatible versions for pod "SwiftyUtils":
      In Podfile:
        SwiftyUtils (= 3.0.0)
    
    None of your spec sources contain a spec satisfying the dependency: `SwiftyUtils (= 3.0.0)`.
    
    You have either:
     * mistyped the name or version.
     * not added the source repo that hosts the Podspec to your Podfile.
    

    If I remove '3.0.0', then version 2.0.0 is installed. What can I do?

    opened by Sweeper777 8
  • Can the members that use UIApplication.shared be marked unavailable in an app extension?

    Can the members that use UIApplication.shared be marked unavailable in an app extension?

    I am trying to use SwiftyUtils in a Today Extensions target, and I get errors in places such as:

    extension UIAlertController {
    
        @objc
        public func show(animated: Bool = true, completion: (() -> Void)? = nil) {
            UIApplication.shared.topViewController()?.present(self, animated: animated, completion: completion)
        }
    
    }
    

    I understand that this is because UIApplication.shared is unavailable in an extension.

    I still want to be able to use SwiftyUtils in a today extension, is there some way to kind of conditionally compile the code that uses UIApplication.shared? Like a if #available check or something like that...

    opened by Sweeper777 7
  • Swift3 api guidelines

    Swift3 api guidelines

    I updated the method and property names so that they follow the Swift 3 API guidelines.

    However, I can’t find some of the methods’ definitions described in README e.g. the UIDevice extensions. Where can I find them?

    opened by Sweeper777 7
  • Readme on Date updated

    Readme on Date updated

    Does the readme need to be corrected for:

    Check if a date is in future or past:

    let later = Date(timeIntervalSinceNow: -100000) print(now.isInFuture) // true print(now.isInPast) // false

    later is not used in the example?

    opened by justdan0227 4
  • NSTimer fuctions not working

    NSTimer fuctions not working

    Trying to use the NSTimer fuctions XCode 7.3.1 targeted for ios8.
    var count = 0 NSTimer.every(1.seconds) { timer in print("Will print every second") if count == 3 { timer.invalidate() } count++ }
    says every is Ambiguous ?

    opened by justdan0227 4
  • Swift Package Manager 4 support

    Swift Package Manager 4 support

    I'm trying to use SwiftyUtils with Swift Package Manager 4, but have errors.

    Package.swift is:

    // swift-tools-version:4.0
    // The swift-tools-version declares the minimum version of Swift required to build this package.
    
    import PackageDescription
    
    let package = Package(
        name: "test-SwiftyUtils-SPM4",
        dependencies: [
            .package(url: "https://github.com/tbaranes/SwiftyUtils.git", from: "2.0.0")
        ],
        targets: [
            .target(
                name: "test-SwiftyUtils-SPM4",
                dependencies: ["SwiftyUtils"]),
        ]
    )
    

    When I run swift package generate-xcodeproj, i get:

    error: package has unsupported layout; found loose source files: /Users/john/Desktop/test-SwiftyUtils-SPM4/.build/checkouts/SwiftyUtils.git--6738090307716277572/Sources/Constants.swift
    

    I'm using: Apple Swift Package Manager - Swift 4.0.0-dev (swiftpm-13752) Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2 macOS Sierra 10.12.6

    opened by rootscript 3
  • Won't compile 4.2

    Won't compile 4.2

    Just tried to update a project from last summer, and when xCode prompts to convert to 4.2, SwiftyUtils has all kinds of errors. Am I missing a branch for 4.2?

    opened by justdan0227 2
  • UIStoryboard extension

    UIStoryboard extension

    Removing it since the only plus value was the fatalError, or I think we should avoid fatalError for a sugar library. Removing this fatalError makes that extension useless

    opened by tbaranes 2
  • Cleaning array

    Cleaning array

    Cleaning a bit the code for ArrayExtension, and removing a few methods. I don't think that methods are really useful beside the safe get which has been replaced by the safe subscript.

    @Sweeper777 Can you take a look at this when you will have a few time? Let me know if you think we should keep some of them or remove / renames the others.

    opened by tbaranes 2
  • How Timer.every works is not quite intuitive (at least to me)

    How Timer.every works is not quite intuitive (at least to me)

    I expected Timer.every to fire the timer once immediately after start is called but it actually fires for the first time after the interval specified. Maybe this is just me, but I am thinking whether I should add a default parameter to the every method, something like fireImmediately: Bool = false. If it is set to true, the timer will behave in my "intuitive" way. I made this a default parameter so it will not break any existing code.

    Should I make such a change? Do you think this feature should be added?

    opened by Sweeper777 2
Releases(5.5.2)
  • 5.5.2(Oct 5, 2022)

  • 5.5.1(Dec 8, 2020)

  • 5.5.0(Nov 8, 2020)

    Enhancements

    • UIViewControllerExtension:
    func addSubSwiftUIView<Content>(_ swiftUIView: Content, to view: UIView) where Content: View
    
    • UIViewExtension:
    var parentViewController: UIViewController?
    func findView<T>() -> T?
    func addSubSwiftUIView<Content>(_ swiftUIView: Content) where Content: View 
    func addBorders(to edges: UIRectEdge, borderColor: UIColor, borderWidth: CGFloat)
    
    Source code(tar.gz)
    Source code(zip)
  • 5.4.0(Oct 6, 2020)

  • 5.3.0(Jul 2, 2020)

    Enhancements

    • UIViewControllerExtension:
    var preview: some View
    
    • BindingExtension:
    static func mock(_ value: Value) -> Self {
    
    • MutableCollection:
    mutating func sort<T: Comparable>(by keyPath: KeyPath<Element, T>, order: (T, T) -> Bool = (<))
    
    • SequenceExtension:
    func sorted<T: Comparable>(by keyPath: KeyPath<Element, T>, order: (T, T) -> Bool = (<)) -> [Element]
    
    • UITableViewExtension:
    func register<T: UITableViewCell>(cellType: T.Type) where T: Reusable & NibLoadable
    func register<T: UITableViewCell>(cellType: T.Type) where T: Reusable
    func dequeueReusableCell<T: UITableViewCell>(for indexPath: IndexPath, cellType: T.Type = T.self) -> T where T: Reusable
    func register<T: UITableViewHeaderFooterView>(headerFooterViewType: T.Type) where T: Reusable & NibLoadable
    func register<T: UITableViewHeaderFooterView>(headerFooterViewType: T.Type) where T: Reusable
    func dequeueReusableHeaderFooterView<T: UITableViewHeaderFooterView>(_ viewType: T.Type = T.self) -> T? where T: Reusable
    
    • UICollectionViewCellExtension:
    func register<T: UICollectionViewCell>(cellType: T.Type) where T: Reusable & NibLoadable
    func register<T: UICollectionViewCell>(cellType: T.Type) where T: Reusable T.self) -> T where T: Reusable
    func register<T: UICollectionReusableView>(supplementaryViewType: T.Type, ofKind elementKind: String) where T: Reusable & NibLoadable
    func register<T: UICollectionReusableView>(supplementaryViewType: T.Type, ofKind elementKind: String) where T: Reusable
    func dequeueReusableSupplementaryView<T: UICollectionReusableView>(ofKind elementKind: String, for indexPath: IndexPath, viewType: T.Type = T.self) -> T where T: Reusable
    
    • Protocols:
    protocol NibLoadable: AnyObject
    protocol NibOwnerLoadable: AnyObject
    protocol Reusable: AnyObject
    typealias NibReusable = Reusable & NibLoadable
    
    Source code(tar.gz)
    Source code(zip)
  • 5.2.0(Apr 28, 2020)

    Enhancements

    • UIFontExtension:
    class func dynamicStyle(_ style: UIFont.TextStyle, traits: UIFontDescriptor.SymbolicTraits?, sizeCategory: UIContentSizeCategory = .large) -> UIFont
    
    • UILabelExtension:
    func configureDynamicStyle(_ style: UIFont.TextStyle, traits: UIFontDescriptor.SymbolicTraits? = nil, minimumScaleFactor: CGFloat = 0.8)
    
    • UITextFieldExtension:
    func configureDynamicStyle(_ style: UIFont.TextStyle, traits: UIFontDescriptor.SymbolicTraits? = nil, adjustToFit: Bool = true)
    
    • UITextViewExtension:
    func configureDynamicStyle(_ style: UIFont.TextStyle, traits: UIFontDescriptor.SymbolicTraits? = nil)
    

    Bugfixes

    • Fixed missing swift sources added to the targets when using CocoaPods to embed SwiftyUtils
    Source code(tar.gz)
    Source code(zip)
  • 5.1.0(Apr 26, 2020)

    Enhancements

    • Completing missing unit tests
    • Adding documentation to the code
    • Adding UIElementPreview, an easy way to generate mulitple SwiftUI previews with different configuration
    • BundleExtension:
    var displayName: String
    
    • DictionaryExtension
    func toData(options: JSONSerialization.WritingOptions = []) throws -> Data?
    
    • DataExtension:
    func toDictionary(options: JSONSerialization.ReadingOptions = []) throws -> [String: Any]?
    
    • NSAttributedStringExtension:
    func isAttributeActivated(_ attribute: NSAttributedString.Key, appliedOn text: String, value: Any) -> Bool
    
    • UIApplicationExtension:
    func openAppSettings()
    func openAppStoreReviewPage(_ url: URL)
    
    • UIButtonExtension:
    func addRightImage(_ image: UIImage?, offset: CGFloat)
    
    • UICollectionViewCellExtension:
    func applyCornerRadius(_ radius: CGFloat)
    func animate(scale: Bool, duration: TimeInterval = 0.35, transformScale: CGFloat = 0.97, damping: CGFloat = 0.7, options: UIView.AnimationOptions = [], delay: TimeInterval = 0.0, velocity: CGFloat = 0.0, completion: ((Bool) -> Void)? = nil)
    
    • UIViewExtension:
    func findView(forIdentifier identifier: String) -> UIView?
    func addConstraints(to edges: UIRectEdge = .all, insets: UIEdgeInsets = .zero)
    func applyCornerRadius(_ radius: CGFloat, maskedCorners: CACornerMask [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner]) 
    
    • UIViewController:
    var isModal: Bool
    func addChildController(_ controller: UIViewController, to subview: UIView, animated: Bool = true, duration: TimeInterval = 0.35, options: UIView.AnimationOptions = [.curveEaseInOut, .transitionCrossDissolve])
    func addChild(_ child: UIViewController, in containerView: UIView)
    func removeChildController(_ child: UIViewController)
    func openSafariVC(withURL url: URL, delegate: SFSafariViewControllerDelegate, tintColor: UIColor = .black, barTintColor: UIColor = .white, barCollapsing: Bool = true)
    
    • PropertyWrappers:
    @UserDefaultsBacked(key: "defaults_key", defaultValue: 20)
    var defaultValue: Int
    @UserDefaultsBacked(key: "default_key2")
    var defaultKey2: String?
    
    Source code(tar.gz)
    Source code(zip)
  • 5.0.1(Nov 13, 2019)

  • 5.0.0(Nov 12, 2019)

    API breaking changes

    • Xcode 11 and Swift 5 support

    Enhancements

    • Moving from Travis to Github Actions
    • Updating Swiftlint and fix all related warnings

    Bugfixes

    • Fixed SPM support
    Source code(tar.gz)
    Source code(zip)
  • 4.0.0(Mar 27, 2019)

    API breaking changes

    • Xcode 10.2 and Swift 5 support

    Enhancements

    • Added Data extensions
      • data to hex string
      • hex string to data
      • data to UInt8 array
    • Added SystemUtility struct with shell command access
    • added ip address validation extension to String
    Source code(tar.gz)
    Source code(zip)
  • 3.0.0(Sep 18, 2018)

    API breaking changes

    • Xcode 10 and Swift 4.2 support
    • Removing following methods:
      • Simulator
      • Iteratable
      • Collection's random and shuffle
      • Collection's testAll, removeAll
      • Dictionnary map and flatMap

    Bugfixes

    • Keep label lineBreakMode when using setLineHeight
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Nov 4, 2017)

    API breaking changes

    • Xcode 9 and Swift 4 support
    • Removing String.length, starting with swift 4, you can directly user String.count

    Enhancements

    • Each UIButton's UIControlState will be translated when using translateSubviews
    • UIApplicationExtension (iOS only)
    public static func delegate<T: UIApplicationDelegate>(_ type: T.Type) -> T? 
    
    • NSMutableAttributedString:
    public static func font(inText text: String, font: SwiftyFont, afterOcurrence occurence: String) -> NSMutableAttributedString
    public func font(_ font: SwiftyFont, afterOcurrence occurence: String)
    
    public static func font(inText text: String, font: SwiftyFont, occurences searchString: String) -> NSMutableAttributedString
    public func font(_ font: SwiftyFont, occurences searchString: String)
    

    Bugfixes

    • Make Array subscript public
    • No more duplicate letter when using String's capitalizedFirst
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Apr 16, 2017)

    In order to reach 1.0, SwiftyUtils got a huge cleanup:

    • Removing extensions /classes that didn't fit in the library's spirit
    • Renaming methods to make them more Swifty
    • Introducing dozens of new extensions
    • Adding a few missing tests
    • Updating the docs
    • ...

    Since that release contains a lot of changes we won't details them all.

    We are really sorry to introduce that many breaking changes, but it was a mandatory cost to release 1.0! Also, the future release should have none (or a very low number) breaking changes and a lot of new features 🎉

    Many thanks to Sweepr777 for reviewing all the PRs!

    Source code(tar.gz)
    Source code(zip)
  • 0.7.0(Jan 15, 2017)

    API breaking changes

    • Some APIs have been updated to follow the Swift 3 API guidelines, check out the README for more information

    Enhancements

    Note: Take a look into the README to see the details of all the following enhancements

    • UILabelExtension (iOS only)
    public func setLineHeight(_ lineHeight: CGFloat)
    
    • CGRectExtension
    public var x: CGFloat
    public var y: CGFloat
    public func with(x: CGFloat) -> CGRect
    public func with(y: CGFloat) -> CGRect
    public func with(width: CGFloat) -> CGRect
    public func with(height: CGFloat) -> CGRect
    public func with(origin: CGPoint) -> CGFloat
    public func with(size: CGSize) -> CGFloat
    
    • UIViewExtension and NSViewExtension
    public var x: CGFloat
    public var y: CGFloat
    public var width: CGFloat
    public var height: CGFloat
    
    Source code(tar.gz)
    Source code(zip)
  • 0.6.0(Nov 18, 2016)

    API breaking changes

    • NSDate is now used as Date

    Enhancements

    Note: Take a look into the README to see the details of all the following enhancements

    New protocols available:

    • Iteratable

    New extensions:

    • CGFloatLiteral (Integer / Float extension):
    public var f: CGFloat
    
    • Array
    subscript(safe index: Int) -> Element?
    
    • Sugar syntax for Date
    Too many things to be described here... check the README
    
    • UILabelExtension (iOS only)
    func isTruncated() -> Bool
    func setText(_ text: String, truncatedText: String)
    

    New extensions for macOS:

    • NSView:
    func convertLocalizables()
    
    Source code(tar.gz)
    Source code(zip)
  • 0.5.0(Sep 14, 2016)

    API breaking changes

    • Swift 3 support. README is up to date, please report if you find any diffs
    • Some APIs have been updated to be more swifty, check out the README for more information

    Classes removed:

    • Async

    Extensions removed:

    • {UI/NS}Color:
    convenience init(hex: String, alpha: Float)
    
    • UIDevice:
    class func deviceModel() -> String
    

    Enhancements

    Note: Take a look into the README to see the details of all the following enhancements

    • watchOS support

    New classes:

    • UITesting
    • UnitTesting

    New iOS classes:

    • Simulator

    New extensions:

    • Color:
    var redComponent: Int
    var greenComponent: Int
    var blueComponent: Int
    var alpha: CGFloat
    
    • String:
    init?(value: Float, maxDigits: Int)
    init?(value: Double, maxDigits: Int)
    
    • Bundle (now available for the fourth platforms):
    var appName: String
    var appVersion: String
    var appBuild: String
    var schemes: String
    var mainScheme: String
    

    New iOS extensions:

    • UIStoryboard:
    static var main: UIStoryboard
    
    • UISwitch:
    func toggle(animated: Bool = true)
    
    • UIImage:
    var original: UIImage
    var template: UIImage
    
    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Sep 11, 2016)

    API breaking changes

    • Color extension initializer has been updated:
    convenience init?(hexString: String)
    convenience init?(hexString: String, alpha: Float)
    

    becomes

    convenience init(hex: String)
    convenience init(hex: String, alpha: Float)
    

    Enhancements

    Note: Take a look into the README to see the details of all the following enhancements

    New protocols available:

    • Then
    • NSBundle is now available for macOS

    New extensions:

    • Color:
    func darker(amount: CGFloat = 0.25) -> SwiftyColor
    func lighter(amount: CGFloat = 0.25) -> SwiftyColor
    
    • UIImage:
    func filled(with color: UIColor?) -> UIImage
    
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(May 19, 2016)

    API breaking changes

    • Creating an UIImage from UIColor is now more swifty: UIImage(color: .orangeColor()) instead of UIImage.imageWithTintColor(.orangeColor())

    Enhancements

    Note: Take a look into the README to see the details of all the following enhancements

    New extensions:

    • NSNotificationCenter:
    func postNotification(name name: String, object: AnyObject? = nil, userInfo: [NSObject : AnyObject]? = nil, queue: dispatch_queue_t)
    

    New iOS extensions:

    • UIAlertController:
    static func show(title title: String, message: String, cancelTitle: String = "OK")
    
    • UIApplication:
    func topViewController() -> UIViewController?
    
    • UIDevice
    func forceRotation(orientation: UIInterfaceOrientation)
    
    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(May 9, 2016)

    Enhancements

    Note: Take a look into the README to see the details of all the following enhancements

    New extensions:

    • CollectionType:
    func shuffle()
    
    • MutableCollectionType:
    func shuffleInPlace()
    
    • NSLayoutConstraint:
    func applyMultiplier(multiplier: CGFloat, toView: SwiftyView)
    
    • NSURL:
    func addSkipBackupAttribute()
    
    • NSRange:
    init(rangeOf textToFind: String, in text: String)
    

    New iOS extensions:

    • UIViewController:
    func deletePreviousViewControllers()
    func setupBackButton(hidden hidden: Bool = false, title: String = "", backIndicatorImage: UIImage? = nil, tintColor: UIColor? = UIColor.whiteColor())
    func setupRightBarView(view: UIView)
    func setupLeftBarView(view: UIView)
    
    Source code(tar.gz)
    Source code(zip)
  • 0.1.0(Apr 24, 2016)

Owner
Tom Baranes
👋
Tom Baranes
swift-highlight a pure-Swift data structure library designed for server applications that need to store a lot of styled text

swift-highlight is a pure-Swift data structure library designed for server applications that need to store a lot of styled text. The Highlight module is memory-efficient and uses slab allocations and small-string optimizations to pack large amounts of styled text into a small amount of memory, while still supporting efficient traversal through the Sequence protocol.

kelvin 4 Aug 14, 2022
Repository for all the programs and Code I would write in Swift.

Swift Programming Language This repository contains the program and codes I write in Swift About Swift Swift is a general-purpose, multi-paradigm, com

Kannan Jayachandran 2 Sep 21, 2022
⏲ A tiny package to measure code execution time. Only 20 lines of code.

Measure ⏲ A tiny package to measure code execution time. Measure.start("create-user") let user = User() Measure.finish("create-user") Console // ⏲ Mea

Mezhevikin Alexey 3 Oct 1, 2022
It makes a preview from an URL, grabbing all the information such as title, relevant texts and images.

Link Previewer for iOS, macOS, watchOS and tvOS It makes a preview from an URL, grabbing all the information such as title, relevant texts and images.

Leonardo Cardoso 1.3k Jan 2, 2023
Returns true for all possible feature flags within the Twitter Mac app!

twitterinject Returns true for all possible feature flags within the Twitter Mac app! On Apple platforms, the default feature flags are present within

Spotlight 9 May 4, 2022
Generate Markdown documentation from source code

SourceDocs SourceDocs is a command line tool that generates markdown documentation files from inline source code comments. Similar to Sphinx or Jazzy,

Eneko Alonso 349 Dec 10, 2022
Swift code to programmatically execute local or hosted JXA payloads without using the on-disk osascript binary

Swift code to programmatically execute local or hosted JXA payloads without using the on-disk osascript binary. This is helpful when you have Terminal access to a macOS host and want to launch a JXA .js payload without using on-disk osascript commands.

Cedric Owens 20 Sep 27, 2022
Useful Swift code samples, extensions, functionalities and scripts to cherry-pick and use in your projects

SwiftyPick ?? ?? Useful Swift code samples, extensions, functionalities and scripts to cherry-pick and use in your projects. Purpose The idea behind t

Manu Herrera 19 May 12, 2022
SnippetsLibrary - Code snippets library for SwiftUI Devs.

SnippetsLibrary is a helpful tool for SwiftUI developers to help with their daily coding life. SnippetsLibrary contains all the needed code snippets for you to view, edit, or add more and more. This will make your daily work easier and faster.

Christopher Lowiec 41 Jan 2, 2023
GenStore is a lightweight swift code generator for your resources.

GenStore is a lightweight swift code generator for your resources. GenStore can create classes for your images, colors and localized strings.

null 11 Oct 23, 2021
Useful extensions for my Swift code

UIViewController extensions presentAlert(withTitle title: String, message : String) presentAlertDialog(withTitle title: String, message : String, acti

Bogdan Grafonsky 1 Oct 17, 2021
qr code generator tool

qr code generator tool Small command line tool for generate and reconition qr codes written in Swift Using Usage: ./qrgen [options] -m, --mode:

Igor 3 Jul 15, 2022
LibAuthentication will simplify your code when if you want to use FaceID/TouchID in your tweaks.

LibAuthentication will simplify your code when if you want to use FaceID/TouchID in your tweaks.

Maximehip 6 Oct 3, 2022
A declarative, thread safe, and reentrant way to define code that should only execute at most once over the lifetime of an object.

SwiftRunOnce SwiftRunOnce allows a developer to mark a block of logic as "one-time" code – code that will execute at most once over the lifetime of an

Thumbtack 8 Aug 17, 2022
Simple utility for only executing code every so often.

Rate Limit Simple utility for only executing code every so often. This will only execute the block passed for a given name if the last time it was cal

Sam Soffes 921 Nov 20, 2022
An eject button for Interface Builder to generate swift code

Eject Eject is a utility to transition from Interface Builder to programatic view layout. This is done by using code generation to create a .swift fil

Rightpoint 524 Dec 29, 2022
EmbeddedStringsKit: Representation localized string in code

EmbeddedStringsKit Representation localized string in code Usage public struct L

Muukii 1 Jul 13, 2022
Async+ for Swift provides a simple chainable interface for your async and throwing code, similar to promises and futures

Async+ for Swift provides a simple chainable interface for your async and throwing code, similar to promises and futures. Have the best of both worlds

async_plus 132 Jan 6, 2023
iOS helper library that contains commonly used code in Uptech iOS projects

iOS helper library that contains commonly used code in Uptech iOS projects.

Uptech 1 Apr 1, 2022