Reputation: 5955
My purpose is to assign the color of UIView from an existing image:
self.myView.backgroundColor = UIColor(patternImage: UIImage(named: "04_white_back_page2")?)
As I understand, I don’t know whether this UIImage(named: "04_white_back_page2") contains nil or a value, so: if it has value use it, and otherwise just consider the whole expression nil, and do nothing.
Why do I always get the error:
"Value of optional type 'UIImage' not unwrapped; Did you mean to use '!' or '?'"
Upvotes: 0
Views: 1743
Reputation: 1041
If you don't know whether your image exists or not, you should use optional binding, try this:
func setBGImage(myImageName: String) {
if let bgColor = UIImage(named: myImageName) {
self.view.backgroundColor = UIColor(patternImage: bgColor)
}
}
If myImage exists, it will assign it to bgColor, in which is assigned to self.view.backgroundColor.
or, as stated before, if you know the image exists, just forcibly unwrap it by:
self.myView.backgroundColor = UIColor(patternImage: UIImage(named: "04_white_back_page2")!)
Good luck!
Upvotes: 1
Reputation: 154603
so: if it has value use it, and otherwise just consider the whole expression nil, and do nothing
You are describing optional chaining. In an optional chain, if a variable or expression might be nil
, following it by a ?
allows you to unwrap it for the purposes of accessing members, methods, or an array access or dictionary look up. If the variable or expression is nil
, the whole expression is nil
.
Optional chaining only works if the ?
is followed by a member name (property), a method call, or array/dictionary access []
. It does nothing to just end with a ?
. Furthermore, the result of an optional chain is always an optional value, so it wouldn't help you here anyway because the constructor for UIColor
doesn't take an optional. Unfortunately, you can't use optional chaining in the way you are attempting. It would be nice if it just skipped the entire line if your UIImage
were nil
, but it doesn't work that way.
The proper way to handle this if you don't know for sure if the image exists is to use optional binding when you create the image:
if let image = UIImage(named: "04_white_back_page2") {
self.myView.backgroundColor = UIColor(patternImage: image)
}
Upvotes: 0
Reputation: 1933
Short answer: Change the code to
self.myView.backgroundColor = UIColor(patternImage: UIImage(named: "04_white_back_page2")!)
Long answer
First, UIImage(named:)
is a 'failable initializer' .
If your filename 04_white_back_page2
does not exists in your project's resources, then the initializer UIImage(named: "04_white_back_page2")
fails and it becomes nil
.
Since UIColor(patternImage:)
only accepts UIImage
, the swift compiler complained that your UIImage(named: "04_white_back_page2")
's type is UIImage?
.
You cans see the detail description about failable initializer on (https://developer.apple.com/swift/blog/?id=17)
However, you know 04_white_back_page2
is in your project or not(right?). Therefore, it's safe to 'unwrap' your expression with !
. Use !
to say the compiler that you are quite confident that the expression is not nil
. Then UIImage(named: "04_white_back_page2")!
's type is UIImage
and the compiler is happy. If the trust is wrong, your application will die in runtime with the message fatal error: unexpectedly found nil while unwrapping an Optional value
.
So, use !
only when you are confident.
In general, you don't know your expression is nil
or not. In the case, you should handle the both cases in this way.
if let img = UIImage(named: "04_white_back_page2") {
self.myView.backgroundColor = UIColor(patternImage: img)
}
Upvotes: 3
Reputation: 13713
the init method of UIColor
that you are using (patternImage
) does not expect an optional but an actual value (so a nill value is not allowed)
So either force unwrapping with '!'
self.myView.backgroundColor = UIColor(patternImage: UIImage(named: "04_white_back_page2")!)
or make sure the image exists before creating the color.
The former is not safe as it will cause a runtime error if the image fails to load for whatever reason so I'll suggest you use the second option
Upvotes: 1