What's New



Initial release


CI Status GitHub tag (latest SemVer) License

DebugKit is designed to make it as simple as possible to build and display useful information about your project. It was built to replace all the individual debugging view controllers, making it easy to use the functionality that is needed in your specific use case, without the need to write it yourself. The framework includes a simple way to build a DebugOptionsViewController (or DebugOptionsView in SwiftUI), containing a variety of debugging related information.

In addition to easy access to basic debugging information and functionality, DebugKit also provides functionality to log incoming items for later viewing. Out of the box, DebugKit is capable of logging MXMetricPayload (and so has a MetricKit dependency) and UNNotification (and so has a UserNotifications dependency). More information about logging custom types can be found below, or in Conforming to Recordable.

To utilize DebugOptionsViewController, the first step is instantiation:

let viewController = DebugOptionsViewController()

This is the simplest way to create a new view controller, but there are a multitude of appearance customization options available as part of the initializer. The view controller is currently created on its own, without a UINavigationController, so if the contents of your debug options will require navigation it must be nested in a UINavigationController or NavigationView.

Once you have the view controller, the only remaining step is populating it with the data you wish to see - this can be accomplished with a single call to configure.

viewController.configure(with: [.init(section: .init(title: "General"),
                                        items: [.version(for: .main), .build(for: .main), .pushToken(with: pushService.deviceToken, title: "Push Token")]),
                                .init(section: .init(title: "Debug"),
                                        items: [.crashTest()]),
                                .init(section: .init(title: "Logs"),
                                        items: [.log(for: "Metrics", logService: metricsLogService), .log(for: "Notifications", logService: notificationsLogService)]))

There are a variety of built in DebugOption presets, including displaying a build / version number, as well as a device APNs token. For custom actions, it is very easy to extend DebugOption. There are three types of DebugOption - action, selection and presentation.

  • Action: Selection of this item invokes some kind of action determined by a handler
  • Selection: Selection of this item updates the selected state of the menu, useful for things like an environment picker
  • Presentation: Selection of this item causes either a navigation push or modal presentation to a given view controller

To implement the crashTest() item above, for example, would involve the following:

extension DebugOption.Item {

    public static func crashTest() -> Self {
        return .action(title: "Crash") { fatalError("Testing a crash!") }


In addition to simple action and selection items, the DebugItem is designed to work seamlessly with another capability of DebugKit - the LogService. This service is designed to record instances of any object, writing them to disk and displaying them in the DebugViewController on demand.

The LogService works with any type that conforms to the Recordable protocol (more information here, allowing entries in this log to be visually displayed using SwiftUI. These logs can be in memory only, or optionally written to some persistent storage if desired. The LogService will accept any item conforming to LogStoring upon initialization, and a default LogFileStorage is provided by the framework.

For example, if you wanted to keep a log of the MXMetricPayload the OS delivers to your app over the course of a few days, you could construct a LogService<MXMetricPayload>, using the provided convenience method:

// Create the log service (with optional file storage)
let metricLogService = LogService<MXMetricPayload>.metricPayloads(storedAt: myFileURL)

// then conform to MXMetricManagerSubscriber to append to the log
func didReceive(_ payloads: [MXMetricPayload]) {

By default, the log's entries will persist for 1 week from recording, although this is customizable through the LogService.expirationInterval property. Once the time comes to display this log in a DebugOptionsViewController (or DebugOptionsView), this can be done using another convenience function on DebugOption where it can easily be added to a DebugOptionsViewController:

let option = DebugOption.log<T>(for: "Title", logService: metricLogService)


To run the example project, clone this repo and open DebugKit.xcworkspace.


Requires iOS 14.0. Dependencies include UIKit, SwiftUI, MetricKit, UserNotifications, CryptoKit.


Swift Package Manager

Add this to your project using Swift Package Manager. In Xcode: File > Swift Packages > Add Package Dependency... and you're done. If you are editing Package.swift directly, you can import the package as follows:

.package(url: "", from: "1.0.0"),


Add the following to your Cartfile:

github "BottleRocketStudios/iOS-DebugKit"

Run carthage bootstrap and follow the steps as described in Carthage's README.


Bottle Rocket Studios


DebugKit is available under the Apache 2.0 license. See the LICENSE file for more information.


See the CONTRIBUTING document. Thank you, contributors!


  • Swift Tools 5.5.0
View More Packages from this Author


  • None
Last updated: Sun Nov 20 2022 16:46:17 GMT-0500 (GMT-05:00)