12

I am a beginner in iOS and swift.

I used to write Android and I think the R.java is a good idea to manage ids, drawables, strings and other resources. So I'm surprised that iOS does't provide a good function to access resources.

If I want to get a Image from assets, I call UIImage(named: "img_name"), but I don't think this is the best way to access img_name, I may use a wrong name and I can't get the image.

I found some open source project like Shark and SwiftGen, but Shark only support images and SwiftGen it seems need to run a command not automatically.

Do you have any better solution? Thank you!

5 Answers5

4
  • If you are using InterfaceBuilder (also called Storyboard, xib), there is no need to define id for each view. You can bind outlets in code.

  • If you want to retrieve views using their ids (like R.java as you asked), you can set tag to each view and manipulate them in code. enter image description here

Unlike AndroidStudio, Xcode will not generate any file.

func viewDidLoad() {
    let labelView = self.view.viewWithTag(0) as? UILabel
}
GRiMe2D
  • 654
  • 1
  • 10
  • 22
  • Thank you. But it only support ids and layouts right? Is there any function to manage images , colors or strings? – Findley Tyler Apr 16 '16 at 10:13
  • Add your images to `Assets` folder in Xcode. Usually, it's enough to add only 3x images to be appear and scale properly. `UIImage(named: "hello")` will retrieve image named `hello` from `Assets`. – GRiMe2D Apr 16 '16 at 12:09
  • Yes, but using the name of images to init may failed because of typo – Findley Tyler Apr 16 '16 at 16:46
  • @FindleyTyler Yes you're right. But, in Swift there is a special generic type called `Optional`. By default, all types and classes are nil "non-compatible". That means, you cannot assign `nil` as value and compiling code fails. `Optional` makes them assignable, so your app will not crash, unless you force to unwrap them. Here is more info. http://stackoverflow.com/a/24026093/3815843 – GRiMe2D Apr 17 '16 at 07:51
  • Also, `UIImageView` has property `image` with type of `UIImage?` that means `Optional`. You can assign `nil` to `image` and the view will not render anything. So if you expect some image but you are not seeing anything, probably you made a typo – GRiMe2D Apr 17 '16 at 07:53
4

There is no such function in Xcode itself, but there is an open source project that does just this: R.swift

It automatically updates the generated file and supports a lot of different resource types such as images, fonts, segues and more.

Mac_Cain13
  • 3,611
  • 2
  • 24
  • 38
michael wang
  • 553
  • 3
  • 11
4

I have a open source project R.swift-plugin it provides features as you mentioned. You just need to install the Xcode Plugin via Alcatraz and search R.swift

The plugin will automatically generate a resource file to manage your images, localizable strings and colors, and you can access them like using R.java

Usage:

enter image description here

Sincerely recommend you to try it. And feel free to give me any suggestion to improve it :)

Azure Chen
  • 859
  • 1
  • 12
  • 21
  • It looks definitely what I want! But just supports strings, images, colors. Anyway I will try it. – Findley Tyler Apr 17 '16 at 18:15
  • Yes, I think the strings, images and colors should be the most common resources. – Azure Chen Apr 18 '16 at 19:14
  • But I plan to make it support id(reuseidentifier, segue), layout(nib), bool, dimen and integer later! I really hope this plugin will be helpful. – Azure Chen Apr 18 '16 at 19:17
  • Be aware, that while this "R.swift-plugin" uses a very similar name, it is unrelated to the [R.swift](https://github.com/mac-cain13/R.swift) tool. – Tom Lokhorst Apr 19 '16 at 23:45
1

You can have similar functionality by using extensions and enums.

Using enums allows you to avoid typos and benefit from Xcode's autosuggest/autocomplete.

Example for UIImage:

extension UIImage {

    enum ImageId: String {
        // These are your images NAMES,
        // as in "SpriteMonster.jpg"
        case SpriteMonster, SpriteHero, BaseLandscape
    }

    convenience init!(id: ImageId) {
        self.init(named: id.rawValue)
    }
}

Usage:

let monster = UIImage(id: .SpriteMonster)  // the "SpriteMonster.jpg" image

For this example I'm force-unwrapping the convenience init, so be careful to actually have the image with the correct name in your bundle.

For String:

extension String {

    enum StringId: String {
        case Welcome = "Welcome to the game!"
        case GameOver = "You loose! Game over!"
    }

    init(id: StringId) {
        self = id.rawValue
    }

}

Usage:

let label = String(id: .Welcome) // "Welcome to the game!"

For fonts:

extension UIFont {

    enum FontId {
        case HelveticaNeueLarge
        case HelveticaNeueMedium
        case HelveticaNeueSmall

        func font() -> UIFont {
            switch self {
            case .HelveticaNeueLarge:
                return UIFont(name: "HelveticaNeue", size: 18)!
            case .HelveticaNeueSmall:
                return UIFont(name: "HelveticaNeue", size: 12)!
            default:
                return UIFont(name: "HelveticaNeue", size: 14)!
            }
        }
    }

    class func get(id: FontId) -> UIFont {
        return id.font()
    }

}

Usage:

let font = UIFont.get(.HelveticaNeueLarge) // <UICTFont: 0x7ffd38f09180> font-family: "Helvetica Neue"; font-weight: normal; font-style: normal; font-size: 18.00pt

These are only examples to demonstrate the concept, you can go much further with this.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
0

If you use Tuist is has SwiftGen inside. It allows to use it out of the box without adding third-party solutions. The disadvantage is that you have to run it every time when you change resource

yoAlex5
  • 29,217
  • 8
  • 193
  • 205