How do I determine whether a UIImage is empty? - ios

How do I check to see if a UIImage is empty?
class UserData {
...
var photo: UIImage = UIImage()
}
My ViewController code looks like:
var userData = UserData()
...
func preparePhoto(){
if (self.userData.photo == nil) {
...
}else{
...
}
}
self.userData.photo == nil won't work in Swift.
Xcode says: UIImage is not convertible to MirrorDisposition

self.userData.photo will never be nil, so the question is pointless.
The reason is that you have declared photo as a UIImage. That is not the same as a UIImage? - an Optional wrapping a UIImage. Only an Optional can be nil in Swift. But, as I just said, photo is not an Optional. Therefore there is nothing to check. That is why Swift stops you when you try to perform such a check.
So, what to do? I have two possible suggestions:
My actual recommendation for solving this is that you do type photo as a UIImage? and set it initially to nil (actually, it is implicitly nil from the start). Now you can check for nil to see whether an actual image has been assigned to it.
But keep in mind that you then will have to remember to unwrap photo when you want to use it for anything! (You could instead type photo as an implicitly unwrapped optional, UIImage!, to avoid that constant unwrapping, but I am not as keen on that idea.)
An alternative possibility would be to examine the size of the image. If it is zero size, it is probably an empty image in the original sense of your question!

Related

Why is Apple using this "if let" code? [duplicate]

This question already has answers here:
Why would I use if and let together, instead of just checking if the original variable is nil? (Swift)
(2 answers)
Closed 7 years ago.
Apple has this segment of code on one of their sample projects:
let existingImage = cache.objectForKey(documentIdentifier) as? UIImage
if let existingImage = existingImage where cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage
}
why is apple using this if let? Isn't more logical to simply use
if cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage!
}
???!!
If you use
let existingImage = cache.objectForKey(documentIdentifier) as? UIImage
if let existingImage = existingImage where cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage
}
This will make sure that if existingImage == nil,it will not
execute return existingImage.
Besides,if let also unwrap existingImage from UIImage? to
UIImage
As Abhinav mentioned above, Apple introduced a new type called optional type with Swift.
What does optional mean?
Short and Sweet, "Optional types are types, which can contain a value of a particular data type or nil".
You can read more about optionals and their advantages here : swift-optionals-made-simple
Now whenever you want to make use of value present in an optional type, first you need to check what it contains i.e. does it contains a proper value or it contains nil. This process is called optional unwrapping.
Now there are two types of unwrapping,
Forced unwrapping : If you're sure that an optional will have an value all the time, you can then unwrap the value present in the optional type using "!" mark. This is force unwrapping.
The one more way is to use if let expression, this is safe unwrapping, here you'll check in your program that, if optional has a value you will do something with it; if it doesn't contain value you'd do something else. A simple example is this (You can test this in play ground:
func printUnwrappedOptional (opt:String?) {
if let optionalValue = opt { //here we try to assign opt value to optionalValue constant, if assignment is successful control enters if block
println(optionalValue) // This will be executed only if optionalValue had some value
}
else {
println("nil")
}}
var str1:String? = "Hello World" //Declaring an optional type of string and assigning it with a value
var str2:String? //Declaring an optional type of string and not assigning any value, it defaults to nil
printUnwrappedOptional(str1) // prints "Hello World"
printUnwrappedOptional(str2) // prints "nil"
Hope this clears your question, read through the link given above it'll be more clear to you. Hope this helps. :)
Edit: In Swift 2.0, Apple introduced "guard" statements, once you're good with optionals go through this link, guard statement in swift 2. This is another way to deal with optionals.
Using if let, makes sure that the object (existingImage) is not nil, and it unwraps it automatically, so you are sure inside the if that the condition is true, and the object is not nil, and you can use it without unwrap it !
With Swift, Apple has introduced a new concept/type - Optional Type. I think you better go through Apple Documentation.
Swift also introduces optional types, which handle the absence of a
value. Optionals say either “there is a value, and it equals x” or
“there isn’t a value at all”. Optionals are similar to using nil with
pointers in Objective-C, but they work for any type, not just classes.
Optionals are safer and more expressive than nil pointers in
Objective-C and are at the heart of many of Swift’s most powerful
features.
existingImage is an optional (as? UIImage) and therefor needs to be unwrapped before used, otherwise there would be a compiler error. What you are doing is called forced unwrapping via !. Your program will crash, if existingImage == nil and is therefor only viable, if you are absolutely sure, that existingImage can't be nil
if let and optional types is more help where is there is changes to get nil values to void crashes and unwanted code executions.
In Swift 2.0,
guard
will help us lot where our intention is clear not to execute the rest of the code if that particular condition is not satisfied

Why is this variable "nil" even though I have an "if" statement that checks it not to be

Even though I check whether self.photoImageView.image != nil, I am still getting a fatal error: unexpectedly found nil while unwrapping an Optional value error when I try to applyBlurEffect in the penultimate line.
Do you know how to reconcile this?
if (output?.getAccel() == true){
if (output?.getImage() != nil){
if (self.photoImageView.image != nil){
println(photoImageView.image)
var blurredImage = self.applyBlurEffect(self.photoImageView.image!)
self.photoImageView.image = blurredImage
}
For context, I have a photoImageView, and when an "accelerometer button" is plugged into that photoImageView, this function takes that image, blurs it, and updates the image as a blurred image.
Also when I print photoImageView.image, it returns
Optional(<UIImage: 0x174087d50> size {1340, 1020} orientation 0 scale 1.000000). Therein may lie the problem but I need a little help to solve it.
In Swift you have to use optional binding to make sure that an optional is not nil. In this case you should do something like this:
if let image = self.photoImageView.image {
//image is set properly, you can go ahead
} else {
//your image is nil
}
It is a very important concept in Swift so you can read more here.
UPDATE: As #rdelmar stated, optional binding is not obligatory here, checking for nil should also be enough. Personally I prefer using optional binding though. One of its benefits is the multiple optional binding instead of checking all optionals for nil:
if let constantName = someOptional, anotherConstantName = someOtherOptional {
statements
}

Variable is not nil but code thinks it's nil

I have a class that implements a protocol in order to add 3 variables. I specifically set the image variable, debugger show that the variable exist, but in code when I print it it shows nil, my if let statement also thinks the variable is nil.
#objc protocol DashboardItem {
var title: String { get }
var detail: String { get }
optional var image: UIImage { get }
}
class StaticDashboardItem: DashboardItem {
var title: String
var detail: String
var image: UIImage?
init(title: String, detail: String, image: UIImage) {
self.title = title
self.detail = detail
self.image = image
}
}
EDIT: New screenshot
Logs
nil
2
Your StaticDashboardItem does not fully implement your DashboardItem protocol. It conforms to it but does not implement the var image: UIImage { get } variable, which he has every right not to implement because this conformance is optional. So your StaticDashboardItem does not have any property/variable image that is coming from that protocol.
BUT, instead, you have added another, completely unrelated property var image: UIImage? to your StaticDashboardItem, and you unfortunately gave it the same named, hence your confusion. But that property image on your StaticDashboardItem is not the same as the one from your DashboardItem protocol and that's where your confusion comes from.
If that var image: UIImage? from your StaticDashboardItem is intended to be the implementation of that non-mandatory image property from your protocol then the types must match, so that property from your StaticDashboardItem must be of type UIImage, not UIImage?.
If that var image: UIImage? from your StaticDashboardItem is intended to be a completely different property unrelated to your protocol, then you better use a different name to avoid confusion.
[EDIT] Now that you've updated your question to show more code that confirms my assumptions. As your local dashboardItem parameter in your configure method is declared as a DashboardItem (so, the protocol), then dashboardItem.image refers to the protocol's property (as that code doesn't know about StaticDashboardItem of course, it only know the protocol), which in your case does not exist (you have no property named image of type UIImage in that dashboardItem you're introspecting) explaining that println result nil and that else branch being executed, that's all to be expected given your code.
The only thing that misleads you is the debugger tooltip that also shows you avery other properties of the object being inspected, even properties not limited to the ones from your DashboardItem protocol type, so including that image: UIImage? property and any other coming from the StaticDashboardItem real type of your object.
You are being misled by the way the debugger works. In your screen shot, we are paused before the variable whose value you are examining. Thus, your tool tip showing the value of dashboardItem is not necessarily accurate. The value of dashboardItem is valid for lines before the line where we are paused, not for lines after the line where we are paused.

Swift - casting a nil core data string as an optional value

I have a field stored on a core data object called "metadata" which is of type String (no optional, because Apple docs say not to mess with optionals in CD). Sometimes, the metadata field is nil. In checking whether this value is nil, I do the following check:
if object.metadata as String? != nil {
...
}
However, my code continuously crashes on this line as an EXC_BAD_ACCESS. I have also tried:
if let metadata = object.metadata as String? {
...
}
Which doesn't work either. I cast objects successfully to optionals in other parts of my code, so I don't understand why this particular case isn't working. How do you check whether a core data property is a nil string?
It looks like what you really want is this:
if object.metadata != nil {
...
}
or this:
if let metadata = object.metadata as? String {
// You can now freely access metadata as a non-optional
...
}
--EDIT--
My mistake, I didn't read the first part of your question thoroughly enough. It looks like the duplicate answer has a solution for this. Essentially, the generated managed object subclass is a bug and you should modify the properties to be either optional or implicitly unwrapped. You can check both of those using the first method for implicitly unwrapped and second for optionals.
There are several questions which discuss the issue of the generated subclasses not producing optional properties. I wouldn't be too concerned about editing the subclasses; there's nothing special about them except that Apple is making it easier to create them.
Check if property is set in Core Data?
Swift + CoreData: Cannot Automatically Set Optional Attribute On Generated NSManagedObject Subclass
--Edit2--
If you really don't want to touch the subclass you can access the property using valueForKey() and could add that as an extension if you wanted something a bit cleaner.
if let metadata = object.valueForKey("metadata") as String? {
...
}
In an extension:
extension ObjectClass {
var realMetadata: String? {
set {
self.setValue(newValue, forKey: "metadata")
}
get {
return self.valueForKey("metadata") as String?
}
}
}

What is the existence operator in Swift?

In Objective C this is a valid line of code
self.scrollView.contentSize = self.image ? self.image.size : CGSizeZero;
Which is checking if self.image is nil or not, and choosing the left or right value.
In Swift I want to recreate the same line of code. Actually it should be exactly the same except without the semicolon
self.scrollView.contentSize = self.image ? self.image.size : CGSizeZero
But this is not valid in my Swift code getting an error, 'UIImage does not conform to protocol LogicValue'
What is the correct Swift code?
This code works if self.image is an Optional. There is no reason to have it otherwise because self.image literally cannot be nil.
The following code is completely valid:
var image : UIImage?
self.scrollView.contentSize = image ? image!.size : CGSizeZero
Note: you must use the "!" to "unwrap" the optional variable image so that you can access its size. This is safe because you just tested before hand that it is not nil.
This would also work if image is an implicitly unwrapped optional:
var image : UIImage!
self.scrollView.contentSize = image ? image.size : CGSizeZero
You are describing the conditional assignment ternary operator ?:, which operates as so:
(condition) ? (assign this value if the condition evaluates to true) : (assign this value if the condition evaluates to false)
therefore, self.image needs to be something that evaluates to true or false, which is the case in Swift for anything that conforms to the LogicValue protocol
unlike Obj-C where the mere presence of an object is equivalent to true, Swift requires a little more... we are given Optional Values that can be used as conditionals!
so what you described works if self.image is an optional value, which it sounds like it is not if you are seeing that error
to round out the answer:
if self.image is not optional, it can never be nil so you can safely make the assignment without doing the conditional check
if it is possible at some point that self.image may be nil, then it needs to be one of the optional types, either UIImage? or UIImage! (implicitly unwrapped optional, see https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html)

Resources