Home > Enterprise >  Swift: If image exists, return it, otherwise return nil
Swift: If image exists, return it, otherwise return nil

Time:09-28

I've been trying to find a way to check if SF Symbols and Images exist in swift.
In all of the answers I've come across, the nil coalescing operator (??) is used, which requires a default image that always exists. This doesn't work in my case.

I would like to test if an image (or a symbol) exists and then return it if it exists, otherwise return nil.

How can this be achieved?

IMPORTANT NOTE
I am trying to achieve this using SwiftUI's Image for a multiplatform application. I am trying to avoid using UIImage or NSImage to do my checks.

UPDATE 1

Note 1: When requesting an SF Symbol that does not exist (for example, there was a typo in the systemName: [name] parameter), the image appears as an empty area. (Tested with Label)

The following solutions have been tested and are ineffective:
(Note: in all of the attemps, there are is a variable name: String)

Solution 1

let image = Image(systemName: name)
if image {
    return image
} else {
    return nil
}

Throws the error:

Cannot convert value of type 'Image' to expected condition type 'Bool'

It throws the exact same error when: let image = Image(name)

Solution 2

if let image = Image(systemName: name) {
    return image
}

Throws the error:

Initializer for conditional binding must have Optional type, not 'Image'

Solution 3

let image = Image(systemName: name)
if image != nil {
    return image
}

Does not work and gives the warning:

Comparing non-optional value of type 'Image' to 'nil' always returns true

CodePudding user response:

As you have discovered, Image.init(systemName:) returns some sort of placeholder image if the name isn't recognized.

If you want to detect whether the name is recognized, you can try creating a UIImage with it. UIImage.init?(systemName:) returns nil if the name isn't recognized.

let image: Image? = UIImage(systemName: name)
    .map { Image(uiImage: $0) }

The above Image might behave differently in some ways than an image created with Image(systemName:). I'm not sure. So you can do the following instead if that is a problem:

let image: Image? = UIImage(systemName: name)
    .map { _ in Image(systemName: name) }

CodePudding user response:

Following @rob mayoff's answer I ended up creating cases for the OS and then using concise checks to determine if an image exists and do logic.

In the end, I was able to avoid using UIImage or NSImage outside the actual check.
This is an unorthodox and inefficient approach, but this is what my code ended up like:

For Custom Images

#if os(macOS)
if (NSImage(named: name)) != nil {
    //image found, do some logic...
}
#elseif os(iOS)
if (UIImage(named: name)) != nil {
    //image found, do some logic...
}
#endif

For System Symbols

#if os(macOS)
if (NSImage(systemSymbolName: name, accessibilityDescription: "")) != nil {
    //image found, do some logic...
}
#elseif os(iOS)
if (UIImage(systemName: name)) != nil {
    //image found, do some logic...
}
#endif
  • Related