Modify your native iOS app in real time.

Related tags

Tools Traits
Overview

Traits - Modify your native iOS app properties in real time.

CircleCI codecov Version License Platform

What are Traits?

Traits allows you to modify the design and behavior of native iOS apps without having to restart them, even across the globe.

Wouldn't it be great if we could adjust designs of our native apps without having to sit back to Xcode, change code, recompile and navigate back to the screen we were at?

Traits is a library that provides you the ability to change many properties of your apps (not only design) without having to recompile the application, even via network across the globe.

Using it offers many benefits:

  • Immediate feedback
  • Ability to update running applications remotely
  • Requires almost no code changes in your app
  • Both Code and Interface Builder designs are supported
  • Can tweak more than just UI
  • Fully tested
  • Supports code injection and real-time programming

Gif

Article describing design and implementation details of this tool

Usage

1. Add the library into your project

2. Assign proper view identifiers either via code:

view.traitSpec = "article.containerView"

or via interface builder:

IBInspectable demo

3. [Optional] If you want live-reloading:

While running on simulator you can observe file on your desktop:

TraitsProvider.setupDesktopDaemon()

While running on device, you can observe remote URL:

TraitsProvider.setupRemoteDaemon(url: myFileURL)

Extending

Traits supports extending the library in real-time, without even having to recompile your project and without unsigning your Xcode 8.

Just install Injection app and code away:
Gif

Adding new Trait that is specific to your project is really simple:

  1. Create a new subclass of Trait
  2. Declares the target types that are supported.
  3. Provide apply function that returns a reversal closure
  4. Declare data mapping using ObjectMapper
  5. Compile. (or code inject as we support that as well)
final public class Constraint: Trait {
    private(set) var constant: CGFloat?

    open override class var restrictedTypes: [AnyClass]? { return [NSLayoutConstraint.self] }

    open override func apply(to target: Trait.Target, remove: inout RemoveClosure) throws {
        let target = target as! NSLayoutConstraint

        remove = { [weak target, constant = target.constant] in
            guard let target = target else { return }
            target.constant = constant
        }

        if let constant = constant {
            target.constant = constant
        }
    }

    public init(constant: CGFloat) {
        super.init()
        self.constant = constant
    }

    public required init?(map: Map) {
        super.init(map: map)
    }

    open override func mapping(map: Map) {
        super.mapping(map: map)
        constant <- map["constant"]
    }
}

Requirements

This library requires a deployment target of iOS 8.0 or greater.

Installation

Traits is available through CocoaPods.

To install it, simply add the following line to your Podfile:

pod "Traits"

Origin

Created by Krzysztof Zabłocki (twitter | website) during Maker Week at The New York Times

Article describing design and implementation details of this tool

Contributing

Contributions to Traits are welcomed and encouraged! Please see the Contributing guide.

A list of contributors is available through GitHub.

To give clarity of what is expected of our members, we adopted the code of conduct defined by the Contributor Covenant. This document is used across many open source communities, and we think it articulates my values well. For more, see the Code of Conduct.

License

Traits is available under the MIT license. See LICENSE for more information.

Attributions

This tool is powered by

Thank you goes to:

  • Véronique Brossier and Chrys Wu from NYT because they helped me clarify expectations for this library.

Other Libraries / Tools

Make sure to check my other libraries and tools, especially:

  • Sourcery - Tool that introduces type-safe meta-programming for swift, allowing you to avoid boilerplate code.
  • KZPlayground - Powerful playgrounds for Swift and Objective-C.
  • KZFileWatchers - Daemon for observing local and remote file changes, used for building other developer tools (Traits uses it)

You can follow me on twitter for news/updates about other projects I am creating.

Comments
  • Can we make it work with UIAppearance?

    Can we make it work with UIAppearance?

    AFAIK, UIAppearance uses proxy objects, so we can't just set trait specs for them.

    Here is what I had to do to make it work with UIAppearance.

    1. Disable restrictedTypes check (can't add private _UIAppearance type to the list)
    2. Use unsafeBitCast instead of force cast on target objects (force cast traps while trying to cast _UIAppearance to something else)
    3. Re-add root UIViews for all UIWindows after traits are reloaded (so that the changes in UIAppearance take effect). Maybe there is a better way to accomplish it.

    The first two hacks are very dirty, but we could try to wrap them in an abstration. We could introduce something like 'TypeCastingStrategy' and use different implementations for normal objects and UIAppearance proxies.

    The hack with re-adding UIViews seems simple and working, but there could be some downsides I'm not aware of.

    What do you think about this? Is support of UIAppearance worth hacking? I could try to make a prototype :)

    opened by antonselyanin 4
  • If i have to define a TraitIdentifierEntry for each property of each object?

    If i have to define a TraitIdentifierEntry for each property of each object?

    Hi,

    if i have to define a TraitIdentifierEntry for each property of each object, just like follow:

    private var entry: TraitIdentifierEntry {
        switch self {
        case .containerView:
            return TraitIdentifierEntry("containerView", classes: [UIView.self])
        case .backgroundView:
            return TraitIdentifierEntry("backgroundView", classes: [UIView.self])
        case .titleLabel:
            return TraitIdentifierEntry("titleLabel", classes: [UILabel.self])
        case .childView:
            return TraitIdentifierEntry("childView", classes: [UIView.self])
        case .childViewWidth:
            return TraitIdentifierEntry("childView.width", classes: [NSLayoutConstraint.self])
        case .childViewHeight:
            return TraitIdentifierEntry("childView.height", classes: [NSLayoutConstraint.self])
        case .titleLabelLeading:
            return TraitIdentifierEntry("titleLabel.leading", classes: [NSLayoutConstraint.self])
        case .titleLabelTop:
            return TraitIdentifierEntry("titleLabel.top", classes: [NSLayoutConstraint.self])
        }
    }
    
    opened by southpeak 1
  • [WIP] proof of concept for TraitModifiable generics

    [WIP] proof of concept for TraitModifiable generics

    Issue #7

    Work in progress, this is just a 'proof of concept' for the idea (all tests are passing, live reloading works).

    One question before I can move forward :).

    Do you want to keep the original type checking method (list of restricted classes) or we can substitute it with generics? TypedTrait is a temporary thing.

    opened by antonselyanin 5
  • Expressing trait type restrictions via protocol?

    Expressing trait type restrictions via protocol?

    As I understand, if I want Font trait to support UITextView I have to modify Font source code: add UITextView.self to restrictedTypes array and modify apply method.

    IMO, if target type restrictions were expressed via a protocol, it would be easier to add new target classes to existing traits.

    opened by antonselyanin 4
  • Carthage support

    Carthage support

    opened by TofPlay 0
Releases(0.1.0)
Owner
Krzysztof Zabłocki
Making Swift engineers more efficient through tools and workflows.  My code powers up over 70 000+ apps.
Krzysztof Zabłocki
Build native iOS, Android, and Web apps with Capacitor and Remix.run 💿

This repository holds production ready Capacitor templates for building native mobile applications using Remix. Using Capacitor, you can quickly build out a native mobile application for iOS and Android using web technology, such as Remix.

Ionic 70 Dec 30, 2022
All new design. Inspect your iOS application at runtime.

Peek: All new design Peek 5 with an all new design and all new features. Whether you're a developer, designer or QA/tester, Peek can help you at all s

Shaps 2.6k Dec 17, 2022
SwiftGen is a tool to automatically generate Swift code for resources of your projects

SwiftGen SwiftGen is a tool to automatically generate Swift code for resources of your projects (like images, localised strings, etc), to make them ty

null 8.3k Jan 5, 2023
An Xcode plug-in to format your code using SwiftLint.

SwiftLintXcode An Xcode plug-in to format your code using SwiftLint. Runs swiftlint autocorrect --path CURRENT_FILE before *.swift file is saved. IMPO

Yuya Tanaka 348 Sep 18, 2022
AVXCAssets Generator takes path for your assets images and creates appiconset and imageset for you in just one click

AVXCAssets Generator Often while developing an app, We ran into a condition when we need to scale images to each and every aspect ratios for icons and

Angel Vasa 339 Dec 6, 2022
An iOS app decrypter, full static using fouldecrypt.

Iridium An iOS app decrypter, full static using fouldecrypt. Supporting iOS 13+ Note We have built everything into the package, you can install and fl

Lakr Aream 234 Jan 9, 2023
An iOS app decrypter, full static using fouldecrypt.

Iridium An iOS app decrypter, full static using fouldecrypt. Supporting iOS 13+ Note We have built everything into the package, you can install and fl

Lakr Aream 226 Dec 24, 2022
Automatically build and rebuild Xcode image catalogs for app icons, universal images, and more

Better asset workflow for iOS developers. Generate Xcode image catalogs for iOS / OSX app icons, universal images, and more.

Dotan J. Nahum 822 Dec 21, 2022
Command line program that detects unused resource strings in an iOS or OS X application.

Abandoned Resource String Detection This command line program detects unused resource strings in an iOS or OS X application. Updated to Swift 3, thank

Josh Smith 360 Nov 26, 2022
A fast, convenient and nonintrusive conversion framework between JSON and model. Your model class doesn't need to extend any base class. You don't need to modify any model file.

MJExtension A fast, convenient and nonintrusive conversion framework between JSON and model. 转换速度快、使用简单方便的字典转模型框架 ?? ✍??Release Notes: more details Co

M了个J 8.5k Jan 3, 2023
ZIP Foundation is a library to create, read and modify ZIP archive files.

ZIP Foundation is a library to create, read and modify ZIP archive files. It is written in Swift and based on Apple's libcompression for high performa

Thomas Zoechling 1.9k Dec 27, 2022
Swift Package used for video where I demonstrate how to extract a package to a local framework and modify it.

SegmentedPicker NOTE: This sample code is taken from the article by Frank Jia in his article titled Build a Custom iOS Segmented Control With SwiftUI

Stewart Lynch 1 Oct 11, 2021
modify IQKeyboardManager

IQKeyboardManager Often while developing an app, We ran into an issues where the iPhone keyboard slide up and cover the UITextField/UITextView. IQKeyb

WL 0 Nov 5, 2021
Workaround to hide/modify List separators in SwiftUI iOS13 and iOS14

Help support my open source work! iOS15 List finally supports setting list row separator color and style as of iOS15! They still don't support list in

Michael Schmidt 135 Dec 7, 2022
ActionCable is a new WebSockets server being released with Rails 5 which makes it easy to add real-time features to your app

ActionCable is a new WebSockets server being released with Rails 5 which makes it easy to add real-time features to your app. This S

Daniel Rhodes 160 Mar 13, 2022
iOS - Real-time messaging app 🎨

General mChat is a real-time messaging app written in Swift for iOS devices. Since mChat uses a fast and reliable Firebase Database, it receives data

Vitaliy Paliy 569 Nov 28, 2022
iOS - Real-time messaging app 🎨

General mChat is a real-time messaging app written in Swift for iOS devices. Since mChat uses a fast and reliable Firebase Database, it receives data

Vitaliy Paliy 569 Nov 28, 2022
MuVis is a macOS, iOS, iPadOS app for real-time music visualization.

MuVis MuVis is an open-source multiplatform app (using SwiftUI, Swift, and Xcode) for music visualization. It renders informative (and musically usefu

Keith Bromley 7 Oct 10, 2022
iOS app that shows real-time information about subway train arrivals in Seoul, South Korea.

NextTrain iOS app that shows real-time information about subway train arrivals in Seoul, South Korea. The app was implemented using clean code and TDD

null 4 Nov 18, 2021
Cardshark is an iOS card counting App that uses state of the art machine learning (YOLO) to classify and count the cards at real time.

Cardshark The game of Blackjack is one of the most popular casino games in the world. It is also the most winnable using a skill called Card Counting.

Eric Miao 1 Jan 23, 2022