Add `ImageAsset` protocol
mpospese opened this issue · comments
Intro
It's a common pattern to have a string-based enum to hold the names of image assets in an asset catalog. In each case you need to add some sort of computed property or func to return the image loaded from the asset catalog. It would be nice to have a protocol that we could simply have our enum conform to and skip having to write that implementation again and again. (This is especially true for cases where you might wish to organize your images into multiple enums, which would require writing that image loading property/func once per enum.)
So let's declare a public protocol named ImageAsset
.
(It is patterned off the protocol Localizable
that is already part of YCoreUI. ImageAsset
will do for image assets what Localizable
does for string assets and Colorable
does for color assets).
Tasks
- declare a public protocol
ImageAsset
- declare a static
get
varbundle
of typeBundle
- declare a static
get
varnamespace
of typeString?
- declare a static
get
varfallbackImage
of typeUIImage
- declare a
loadImage
func that takes no parameters and returnsUIImage?
- declare a
get
varimage
of typeUIImage
- declare a static
- add default implementations to all 4
bundle
defaults toBundle.main
namespace
defaults tonil
fallbackImage
defaults to a custom-drawn image that will be obvious to visual QA is not correct. Perhaps a 16x16 image filled withUIColor.systemPink
loadImage
attempts to load the named image using (optionalnamespace
prepended to)rawValue
andbundle
(but returnsnil
if the image does not exist in the asset catalog).image
usesloadImage
but nil-coalesces the result back tofallbackImage
so that it always returns something.
Acceptance Criteria
- Implement
ImageAsset
as described in Tasks above - SwiftLint analysis has 0 violations
- fully unit test the new code by adding images to an asset catalog in the test target only, declaring an enum that lists the names of the images, and test that it loads. Also test expected failures (e.g. blank name or random name does not load, wrong bundle, etc)
- the sample image assets used in our test target need to be as small as possible freely distributable. (I might just create some simple pixel art images to use.)
- fully document all public interfaces on the new code (as per Jazzy documentation coverage tests)
Uses these assets and the following enums for testing:
enum Flags: String, CaseIterable, ImageAsset {
case unitedStates = "flag_us"
case india = "flag_in"
case brazil = "flag_br"
case switzerland = "flag_ch"
static var bundle: Bundle { .module }
}
enum Icons: String, CaseIterable, ImageAsset {
case plus
case minus
static var bundle: Bundle { .module }
static var namespace: String? { "Icons" }
}
enum Missing: String, CaseIterable, ImageAsset {
case notHere
case gone
static var fallbackImage: UIImage {
let image: UIImage! = UIImage(systemName: "x.squareroot")
return image
}
}
Images:
ImageAssets.zip
Put all 6 images into the assets catalog in the Test target.
You can leave the 4 flag images at root level. These are the Flags
enum.
Create a folder "Icons", mark it as being a namespace and put plus
and minus
files inside it. These are the Icons
enum.
The Missing
enum is, well, missing, so we don't need any assets. This lets us test fallback.