Giter Site home page Giter Site logo

mac-cain13 / r.swift Goto Github PK

View Code? Open in Web Editor NEW
9.4K 111.0 753.0 4.53 MB

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

License: MIT License

Ruby 0.54% Swift 99.46%
swift ios watchos tvos code-generator autocompletion xcode resources

r.swift's Introduction

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

As of Rswift 7, Swift Package Manager is the recommended method of installation.

Demo video: Updating from R.swift 6 to Rswift 7 (Starting at 1:06, this describes the installation of Rswift 7).

Xcode project - SPM

  1. In Project Settings, on the tab "Package Dependencies", click "+" and add github.com/mac-cain13/R.swift
  2. Select your target, on the tab "General", in the section "Frameworks, Libraries, and Embeded Content", click "+" and add RswiftLibrary
  3. Select your target, on the tab "Build Phases", in the section "Run Build Tool Plug-ins", click "+" and add RswiftGenerateInternalResources
  4. Build your project, now the R struct should be available in your code, use auto-complete to explore all static references

Screenshot of the Build Phase can be found here

When running on Xcode Cloud

  1. Add a custom build script in ci_scripts/ci_post_clone.sh with the content: defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YES

Package.swift based SPM project

  1. Add a dependency in Package.swift:
    dependencies: [
        .package(url: "https://github.com/mac-cain13/R.swift.git", from: "7.0.0")
    ]
  2. For each relevant target, add a dependency and a plugin
    .target(
        name: "Example",
        dependencies: [.product(name: "RswiftLibrary", package: "R.swift")],
        plugins: [.plugin(name: "RswiftGeneratePublicResources", package: "R.swift")]
    )
  3. Build your project, now the R struct should be available in your code, use auto-complete to explore all static references

CocoaPods

  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

  1. Add the R.swift library to your project
  2. Add mac-cain13/R.swift to your Mintfile and run mint bootstrap to install this package without linking it globally (recommended)
  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:
    if mint list | grep -q 'R.swift'; then
      mint run [email protected] rswift generate "$SRCROOT/R.generated.swift"
    else
      echo "error: R.swift not installed; run 'mint bootstrap' to install"
      return -1
    fi
  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

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

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.

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.

r.swift's People

Contributors

417-72ki avatar 9race avatar amichnia avatar bclymer avatar cerisier avatar chillpop avatar craigsoveritall avatar eeyore741 avatar iv-mexx avatar ky1ejs avatar lammertw avatar mac-cain13 avatar maciejpiotrowski89 avatar mbernson avatar mfcollins3 avatar nicoelayda avatar ntnmrndn avatar pbernery avatar pedrovieira avatar rafaelnobrepd avatar robfeldmann avatar roman-aliyev avatar shiraji avatar tomasharkema avatar tomlokhorst avatar tvede-dk avatar uhooi avatar uny avatar uypanha avatar ykws avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

r.swift's Issues

Handle duplicate names in storyboard/xcasset files

How should we handle this? When you have a Main.storyboard and a Main.xcassets we generate twe structs with the same name.

Possible solutions:

  • Namespacing R.storyboard.* and R.assets.*, but this gives longer names
  • Merge the two structs, but this still gives a small changes of collisions
  • ?

Type fonts

On iOS, user can provide custom fonts through Info.plist's UIAppFonts.
It would be nice to provide completion for:

 func R.font.appFonts.fontName(fontSize:14.0) -> UIFont!
 var R.font.appFonts.fontName: String

Bonus:

R.font.system.helvetica(fontSize:14.0) -> UIFont!
var R.font.system.helvetica: String

This is a bit complicated since with have to find the right names for the fonts, but it would be a really nice feature :)

Maybe I can find some time to implement that.
Can you give me a feedback before I start ?

generated swift file contains storyboard, segue structs in a project which doesn't have any storyboards

Hi there,

First of all, thanks for opensourcing this project :)

I just integrated this with Cocoapods and there's something I couldn't understand. My project doesn't contain any storyboards, thus any segues neither; but after compiling the project, my R.generated.swift file has a storyboard struct, a segue struct with some segues that I couldn't understand where they came from. Also, the reuseIdentifier struct has many duplicate "Cell" reuseIdentifiers which causes the project not to compile. I couldn't understand where those came from either :) cos I don't have any cells in storyboards or nibs.

I hope I'm just confused and missing something :) because I'd love to use this a lot!

Thanks in advance and cheers!

[iOS 9] Add support for ApplicationShortcuts

Static shortcut items must be defined in Info.plist with the following keys under the UIApplicationShortcutItems array:

Key Description
UIApplicationShortcutItemType (required) A required string delivered to your app when the user invokes the corresponding quick action. Your app can use this string to classify quick actions into types, and then to disambiguate among action types it receives. You don’t need to register your quick action types.
UIApplicationShortcutItemTitle (required) A string displayed to the user on the Home screen as the name of the quick action. If the title fits on one line, the system displays it as a single line quick action item. If the title is too long for one line and you have not specified a UIApplicationShortcutItemSubtitle string, the system displays the title on two lines. You can, optionally, internationalize a quick action title by employing your app’s InfoPlist.strings file. For guidance on how to do this, read Localizing Property List Values.
UIApplicationShortcutItemSubtitle An optional string that is displayed to the user on the Home screen, immediately below the corresponding title string. If you specify a subtitle for a quick action, the system displays the quick action title on a single line (perhaps just a portion of the title, followed by ellipsis character), no matter how long the title is. You can, optionally, internationalize a quick action subtitle by employing your app’s InfoPlist.strings file. For guidance on how to do this, read Localizing Property List Values.
UIApplicationShortcutItemIconType An optional string specifying the type of an icon from the system-provided library; see the UIApplicationShortcutIconType enumeration in UIApplicationShortcutIcon Class Reference. The icon is displayed in the set of quick actions for your app, along with the quick action's title, on the Home screen.
UIApplicationShortcutItemIconFile An optional string specifying an icon image to use from the app’s bundle, or the name of an image in an asset catalog. The icon is displayed before quick action title on the Home screen. Icons should be square, single color, and 35x35 points, as shown in these template files and as described in iOS Human Interface Guidelines. If you specify this key, the system ignores the UIApplicationShortcutItemIconType key.
UIApplicationShortcutItemUserInfo An optional, app-defined dictionary. One use for this dictionary is to provide app version information, as described in the “App Launch and App Update Considerations for Quick Actions” section of the overview in UIApplicationShortcutItem Class Reference.

More info:

Tests

I would be a lot more comfortable using this if this had at least a few tests.
Great work though, I absolutely love this :)

Destination Directory

Hi there,

I was wondering if it would be possible to add another argument so that one can specify destination folder. I don't want to have the auto generated file in the root of the project folder but rather in a dedicated resources folder.

What do you think? I would implement this myself but I'm honestly a little confused with your project setup.

Create validate storyboard images thing

Something like:

struct R {
  static func validateStoryboardImages() {
    assert(UIImage(named: "bla") != nil, "Err?!")
  }
}

that we can call at application launch for debug builds, this would make sure old image don't linger around in your storyboard.

Type CoreData stuff

We could generate full ManagedObjects in Swift (since Apple does that so poorly), but we also could make querying better by providing something like R.managedObject.car.color == "color" that you can use a %K value in a predicate.

Detect unused images

Maybe we could do something with detecting unused images and warning the developer about it?!

Homebrew

Would be cool if we could install this using Homebrew :)
Then we wouldn't need to have the binary in every single project folder.

Typed overload of dequeueReusableCellWithIdentifier

Would be nice to write this:
let x = tableView.dequeueReusableCellWithIdentifier(R.reuseIdentifier.rerouteBusinessHoursCell, forIndexPath: indexPath)

instead of this:
let x = tableView.dequeueReusableCellWithIdentifier(R.reuseIdentifier.rerouteBusinessHoursCell, forIndexPath: indexPath) as RerouteBusinessHoursCell

The new release (0.8.1) is broken

It generates a file where UITableViewCell and UICollectionView (and more) are written as Uitableviewcell and Uicollectionview (or similar) and a project using it won't compile.

Carthage support

Do you have any plans as of yet to implement Carthage support for this repo?

Fantastic project by the way!

Detect resources based on resource build step

Detect resources based on resource build step in the Xcode project file not based on browsing the users folders. This is would be way more reliable and prevent confusion of files that are missing or duplicated etc.

Spaces in image names not supported

xcode works fine with spaces in asset names, however R.swift generates invalid code

static var detail Disclosure: UIImage? { return UIImage(named: "Detail Disclosure") }

[Xcode 7] [Swift 2] 'Printable' has been renamed to 'CustomStringConvertible'

Attempting to use R.swift in a project which has been converted to Swift 2 in Xcode 7 beta 5 results in a build error in R.generated.swift which says 'Printable' has been renamed to 'CustomStringConvertible'.

The offending code is:

struct ReuseIdentifier<T>: Printable {
  let identifier: String

  var description: String { return identifier }
}

Change distribution method to script based instead of binary

Hi,
I had an issue migrating our app to swift 2.0:
See:
ntnmrndn@a1d58b9

By forking and editing the source code, I noticed that the script is not being compiled from source but rather distributed as a binary.
While I'm convinced you are honest and while I could probably verify that the binary distributed is the same as the one I would be able to compile myself, I strongly believe it would be better for the user to compile directly the source on his computer, and launch the script using swift command line tools.

Better support for images in different bundles

I have some IBDesignable classes that rely on images. Unfortunately using UIImage(named:) doesn't work in Interface Builder, as Interface Builder creates separate bundles for each class which you're supposed to use when creating images. For example, I have the following code:

let bundle = NSBundle(forClass: self.dynamicType)
let image = UIImage(named: "chevronAccessory", inBundle: bundle, compatibleWithTraitCollection: nil)
return UIImageView(image: image)

"chevronAccessory" is an image that exists in my asset catalog, so it would be nice if I could use R.swift to get the name.

Perhaps with the following format:
R.imageName.chevronAccessory
or
R.image.name.chevronAccessory

I'm not sure how typical this use case is, so it might not be worth decreasing the usability of images, but if you wanted to do so you could make images into a nested struct like nib. So then you could have:
R.image.chevronAccessory.instance
R.image.chevronAccessory.insantiateWithBundle(bundle)

UINavigationController without custom class generates wrong return type

Storyboard:
<navigationController storyboardIdentifier="modalShipmentResultNavigationController" id="zyq-w4-qbK" sceneMemberID="viewController">

Generates:
static var modalShipmentResultNavigationController: UIViewController? { return instance.instantiateViewControllerWithIdentifier("modalShipmentResultNavigationController") as? UIViewController }

Should be:
static var modalShipmentResultNavigationController: UINavigationController? { return instance.instantiateViewControllerWithIdentifier("modalShipmentResultNavigationController") as? UINavigationController }

Swift 2 Support

Currently the generated R.Swift has a struct that implements Printable:

struct ReuseIdentifier<T>: Printable {
  let identifier: String

  var description: String { return identifier }
}

Printable has been replaced with CustomStringConvertible with the introduction of Swift 2. Perhaps we could have a argument to pass a version of swift to generate the file for?

Take the nib structs out of scope to prevent autocompletion

As suggested by Tom on Q42 Slack:

Feature request voor R.swift:
Niet de struct in dezelfde namespace hebben als de waarde die ik nodig heb.
Ik moet gebruiken R.nib.textCell, maar in de autocomplete zit ook R.nib.TextCell, die ik nooit nodig heb.
Of op z'n minst postfix de naam, zodat het duidelijk is dat ik die niet wil: R.nib.TextCellNibResource

I think they should be completely out of the R-struct since it's a strictly supporting struct.

InitialViewController

Wil je mij de initiele viewController via R.swift aanbieden?

// <3 R.swift
let storyboard = R.storyboard.main.instance
let initialViewController = storyboard.instantiateInitialViewController() as UIViewController

What about UIViewController with Nib?

I don't think it is not possible yet to initial an UIViewController with nib file like the example below.

/// Old way 
SelectPlanViewController(nibName: "SelectPlanViewController", bundle: nil)

/// Should be 
SelectPlanViewController(nibName: R.nib.selectPlanViewController.nibName, bundle: nil)

/// or even as extensions from UIViewController 
SelectPlanViewController(rResource: R.nib.selectPlanViewController)

What do you think about it?

Manual Install confusion

I've dragged the unzipped R.swift-master into my $SRCROOT and attempted to run script build phase with "$SRCROOT/rswift" "$SRCROOT", but all I get is "/Users/mlchild//Developer/Project/rswift: No such file or directory".

I understand I am likely an idiot, but cannot figure this out. Prefer not to use cocoapods.

Force unwrapped UIImages

I was wondering whether it would be possible to force unwrap the UIImages so that the different struct vars don't return an Optional? Might seem scary but it shouldn't be too dangerous if the library is well tested. What do you think?

Cocoapods

Kan je hem toegankelijk maken op Cocoapods? 👼

Not supporting images in Assets.xcassets

Images I placed inside Assets.xcassets are not getting strong-typed.

Everything else seems to work file - storyboards/view-controllers/xibs etc.
I have integrated R.swift using pod in my project.

Using Swift 1.2
Xcode 6.4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.