Perform - Easy dependency injection for storyboard segues

Overview

Perform

Easy dependency injection for storyboard segues.

import Perform

// ...

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: NSIndexPath) {
  let task = taskList[indexPath.row]
  perform(.showTaskDetails) { taskVC in
    taskVC.task = task
  }
}

Usage

Configure your segues:

// Sources/Extensions/Segue.swift
import Perform

extension Segue {
  static var showTaskDetails: Segue<TaskDetailsViewController> {
    return .init(identifier: "ShowTaskDetails")
  }
}

And then use perform(_:prepare:) instead of performSegue(withIdentifier:sender:). That's it!

Type-safe segues

Perform checks the type of the destination view controller and casts it for you, raising an error if your destination view controller is an unexpected type.

Still works if your view controller is embedded in a container

Ever written code like this?

guard let nav = segue.destinationViewController as? UINavigationController,
  let content = nav.rootViewController as? MyViewController
  else { return }

// ... finally! 😭

Perform takes care of this, searching the view controller hierarchy for a view controller of the matching type!

No switch statements in prepareForSegue(_:sender:)

Multiple segues from one view controller? No problem, just prepare each destination view controller right where you perform the segue. No more massive switch statements.

Further reading

For more examples, and a discussion about the motivation and design of Perform, take a look at the introductory blog post.

Installation

Compatibility

Swift Version Perform Version
3.x 2.x
2.x 1.x

Carthage

Add the following to your Cartfile:

github "thoughtbot/Perform" ~> 2.0

Then run carthage update Perform.

Follow the instructions in Carthage's README for up-to-date installation instructions.

CocoaPods

Add the following to your Podfile:

pod "Perform", "~> 2.0"

See the CocoaPods guide for up-to-date installation instructions.

Contributing

See the CONTRIBUTING document.

License

Perform is Copyright (c) 2016 thoughtbot, inc. It is free software, and may be redistributed under the terms specified in the LICENSE file.

About

thoughtbot

Perform is maintained and funded by thoughtbot, inc. The names and logos for thoughtbot are trademarks of thoughtbot, inc.

We love open source software! See our other projects or hire us to help build your product.

Comments
  • Hook prepareForSegue with Aspects instead of RAC

    Hook prepareForSegue with Aspects instead of RAC

    Fixes #3.

    Aspects is a significantly thinner library than RAC, yet still provides the feature we're interested in: a block-based callback for a message-send. This even simplifies the implementation by discarding the extra power (and thus complexity) that RAC provides.

    opened by sharplet 3
  • Cannot convert value of type '(_) -> ()' to expected argument type 'Any!'

    Cannot convert value of type '(_) -> ()' to expected argument type 'Any!'

    When I try to use the class I get the following error:

    Cannot convert value of type '(_) -> ()' to expected argument type 'Any!'

    I'm not sure it can be the cause but I'm using Swift 4.

    My code is as follows: perform(.embedPromotions) { promotionsVC in promotionsPageController = promotionsVC promotionsPageController.promotionsData = promotionsData }

    Any help will be greatly appreciated.

    opened by VladimirSpasov 2
  • Disable App Extension API

    Disable App Extension API

    It'd be nice to be able to do this (and our code does only use the app extension API), but since we're linking in Aspects (which doesn't only use the app extension API), we actually can't make that guarantee. We should disable it to avoid the resulting warnings as well as any confusion that we might run into.

    opened by gfontenot 2
  • Update to Swift 4.2

    Update to Swift 4.2

    Upgrades the pod from using Swift 4 to Swift 4.2, avoiding having to do compatibility checks in the Podfile of a project built in Xcode 10.1 (specifying the version of Swift needed to build the target, such as https://github.com/CocoaPods/CocoaPods/issues/6791).

    opened by patrickmontalto 1
  • Migrate to Swift 3

    Migrate to Swift 3

    After this is merged to master, the plan is to tag 2.0.0. Going forward, future development will likely be for Swift 3 unless there's a compelling reason to backport the change to Swift 2.

    opened by sharplet 1
  • Don't use private API in Release builds

    Don't use private API in Release builds

    The use of _printHierarchy is purely for debugging purposes, and should be excluded from release builds where it could cause app rejections.

    Unfortunately this means that anyone using prebuilt Carthage binaries probably will never see the debug version of the message.

    opened by sharplet 1
  • Add UITabBarController.configureViewControllers

    Add UITabBarController.configureViewControllers

    Fixes #6.

    Simplifies passing dependencies to tabs within a tab bar controller by searching within each tab's view controller hierarchy for a matching view controller to configure.

    opened by sharplet 1
  • Searching for a view controller of the matching type is useful outside of segues

    Searching for a view controller of the matching type is useful outside of segues

    It would be nice to expose the functionality of UIStoryboardSegue.destinationViewController(ofType:) in a more general way that is useful in different contexts.

    For example, lets say you wanted to configure the tabs in a UITabBarController:

    final class MyTabBarController: UITabBarController {
      override func viewDidLoad() {
        super.viewDidLoad()
    
        nextTab: for tab in viewControllers {
          for child in tab.hierarchy {
            switch child {
            case let feed as FeedViewController:
              // configure feed
              continue nextTab
            case let profile as ProfileViewController:
              // configure profile
              continue nextTab
            }
          } 
        }
      }
    }
    

    For each tab, this code searches the view controller hierarchy until it finds a matching view controller, then continues to the next tab.

    This would be more concise:

    for tab in viewControllers {
      if let feed = tab.childViewController(ofType: FeedViewController.self) {
        // configure feed
      }
    
      if let profile = tab.childViewController(ofType: ProfileViewController) {
        // configure profile
      }
    }
    

    But has the disadvantage of searching each tab N times, where N is the number of different things you need to configure.

    I think there should be a way to encapsulate the first search strategy using a higher-level construct.

    opened by sharplet 1
  • Add method to perform and prepare for segue in one

    Add method to perform and prepare for segue in one

    I decided to try and test drive this, which worked pretty well, as it uncovered a weird Swift type checker behaviour (that is quite possibly a bug).

    See commit log for more info.

    opened by sharplet 1
  • Update to circle ci 2.0

    Update to circle ci 2.0

    Why

    • Old Xcode version used on Circle was causing tests to fail.
    • Circleci 1.0 is going away on March 15 (~a week from today)

    How

    • Specify Xcode 10.1.0 and use circle 2.0
    opened by patrickmontalto 0
  • Remove dependency on ReactiveCocoa

    Remove dependency on ReactiveCocoa

    We currently use RAC to dynamically implement prepareForSegue(_:sender:), but it's not exposed via the public API. It really simplifies this library, but it would be nice to investigate removing that dependency before 1.0.

    opened by sharplet 0
  • Manual Installation

    Manual Installation

    CocoaPods and Carthage are awesome tools and make our life really easier, but there are some devs who still don't know how to use them.

    It would be cool to add the Manual installation guide in your README.md. You can take a look at my iOS Readme Template to see how you can do it.

    opened by lfarah 2
  • Document configureViewControllers

    Document configureViewControllers

    This is a pretty useful method for doing DI with UITabBarController, but there's currently no documentation for it other than the documentation comment.

    help wanted 
    opened by sharplet 0
Releases(2.0.2)
  • 2.0.2(Mar 7, 2019)

  • 2.0.1(Jun 27, 2018)

  • 2.0.0(Apr 6, 2017)

    • Swift 3 support (including Swift 3.1)
    • Disable App Extension API (https://github.com/thoughtbot/Perform/pull/15, thanks @gfontenot!)
    • Audit Aspects version compatibility
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Sep 12, 2016)

    This is the first public release of Perform.

    • Use the perform(_:prepare:) method to configure a segue's destination view controller right where it's triggered. No more massive prepareForSegue method.
    • Define your destination view controller's type statically using the Segue<Destination>. Perform automatically casts the destination view controller for you before calling your prepare function.
    • If the destination view controller is a container (e.g., UINavigationController), Perform searches the view controller hierarchy and locates a child view controller with the matching type.
    • Share dependencies between tabs in a UITabBarController by using the configureViewControllers extension.
    Source code(tar.gz)
    Source code(zip)
Owner
thoughtbot, inc.
We work with organizations of all sizes to design, develop, and grow their web and mobile products.
thoughtbot, inc.
Injection - Dependency injection using property wrappers

Dependency injection using property wrappers. Registering types: // injecting a

Alejandro Ramirez 3 Mar 14, 2022
Inject-Dylib - ObjC Code to Programmatically Perform Dylib Injection

Inject-Dylib ObjC Code to Programmatically Perform Dylib Injection. Code leveraged from Wojciech Regula's FirefoxStealer project (https://github.com/r

Cedric Owens 1 Jan 2, 2022
Inject Dylib - Swift code to programmatically perform dylib injection

Inject_Dylib Swift code to programmatically perform dylib injection. You can als

Cedric Owens 40 Sep 27, 2022
Deli is an easy-to-use Dependency Injection Container that creates DI containers

Deli is an easy-to-use Dependency Injection Container that creates DI containers with all required registrations and corresponding factories.

Jungwon An 134 Aug 10, 2022
Kraken - Simple Dependency Injection container for Swift. Use protocols to resolve dependencies with easy-to-use syntax!

Kraken Photo courtesy of www.krakenstudios.blogspot.com Introduction Kraken is a simple Dependency Injection Container. It's aimed to be as simple as

Syed Sabir Salman-Al-Musawi 1 Oct 9, 2020
Cleanse is a dependency injection framework for Swift.

Cleanse - Swift Dependency Injection Cleanse is a dependency injection framework for Swift. It is designed from the ground-up with developer experienc

Square 1.7k Dec 16, 2022
Corridor A Coreader-like Dependency Injection μFramework

Corridor A Coreader-like Dependency Injection μFramework Table of Contents Why | Examples | Usage | Installation | Credits & License | Why In order to

symentis GmbH 60 Nov 1, 2022
DIKit Dependency Injection Framework for Swift, inspired by KOIN.

DIKit Dependency Injection Framework for Swift, inspired by KOIN. Basically an implementation of service-locator pattern, living within the applicatio

null 95 Dec 22, 2022
Dip is a simple Dependency Injection Container.

Dip is a simple Dependency Injection Container. It's aimed to be as simple as possible yet p

Olivier Halligon 949 Jan 3, 2023
Tranquillity is a lightweight but powerful dependency injection library for swift.

DITranquillity Tranquillity is a lightweight but powerful dependency injection library for swift. The name "Tranquillity" laid the foundation in the b

Ivlev Alexander 393 Dec 24, 2022
Swinject is a lightweight dependency injection framework for Swift.

Swinject Swinject is a lightweight dependency injection framework for Swift. Dependency injection (DI) is a software design pattern that implements In

null 5.6k Dec 31, 2022
Typhoon Powerful dependency injection for Cocoa and CocoaTouch.

Typhoon Powerful dependency injection for Cocoa and CocoaTouch. Lightweight, yet full-featured and super-easy to use. Pilgrim is a pure Swift successo

AppsQuick.ly 2.7k Dec 14, 2022
Dependency Injection framework for Swift (iOS/macOS/Linux)

Declarative, easy-to-use and safe Dependency Injection framework for Swift (iOS/macOS/Linux) Features Dependency declaration via property wrappers or

Scribd 684 Dec 12, 2022
Swift Ultralight Dependency Injection / Service Locator framework

Swift Ultralight Dependency Injection / Service Locator framework

Michael Long 1.9k Jan 6, 2023
DIContainer Swift is an ultra-light dependency injection container made to help developers to handle dependencies easily. It works with Swift 5.1 or above.

?? DIContainer Swift It is an ultra-light dependency injection container made to help developers to handle dependencies easily. We know that handle wi

Victor Carvalho Tavernari 10 Nov 23, 2022
A simple way to handle dependency injection using property wrappers

Injektion Introduction A simple way to handle dependency injection using propert

Andrew McGee 2 May 31, 2022
Reliant - Nonintrusive Objective-C Dependency Injection

Reliant Reliant is a Dependency Injection (DI) framework for Objective-C, both for OS X and iOS. Its goal is to make its use as simple as possible, wh

AppFoundry 52 Oct 14, 2022
Pilgrim - Dependency injection for Swift (iOS, OSX, Linux). Strongly typed, pure Swift successor to Typhoon.

pilgrim.ph Pilgrim is a dependency injection library for Swift with the following features: Minimal runtime-only library that works with pure Swift (s

AppsQuick.ly 60 Oct 24, 2022
ViperServices - Simple dependency injection container for services written for iOS in swift supporting boot order

ViperServices Introduction ViperServices is dependency injection container for iOS applications written in Swift. It is more lightweight and simple in

Siarhei Ladzeika 5 Dec 8, 2022