简体   繁体   中英

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?

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 (ie failing to add the images to the project or mistyping their names) - so an exception is a great way to figure that out.

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)
     }
}

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!)
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM