Strong typed, autocompleted resources like images, fonts and segues in Swift projects

Overview

R.swift Version License Platform

Get strong typed, autocompleted resources like images, fonts and segues in Swift projects

Why use this?

It makes your code that uses resources:

  • Fully typed, less casting and guessing what a method will return
  • Compile time checked, no more incorrect strings that make your app crash at runtime
  • Autocompleted, never have to guess that image name again

Currently you type:

let icon = UIImage(named: "settings-icon")
let font = UIFont(name: "San Francisco", size: 42)
let color = UIColor(named: "indicator highlight")
let viewController = CustomViewController(nibName: "CustomView", bundle: nil)
let string = String(format: NSLocalizedString("welcome.withName", comment: ""), locale: NSLocale.current, "Arthur Dent")

With R.swift it becomes:

let icon = R.image.settingsIcon()
let font = R.font.sanFrancisco(size: 42)
let color = R.color.indicatorHighlight()
let viewController = CustomViewController(nib: R.nib.customView)
let string = R.string.localizable.welcomeWithName("Arthur Dent")

Check out more examples or hear about how Fabric.app uses R.swift!

Demo

Autocompleted images:

Autocompleted images

Compiletime checked images:

Compiletime checked images

This is only the beginning, check out more examples!

CocoaHeadsNL presentation

Mathijs Kadijk presented R.swift at the September 2016 CocoaHeadsNL meetup. Talking about the ideas behind R.swift and demonstrating how to move from plain stringly-typed iOS code to statically typed code.

R.swift presentation at CocoaHeadsNL

Features

After installing R.swift into your project you can use the R-struct to access resources. If the struct is outdated just build and R.swift will correct any missing/changed/added resources.

R.swift currently supports these types of resources:

Runtime validation with R.validate():

  • If all images used in storyboards and nibs are available
  • If all named colors used in storyboards and nibs are available
  • If all view controllers with storyboard identifiers can be loaded
  • If all custom fonts can be loaded

Q&A

Installation

CocoaPods is the recommended way of installation, as this avoids including any binary files into your project.

Note on Carthage: R.swift is a tool used in a build step, it is not a dynamic library. Therefore it is not possible to install it with Carthage.

CocoaPods (recommended)

  1. Add pod 'R.swift' to your Podfile and run pod install
  2. In Xcode: Click on your project in the file list, choose your target under TARGETS, click the Build Phases tab and add a New Run Script Phase by clicking the little plus icon in the top left
  3. Drag the new Run Script phase above the Compile Sources phase and below Check Pods Manifest.lock, expand it and paste the following script:
    "$PODS_ROOT/R.swift/rswift" generate "$SRCROOT/R.generated.swift"
  4. Add $SRCROOT/R.generated.swift to the "Output Files" of the Build Phase
  5. Uncheck "Based on dependency analysis" so that R.swift is run on each build
  6. Build your project, in Finder you will now see a R.generated.swift in the $SRCROOT-folder, drag the R.generated.swift files into your project and uncheck Copy items if needed

Screenshot of the Build Phase can be found here

Tip: Add the *.generated.swift pattern to your .gitignore file to prevent unnecessary conflicts.

Mint

First, Install R.Swift Binary and Run Script Phase

  1. Add mac-cain13/R.swift to your Mintfile and run mint bootstrap to install this package without linking it globally (recommended)
  2. In Xcode: Click on your project in the file list, choose your target under TARGETS, click the Build Phases tab and add a New Run Script Phase by clicking the little plus icon in the top left
  3. Drag the new Run Script phase above the Compile Sources phase, expand it and paste the following script:
    if mint list | grep -q 'R.swift'; then
      mint run R.swift rswift generate "$SRCROOT/R.generated.swift"
    else
      echo "error: R.swift not installed; run 'mint bootstrap' to install"
      return -1
    fi
  4. Add $SRCROOT/R.generated.swift to the "Output Files" of the Build Phase
  5. Uncheck "Based on dependency analysis" so that R.swift is run on each build
  6. Build your project, in Finder you will now see a R.generated.swift in the $SRCROOT-folder, drag the R.generated.swift files into your project and uncheck Copy items if needed

Tip: Add the *.generated.swift pattern to your .gitignore file to prevent unnecessary conflicts.

Second, Install R.Swift.Library via the Swift Package Manager (requires Xcode 11)

If you see a build error No such module 'Rswift' when trying to #import Rswift at the top of the R.generated.swift file, then you will also need to install the library via the Swift Package Manager available in Xcode 11+.

Head over to the R.Swift.Library repo and follow the Swift Package Manager installation instructions.

Homebrew

R.swift is also available through Homebrew. This makes it possible to install R.swift globally on your system. Install R.swift by running: brew install rswift. The Homebrew formula is maintained by @tomasharkema.

Manually

  1. Add the R.swift.Library to your project
  2. Download a R.swift release, unzip it and put it into your source root directory
  3. In Xcode: Click on your project in the file list, choose your target under TARGETS, click the Build Phases tab and add a New Run Script Phase by clicking the little plus icon in the top left
  4. Drag the new Run Script phase above the Compile Sources phase, expand it and paste the following script:
    "$SRCROOT/rswift" generate "$SRCROOT/R.generated.swift"
  5. Add $SRCROOT/R.generated.swift to the "Output Files" of the Build Phase
  6. Uncheck "Based on dependency analysis" so that R.swift is run on each build
  7. Build your project, in Finder you will now see a R.generated.swift in the $SRCROOT-folder, drag the R.generated.swift files into your project and uncheck Copy items if needed

Screenshot of the Build Phase can be found here

Tip: Add the *.generated.swift pattern to your .gitignore file to prevent unnecessary conflicts.

Building from source

R.swift is built using Swift Package Manager (SPM).

  1. Check out the code
  2. Run swift build -c release from the root directory
  3. Follow the manual installation steps with the binary you now have

For developing on R.swift in Xcode, run swift package generate-xcodeproj --xcconfig-overrides RswiftConfig.xcconfig.

Contribute

We'll love contributions, read the contribute docs for info on how to report issues, submit ideas and submit pull requests!

License

R.swift and R.swift.Library are created by Mathijs Kadijk and released under a MIT License.

Special thanks to Tom Lokhorst for his major contributions and help maintaining this project.

Comments
  • Cannot archive project in Xcode 13 - input file 'R.generated.swift' was modified during the build

    Cannot archive project in Xcode 13 - input file 'R.generated.swift' was modified during the build

    Greetings! A project that worked perfectly fine in Xcode 12.5.1 and earlier doesn't archive anymore in Xcode 13 Beta 5. It fails with this error.

    CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler (in target 'Vectornator' from project 'Vectornator')
    <Build command>
    error: input file '/PrivatePath/Other Sources/R.generated.swift' was modified during the build
    error: input file '/PrivatePath/Other Sources/R.generated.swift' was modified during the build
    Command CompileSwiftSources failed with a nonzero exit code
    

    The project is an iOS app with a Catalyst version. iOS builds, runs and archives fine. Catalyst builds and runs fine, but fails to archive. Here's the build phase setup. Bildschirmfoto 2021-09-13 um 18 18 31

    Does anyone have any idea what's going wrong? Bildschirmfoto 2021-09-13 um 18 15 40

    I will retest with Xcode 13 RC tomorrow and update the issue.

    opened by kaiengelhardt 35
  • ⚠️ R.swift and Xcode 10 / Swift 4.2

    ⚠️ R.swift and Xcode 10 / Swift 4.2

    The currently latest alpha release of R.swift (5.0.0.alpha.2) supports Swift 4.2 and Xcode 10.

    However, there is a known build system issue. We want to fix this issue before releasing the official 5.0 version of R.swift.

    If you can work around the build system issue, feel free to use the alpha version of 5.0, it works pretty much like R.swift 4.0, but for Swift 4.2. (See complete list of differences)

    Issue: R.swift build step and the New Build System

    When the new build system is used, with a standard R.swift build step, this build step is not run before the Compile Sources build step.

    Because of this, the initial compilation will fail, because there's no R.generated.swift file, and references to the R struct in the rest of the source code are invalid.

    While it's easy to "build twice" during development in Xcode, this is particularly a problem on CI servers, where the build will simply fail because of the missing R.generated.swift file.

    Partial solution: Adding R.generated.swift as an output file

    As a fix for the above issue, you can add R.generated.swift as an output file:

    This will make sure the R.swift step has finished, before the Compile Sources step starts. However, with this output file, the step will only run once:

    Issue: Build step with output file only runs once

    When R.generated.swift is configured as the output file (and there are no input files), the R.swift build step will only run once. On subsequent incremental builds, the step is skipped. Because of this, new resources won't show up in the R struct.

    It is sometimes possible to list the resource files used als input files for the build step, but not always.

    For example, when adding a new image to the asset catalog, the new filename isn't known beforehand.

    Workarounds

    These are possible workarounds:

    1. Use the Legacy Build System. This behaves like before, and the R.swift build step will always run.
    2. Commit the R.generated.swift file. This means during development, you can "build twice" and commit the resulting up-to-date file to git.
    3. Clean build when resources change. Configure the output file for the build step, and manually do a clean build whenever one of the resources are changed.

    None of these workarounds are ideal, so we're still looking for a proper solution.

    opened by tomlokhorst 30
  • Support skipping files

    Support skipping files

    This is a first draft of skipping resource files.

    Not Implemented, yet

    At this moment, following features are not implemented.

    • wildcard
    • skipping all files in folder
    • must not start with "/" (.gitignore ignores first slashes)
    • negation ("!" symbol at the beginning of the line)

    Sample skip file

    Same as .gitignore file, developers should specify relative path from --rswiftignore file. (I don't think it should accept using "..")

    # filter Colors.jpg
    ResourceApp/Images/Colors.jpg
    # filter GdyBkltter1911.ttf
    ResourceApp/Fonts/GdyBkltter1911.ttf
    

    Other comments

    I cherry-pick your commits but some of them conflict with master. So, you better check all of the commits listed here.

    Let me know if you want me to squash my commits.

    Thanks, in advance!

    opened by shiraji 26
  • R.swift not generated

    R.swift not generated

    Hi I have problem in using R.swift. I do every step of installing R.swift using Pods in Xcode 10 but I have this error and no R.generated.swift generated : [R.swift] The folder “R.generated.swift” doesn’t exist.

    opened by erfanwakka 20
  • Add support for loading local project files

    Add support for loading local project files

    Can we add support to recognize the local files stored in the project? Sometimes we add videos, html or json files to the project directory. We should add capability to recognize those files as assets as well.

    Happy to create a PR for this if someone can give me directions on how to implement.

    opened by RishabhTayal 19
  • Info plist is not resolved using environment variables, this is causing errors

    Info plist is not resolved using environment variables, this is causing errors

    I installed with CocoaPods.

    Then i got warning [R.swift] File could not be parsed as Info Plist from URL: /path/to/project/module_name/ $(SRCROOT)/project_name/my_path/Info.plist on xcode 11.2.1.

    However i can use R.swift methods.

    Using version

    • Xcode 11.2.1
    • CocoaPods: 1.8.4
    • R.swift (5.1.0)
    • R.swift.Library (5.1.0)

    BuildPhase

    opened by kumanmushi 18
  • R.swift Cocoapods Run Script Illegal instruction

    R.swift Cocoapods Run Script Illegal instruction

    Hello,

    We are trying to get R.swift setup with our project and we are running into the following error when building the project.

    Command /bin/sh failed with exit code 132

    We installed R.swift via Cocoapods and added the following Run Script above Compile Sources and below Check Pods Manifest.

    "$PODS_ROOT/R.swift/rswift" "$SRCROOT"

    We were able to get R.swift to work in a newly created project.

    We are using Xcode 8.3.3 and targeting iOS 9.0. The project is Objective-C and Swift 3.

    Any help would be greatly appreciated! :)

    opened by pjvea 18
  • Use of undeclared type 'GRKStoryboardProxyViewController'

    Use of undeclared type 'GRKStoryboardProxyViewController'

    I am using R.swift in my project. I some of my view controllers are of instances of GRKStoryboardProxyViewController.

    I have upgraded to R.swift version 3.1.0 and now the R.generated.swift file doesn't import GRKStoryboardProxyViewController

    I am getting "use of undeclared type" errors in

    /// Optionally returns a typed version of segue `showCustomer`.
    /// Returns nil if either the segue identifier, the source, destination, or segue types don't match.
    /// For use inside `prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)`.
    static func showCustomer(segue: UIKit.UIStoryboardSegue) -> Rswift.TypedStoryboardSegueInfo<UIKit.UIStoryboardSegue, BookingViewController, GRKStoryboardProxyViewController>? {
        return Rswift.TypedStoryboardSegueInfo(segueIdentifier: R.segue.bookingViewController.showCustomer, segue: segue)
    }
    

    and other parts of the file where GRKStoryboardProxyViewController is referenced

    I am sorry in I have done some thing wrong and this is not an issue, but any help would be greatly appreciated

    type: issue 
    opened by markGilchristBookingBug 18
  • First build always fails using the new build system with Xcode 10 Beta 6

    First build always fails using the new build system with Xcode 10 Beta 6

    Hi,

    Using the new build system (the default setting) with Xcode 10 Beta 6 results in the first build failing. Subsequent builds pass.

    Configuration

    • Xcode 10 Beta 6
    • R.swift added via cocoapods
    • R.swift build script as follows $PODS_ROOT/R.swift/rswift" "generate" "$SRCROOT

    Result error: Build input file cannot be found: '/Project/R.generated.swift'

    On a local machine, this is not a problem, as we can build again. However, on a CI environment such as Buddybuild, the build continuously fails as it performs a clean build every time.

    opened by superpeteblaze 17
  • Localised Strings in addition to currentLocale

    Localised Strings in addition to currentLocale

    I would like to use localized strings in addition to NSLocale.currentLocale().

    Pattern 1:

    struct string {
      struct localizable {
        let locale: NSLocale
        init(locale: NSLocale = NSLocale.currentLocale()) {
          self.locale = locale
        }
        /// Locales: en, ja
        static func helloWorld() -> String {
            return String(format: NSLocalizedString("HelloWorld", comment: ""), locale: self.locale)
        }
      }
    }
    

    Pattern 2:

    struct string {
      struct en {
        /// Locales: en, ja
        static func helloWorld() -> String {
            return String(format: NSLocalizedString("HelloWorld", comment: ""), locale: NSLocale(localeIdentifier: "en"))
        }
      }
    }
    
    type: enhancement 
    opened by uny 17
  • R.generated.swift is not re-generated without a clean build on 5.0.0 final

    R.generated.swift is not re-generated without a clean build on 5.0.0 final

    Hi!

    I was using R.swift 5.0.0-alpha2 and had a unit test running validate() which was correctly failing whenever I had a wrong asset or font in a XIB:

    XCTAssertNoThrow(try R.validate())
    

    I've just updated to 5.0.0 and checked if that was still working before merging this update, but the test now passes for the same incorrect asset/font that fails the test at 5.0.0-alpha2.

    Am I doing this in a deprecated way or is the feature broken?

    Thanks!

    opened by gobetti 15
  • Call to main actor-isolated initializer 'init(resource:)' in a synchronous nonisolated context

    Call to main actor-isolated initializer 'init(resource:)' in a synchronous nonisolated context

    I get the error on every line containing

    return UIKit.UIStoryboard(resource: R.storyboard.anything)
    

    also happens for UIKit.UINib(resource:)

    IDE: Xcode 14 RC Target: iOS 14

    opened by sprzenus 1
  • Feature request: An option to convert snake case to camel case?

    Feature request: An option to convert snake case to camel case?

    Currently welcome.with_name localization key generates welcomeWith_name function. That's a weird name. I'd like to introduce an option to generate welcomeWithName function instead.

    opened by shinichy 0
  • Unable to generate test coverage report after migrating to Xcode 13

    Unable to generate test coverage report after migrating to Xcode 13

    Getting this error while code coverage generation. I have updated R.swift to latest version but still getting the same issue.

    Failed to merge raw profiles in directory /Users/parmodhchawla/Library/Developer/Xcode/DerivedData/EnrollSDK-duogdaucphsyobgfheuodljkzraz/Build/ProfileData/43D7EAD6-8A9E-43F9-9A18-1EE4E241AA19 to destination /Users/parmodhchawla/Library/Developer/Xcode/DerivedData/EnrollSDK-duogdaucphsyobgfheuodljkzraz/Build/ProfileData/43D7EAD6-8A9E-43F9-9A18-1EE4E241AA19/Coverage.profdata: Aggregation tool '/Users/parmodhchawla/Downloads/Xcode 2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/llvm-profdata' failed with exit code 1

    opened by Parmodlhchawla89 1
  • R.Swift + Multiple targets (widget, app clip ...)

    R.Swift + Multiple targets (widget, app clip ...)

    Hey everyone, I'm struggling with the proper setup of the project where I use R.Swift and have multiple targets:

    • Main iOS app
    • App Clip
    • Widget

    I have files with R.Swift generated strings, images, colors and I'd like to share them across those targets.

    enum Foo {
        case a,b,c
        
        var image: UIImage? {
            switch self {
            case .a:
                return R.image.aImage()
            case .b:
                return R.image.bImage()
            case .c:
                return R.image.cImage()
            }
        }
    }
    

    What is the best way to do that? Should those targets use the single R.generated file, or every target should have its own file (with a different name?)? How should run script phases look like? I'd really appreciate any tips and guides on how to do that. Trying various setups I hit the wall with errors like: Cannot find 'R' in scope Multiple commands produce... Cycle dependencies between targets...

    Thanks!

    opened by ondrejkorol 1
Releases(v6.1.0)
Owner
Mathijs Kadijk
CTO @getmibo — We're hiring ✨
Mathijs Kadijk
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.2k Sep 23, 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 336 Aug 16, 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 823 Sep 17, 2022
This repository contains rules for Bazel that can be used to generate Xcode projects

rules_xcodeproj This repository contains rules for Bazel that can be used to generate Xcode projects. If you run into any problems with these rules, p

BuildBuddy 175 Sep 16, 2022
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 56 Sep 14, 2022
swiftenv allows you to easily install, and switch between multiple versions of Swift.

Swift Version Manager swiftenv allows you to easily install, and switch between multiple versions of Swift. This project was heavily inspired by pyenv

Kyle Fuller 1.9k Sep 16, 2022
Xcode storyboards diff and merge tool.

StoryboardMerge Storyboard diff and merge tool which: compares and merges two storyboard files, provides an automatic merge-facility, The storyboardin

null 238 Sep 12, 2022
An adorable little framework and command line tool for interacting with SourceKit.

SourceKitten An adorable little framework and command line tool for interacting with SourceKit. SourceKitten links and communicates with sourcekitd.fr

JP Simard 2.1k Sep 19, 2022
Soulful docs for Swift & Objective-C

jazzy is a command-line utility that generates documentation for Swift or Objective-C About Both Swift and Objective-C projects are supported. Instead

Realm 7.2k Sep 29, 2022
Laurine - Localization code generator written in Swift. Sweet!

Author's note: Thanks everyone for making Laurine the TOP trending Swift repository in the world - this is amazing and very heart-warming! But this is

Jiri Trecak 1.3k Aug 14, 2022
Script to support easily using Xcode Asset Catalog in Swift.

Misen Misen is a script to support using Xcode Asset Catalog in Swift. Features Misen scans sub-directories in the specified Asset Catalog and creates

Kazunobu Tasaka 123 Jun 29, 2022
An Xcode Plugin to convert Objective-C to Swift

XCSwiftr Convert Objective-C code into Swift from within Xcode. This plugin uses the Java applet of objc2swift to do the conversion. Noticed that the

Ignacio Romero Zurbuchen 338 Sep 7, 2022
Swift autocompleter for Sublime Text, via the adorable SourceKitten framework

SwiftKitten SwiftKitten is a Swift autocompleter for Sublime Text, via the adorable SourceKitten framework. Faster than XCode ! This package is new an

John Snyder 142 Sep 9, 2022
Strong typed, autocompleted resources like images, fonts and segues in Swift projects

R.swift Get strong typed, autocompleted resources like images, fonts and segues in Swift projects Why use this? It makes your code that uses resources

Mathijs Kadijk 8.8k Sep 26, 2022
Swift CLI for strong-typing images, colors, storyboards, fonts and localizations

Shark Shark is a Swift command line tool that generates type safe enums for your images, colors, storyboards, fonts and localizations. Because Shark r

Kaan Dedeoglu 375 Aug 13, 2022
SwiftGen is a tool to automatically generate Swift code for resources of your projects (like images, localised strings, etc), to make them type-safe to use.

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

null 8.2k Sep 18, 2022
Write amazing, strong-typed and easy-to-read NSPredicate.

PredicateFlow Write amazing, strong-typed and easy-to-read NSPredicate. This library allows you to write flowable NSPredicate, without guessing attrib

Andrea Del Fante 103 Aug 12, 2022
Write amazing, strong-typed and easy-to-read NSPredicate.

PredicateFlow Write amazing, strong-typed and easy-to-read NSPredicate. This library allows you to write flowable NSPredicate, without guessing attrib

Andrea Del Fante 103 Aug 12, 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.2k Sep 23, 2022
Easy BMI calculator to review optionals, segues and structs

BMI Calculator Our Goal The goal of this tutorial is to learn more about Optionals, solidify your understanding of the MVC design pattern and to intro

null 0 Oct 24, 2021