David
David

Reputation: 5

Int' is not convertible to 'Range<Int>

I am trying to create a dictionary containing four images to set one of them as background of the UIView. The image selected will depend on the value of a rand number.

Here is code that creates a dictionary:

let backgroundDict = [
        "Clouds":   UIImage(named: "clouds.jpg"),
        "Clouds2":  UIImage(named: "clouds2.jpg"),
        "Sunset":   UIImage(named: "sunset.jpg"),
        "Sunset2":  UIImage(named: "sunset2.jpg")
    ]

Here is how I create the rand number:

var randNumber = Int(arc4random_uniform(UInt32(backgroundDict.count)))

This is the code that declares an array with the keys of the dictionary:

let backgroundArray = Array(backgroundDict.keys)

I get the error 'Int' is not convertible to 'Range<Int> when I try to set the background image:

self.view.backgroundColor = UIColor(patternImage: backgroundDict[backgroundArray[randNumber] as String])

Why is that happening?

Upvotes: 0

Views: 493

Answers (3)

Diego Allen
Diego Allen

Reputation: 4653

Dictionaries return optionals in swift to handle the case of non-existing keys. Using if let image = backgroundDict[backgroundArray[randNumber]] makes sure there's a corresponding UIImage for the key backgroundArray[randNumber] before assigning to the variable image.

The image! (optional unwrapping) inside the conditional is used because image is of type UIImage? (this will cause an error if it's nil). Initialising UIImage by name returns an optional to handle the case of not finding an image with the name provided.

let backgroundDict = [
            "Clouds":   UIImage(named: "clouds.jpg"),
            "Clouds2":  UIImage(named: "clouds2.jpg"),
            "Sunset":   UIImage(named: "sunset.jpg"),
            "Sunset2":  UIImage(named: "sunset2.jpg")
        ]

        var randNumber = Int(arc4random_uniform(UInt32(backgroundDict.count)))
        let backgroundArray = Array(backgroundDict.keys)

        if let image = backgroundDict[backgroundArray[randNumber]] {
            self.view.backgroundColor = UIColor(patternImage: image!)
        }

Upvotes: 0

kellanburket
kellanburket

Reputation: 12833

UIImage(named: "") is an optional initializer init? and UIColor(patternImage: ...) takes a UIImage, so you need to unwrap your images before using them. You also need to unwrap the value returned from the dictionary:

//In Swift 1.2
if let optionalImage = backgroundDict[backgroundArray[randNumber] as String], image = optionalImage {
         UIImage(patternImage: image)
}

//In Swift 1.1
if let optionalImage = backgroundDict[backgroundArray[randNumber] as String] {  
     if let image = optionalImage {
         UIImage(patternImage: image)
     }
}

Upvotes: 1

Antonio
Antonio

Reputation: 72760

There are 2 similar problems:

  • the UIImage initializer is failable, so it returns an optional
  • the dictionary always returns an optional when accessing an element by key

There are 2 ways to fix it:

  • force unwrapping the image twice:

    UIColor(patternImage: backgroundDict[backgroundArray[randNumber] as String]!!)
                                                                               ^^
    
  • force unwrap images when creating the dictionary:

    let backgroundDict = [
        "Clouds":   UIImage(named: "clouds.jpg")!,
        "Clouds2":  UIImage(named: "clouds2.jpg")!,
        "Sunset":   UIImage(named: "sunset.jpg")!,
        "Sunset2":  UIImage(named: "sunset2.jpg")!
    ]
    

    then use a single force unwrap when accessing the dictionary by value:

    UIColor(patternImage: backgroundDict[backgroundArray[randNumber] as String]!)
    

Although I'd usually recommend using optional binding to prevent runtime exceptions, I presume that in this case images must exist, and if they don't it is a development mistake (i.e. failing to add the images to the project or mistyping their names) - so an exception is a great way to figure that out.

Upvotes: 2

Related Questions