Tip: Image Literals

iOS Development tips weekly is a series you can find at the Lynda.com and LinkedIn Learning libraries. The first week of a week’s tip will be available for free. After that, you will need a subscription to get access to it. Click the image at left  to view.  You’ll find an amended transcript below.

You’ve probably seen them in the auto complete in Xcode, but have you ever used Image Literals? Image literals pop images directly into code without initializing a UIImage. While easy, they have their drawbacks. Let’s take look at porting code with image literals.
You’re most likely to use an image literal in a swift playground for iPad.
Download the project from GitHub and install the Swift playground in an iPad Playground. I’ve set up a simple photo background in viewDidLoad. Add the one missing line to this code.

imageView.image = 

You’ll find at the bottom  in autocomplete a small icon with a  mountain and sun.


That the image literal button. Tap that. You get a pop up of several images.

Select the fish dinner. The fish appears in a window.


Tap Use. The image appears in the code.

On iPad, it’s difficult to get a name of an image. You can find it at the top of the image literal selection, but that’s pretty late in the game. You are forced to use literals.
Run this code, and you get the image of the fish dinner.

If you want to change to the ocean scene, tap the literal, tap the Ocean scene,

and you have the ocean. Run again and you get the Ocean scene. Swipe the live  view to the left to see the entire scene.

 

Close the playground, and open the same file as a Xcode playground.

Xcode should start to run the application. Open the live view by clicking the assistant editor button. You’ll notice as it loads, we only get the icon for the image literal.

Once loaded we get the ocean. Stop the code.


Delete the literal, and try adding the fish back. Type Fish and nothing happens. The Swift Xcode Playground doesn’t like adding literals.
To get the fish in, you’ll need the image name. Press Command-1 to open the navigator. Open Resources to get the image names.

 

I’ll add the UIImage(named:) method to use the image:

 imageView.image = UIImage(named:"Fish")

Run and this works.

Let’s convert this to a Xcode project. Add a new Xcode project. Call the project Image literals. Use your team, organization identifier and organization name, and of course Swift for the language. Create it somewhere convenient. I’ll select an iPhone 8 plus for my simulator, and warm up my simulator by right clicking Xcode in the dock and hitting OpenDeveloperTool>Simulator.

Back in your playground, copy the viewDidLoad, and replace the one in the viewDidLoad in the Xcode project. In the playground, select the Fish and the Ocean image. Go back to the Xcode project. Open the Assets.xcassets folder. Drag the fish and ocean to the assets.

 

The assets copy into the assets folder. Xcode uses the literal name  from the assets folder.

 

You can use either the name or the image literal in the project.
Go back to the view controller. Delete the UIImage and type Ocean. The ocean literal shows on the autocomplete.

Select it.

 

Set the simulator to iPhone 8 Plus. Build and Run the code. The Ocean appears. I rotated my phone to see the full image.

Image literals are very convenient, but they are inconsistent in use, especially in Xcode playgrounds. When porting a project from an iPad playground, know where the resources folder is and the resources you used, so you can convert your code to UIImage(named:) for Xcode playgrounds. When working in Xcode projects feel free to use any image you put in the asset folder. Just remember to move the asset folder when moving code around.

The Whole Code

Please note the image literals do not translate well in text based documents. You can also download example files on GitHub here

Swift playground

//:# Image Literals
//: A demonstration of using image literals
import UIKit
import PlaygroundSupport

class ViewController:UIViewController{
    override func viewDidLoad() {
        super.viewDidLoad()
        let imageView = UIImageView()
        // Add the image below here:
        imageView.image = UIImage(named: "Fish")
        imageView.contentMode = .scaleAspectFill
        
        let label = UILabel()
        label.text = "Image Literal"
        label.font = UIFont(name: "Georgia", size: 48)
        label.textColor = .white
        label.backgroundColor = .clear
        view.addSubview(imageView)
        view.addSubview(label)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        label.translatesAutoresizingMaskIntoConstraints = false
        let views:[String:Any] = ["imageView":imageView, "label":label]
        var constraints = [NSLayoutConstraint]()
        let VConstraints = "V:|-[label]-[imageView]-|"
        let HConstraints = "H:|-[imageView]-|"
        constraints += NSLayoutConstraint.constraints(withVisualFormat: VConstraints, options: NSLayoutFormatOptions.alignAllCenterX, metrics: nil, views: views)
        constraints += NSLayoutConstraint.constraints(withVisualFormat: HConstraints, options: .alignAllCenterY, metrics: nil, views: views)
        NSLayoutConstraint.activate(constraints)
    }
    
}

PlaygroundPage.current.liveView = ViewController()

ViewController.swift

//
//  ViewController.swift
//  ImageLiterals
//
//  Created by Steven Lipton on 4/17/18.
//  Copyright © 2018 Steven Lipton. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let imageView = UIImageView()
        // Add the image below here:
        imageView.image = #imageLiteral(resourceName: "Ocean")
        imageView.contentMode = .scaleAspectFill
        
        let label = UILabel()
        label.text = "Image Literal"
        label.font = UIFont(name: "Georgia", size: 48)
        label.textColor = .white
        label.backgroundColor = .clear
        view.addSubview(imageView)
        view.addSubview(label)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        label.translatesAutoresizingMaskIntoConstraints = false
        let views:[String:Any] = ["imageView":imageView, "label":label]
        var constraints = [NSLayoutConstraint]()
        let VConstraints = "V:|-[label]-[imageView]-|"
        let HConstraints = "H:|-[imageView]-|"
        constraints += NSLayoutConstraint.constraints(withVisualFormat: VConstraints, options: NSLayoutFormatOptions.alignAllCenterX, metrics: nil, views: views)
        constraints += NSLayoutConstraint.constraints(withVisualFormat: HConstraints, options: .alignAllCenterY, metrics: nil, views: views)
        NSLayoutConstraint.activate(constraints)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.