Swiftpack.co - Package - icapps/ios-stella

CI Status License Platform Language Swift 4.0

Stella contains a set of utilities that can be used during iOS development in Swift.


Installation 💾

Swift Package Manager

You can install Stella using the Swift Package Manager. This is available starting from Xcode 11. Just search for icapps/ios-stella and install it.


Stella is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'Stella', git: 'https://github.com/icapps/ios-stella.git', commit: '...'

Pass the correct commit reference to make sure your code doesn't break in future updates.


To integrate Stella into your Xcode project using Carthage, specify it in your Cartfile"

github "icapps/ios-stella" ~> 1.5.1

Then, run the following command to build the Stella framework:

carthage update

Perform the additional steps in orde the get Carthage setup with this framework: Carthage's README



We have a cleaner way to use NSUserDefaults. Define the user defaults by extending the DefaultsKeys class.

extension DefaultsKeys {
  // Writes a string object to the defaults with the 'stringValue' key.
  static let stringValue = DefaultsKey<String?>("stringValue")
  // Writes an integer to the defaults with the 'integerValue' key.
  static let integerValue = DefaultsKey<Int?>("integerValue")
  // Writes a double to the defaults with the 'doubleValue' key.
  static let doubleValue = DefaultsKey<Double?>("doubleValue")
  // Writes a float to the defaults with the 'floatValue' key.
  static let floatValue = DefaultsKey<Float?>("floatValue")
  // Writes a bool to the defaults with the 'booleanValue' key.
  static let booleanValue = DefaultsKey<Bool?>("booleanValue")
  // Writes a date object to the defaults with the 'dateValue' key.
  static let dateValue = DefaultsKey<NSDate?>("dateValue")

You can read/write the from/to the NSUserDefaults by using the subscript on the Defaults class.

Defaults[.stringValue] = "A string value"
print(Defaults[.stringValue]) // Prints 'A string value'

Defaults[.integerValue] = 123
print(Defaults[.integerValue]) // Prints '123'

Defaults[.doubleValue] = 123.123
print(Defaults[.doubleValue]) // Prints '123.123'

Defaults[.floatValue] = 123.321
print(Defaults[.floatValue]) // Prints '123.312'

Defaults[.booleanValue] = true
print(Defaults[.booleanValue]) // Prints 'true'

Defaults[.dateValue] = NSDate()
print(Defaults[.dateValue]) // Prints '1996-12-19T16:39:57-08:00'


We have a cleaner way to use the Keychain. Define the user defaults by extending the Keys class.

extension Keys {
  // Writes a string object to the keychain with the 'stringValue' key.
  static let stringValue = Key<String?>("stringValue")

You can read/write the from/to the Keychain by using the subscript on the Keychain class.

Keychain[.stringValue] = "A string value"
print(Keychain[.stringValue]) // Prints 'A string value'

In some cases you want to be able to set additional keychain query paramaters on an item.

static let noBackupValue = Key<String?>("noBackup", {
  return [kSecAttrAccessible as String: kSecAttrAccessibleAlwaysThisDeviceOnly]


Localize a key in no time with this handy localization function.

let key = "this_is_your_localization_key"
// The debug console will print the localized
// string found in your .strings file.



Fetch an element from an array that could possible be out of bounds.

let array = [1, 2, 3, 4]
array[safe: 2] // Returns 3
arra[safe: 10] // Returns nil

Returns the array with a limited subset starting from the front/rear.

let array = [1, 2, 3, 4]
array.truncate(by: 2) // Returns [1, 2]
array.reverseTruncate(by: 2) // Returns [3, 4]

Returns if an element is found in an array.

let array = [1, 2, 3, 4]
array.contains(2) // Returns true
array.contains(10) // Returns false

Returns an array with unique values depending on the Hashable value.

let array = [1, 2, 3, 2, 4, 1]
array.unique // Returns [1, 2, 3, 4]

Remove an element from an array and returns the removed index.

var array = [1, 2, 3, 4]
array.remove(3) // Returns 2
array // Mutated to [1, 2, 4]


Get the marketing and build version quickly from the bundle.

let bundle = Bundle.main
bundle.shortVersionString // Returns 1.2.3
bundle.bundleVersion // Returns 1 (the build version)


Quickly add a shadow around a certain view

let view = UIView()

let customShadowView = UIView()
customShadowView.layer.applyShadow(color: .red, opacity: 0.2, x: 0, y: 4, blur: 10, spread: 0)

Quickly remove a shadow from a certain view

let view = UIView()


Convert from degrees to radians and vice versa.

CGFloat(180).degreesToRadians // Returns .pi
CGFloat.pi.radiansToDegrees // Returns 180.0


Get the UIViewController that manages your view.

let controller = UIViewController()
controller.view.respondingController // Returns the controller instance.


Register and reuse cells in a type safe way.

// Register a cell from a nib with the same name.

// Register a reusable view from a nib with the same name.
collectionView.register(CustomReusableView.self, forSupplementaryViewOfKind: "Some")

// Dequeue a cell of type CustomCollectionViewCell
collectionView.dequeueReusableCell(for: indexPath) as CustomCollectionViewCell

// Dequeue a reusable view of type CustomReusableView
collectionView.dequeueReusableSupplementaryView(ofKind: "Some", for: indexPath) as CustomReusableView


Register and reuse cells in a type safe way.

// Register a cell from a nib with the same name.

// Register a footer view from a nib with the same name.

// Dequeue a cell of type CustomTableViewCell
tableView.dequeueReusableCell(forIndexPath: indexPath) as CustomTableViewCell

// Dequeue a cell of type CustomTableViewCell with a custom identifier.
tableView.dequeueReusableCell(forIdentifier: "identifier") as CustomTableViewCell

// Dequeue a header view of type CustomReusableView with a custom identifier.
tableView.dequeueReusableHeaderFooter(forIdentifier: "identifier") as CustomReusableView

// Dequeue a header view of type CustomReusableView.
tableView.dequeueReusableHeaderFooter(forIdentifier: "identifier") as CustomReusableView

// Get the types cell for row.
tableView.cellForRow(at: indexPath) as CustomTableViewCell


Constraint a subview quickly to the bounds of the superview.

Optionally you can add insets that set some spacing inside the view.

view.constraint(to: superview)
view.constraint(to: superview, insets: .zero)

// Same as above but take safe area's into account.
view.constraint(to: superview, safeAreaInsets: .zero)


Get access to reuse identifiers.

// Return the name of the view's class as it's reuse identifier.

// Return the name of the view's class as it's nib name.

// Return the nib matching the class name of the view.

Load the UIView from a nib with the same name.

It is important to type the destination property in orde to load the correct nib.

let view: SomeView = UIView.loadFromNib()


Easily add and remove a controller as a childViewController.

Optionally you can add insets that set some spacing inside the container view.

// Add the controller to the container view, pin it and handle the containment correctly.
rootController.add(childController: controller, to: containerView)
rootController.add(childController: controller, to: containerView, insets: .zero)

// Add the same child controller as above, but take the safe area's into account.
rootController.add(childController: controller, to: containerView, safeAreaInsets: .zero)

// Remove the controller and handle the containtment correctly.
rootController.remove(childController: controller)


Load the view controller directly from a storyboard.

// Load the initial controller from the storyboard.
let controller = SomeController.from(storyboard: "StoryboardName")

// Pass a custom bundle to load from.
let controller = SomeController.from(storyboard: "StoryboardName", bundle: CustomBundle())

// Load a controller with the given storyboard identifier.
let controller = SomeController.from(storyboard: "StoryboardName", identifier: "SomeControllerIdentifier")


Get the UIViewController that is currently presented on top of the application. It doesn't matter if a UINavigationController or a UITabBarController is in play or not.

let controller = UIAlertController(...)

// Present an alert an top of all the controllers.
otherController.topMostViewController.present(controller, animated: false, completion: nil)


Added soms easy to used optional intializers.

URL(string: nil)
UIImage(data: nil)


How to contribute ❓

  1. Add a Github issue describing the missing functionality or bug.
  2. Implement the changes according to the Swiftlint coding guidelines.
  3. Make sure your changes don't break the current version. (deprecate is needed)
  4. Fully test the added changes.
  5. Send a pull-request.

Contributors 🤙


Stella is available under the MIT license. See the LICENSE file for more info.


Stars: 1
Help us keep the lights on


Used By

Total: 0


1.5.3 - Jun 15, 2019

  • Add Swift 5.0 support
  • Add Swift Package Manager support

1.5.2 - Apr 29, 2019

Added Carthage support.

1.5.1 - Jan 24, 2019

  • Make topMostViewController public

1.5.0 - Jan 24, 2019

  • Add an explicit bundle identifier in the Keychain flow
  • Fix tvOS availability
  • Get the top most view controller

1.4.0 - Nov 30, 2018

  • Radians/degrees functionality.
  • Add some UIViewController / UIView loading utilities.
  • Add array utilities.
  • Shadow and UIStackView utilities.
  • Added some optional init's.
  • Add more constraint helper functions.
  • Upgrade to Swift 4.2.