TomQDRS
TomQDRS

Reputation: 895

IBDesignable's custom background color property doesn't update based on the target

I am running into an extremely specific problem with XCode.

Setup

Equally named Colors different in Targets

I have two targets in my XCode project, Target A and Target B.

They both have an individual assets folder named Colors.xcassets with a color named "Primary". The color "Primary" in Target A is red, the one in Target B is blue.

Both Targets have Storyboard with standard UI elements using the color "Primary". Building and Running the targets causes the interface to display the correct "Primary" color for the target.

Shared IBDesignable

Both targets are assigned the same IBDesignable class for a custom UIButton that displays colors by creating a UIImage as the background so it can be rounded.

The background image is set by calling the following function when the button is initialised or the color property is set:

private func refreshBackgroundWith(color: UIColor) {

    let image = createImageFrom(color: color)
    setBackgroundImage(image, for: UIControl.State.normal)

    clipsToBounds = true
}

The image is created like this:

private func createImageFrom(color: UIColor) -> UIImage {

    // If color is clear, return clear image
    if(color == UIColor.clear) {
        return UIImage()
    }

    UIGraphicsBeginImageContextWithOptions(CGSize(width: 1, height: 1), true, 0.0)
    color.setFill()
    UIRectFill(CGRect(x: 0, y: 0, width: 1, height: 1))
    let image = UIGraphicsGetImageFromCurrentImageContext()!

    return image
}

This works well in general, however with the above mentioned target-color situation, I am running into the problem.

Expectation

I am expecting the IBDesignable button to create a background image based on the color I assigned it in the Storyboard, and that color to be different when I build different targets.

Result

When I build and run Target B, the color on the IBDesignable button shows red, even though I am expecting blue. This can also happen the other way around, when I build Target A and it shows blue instead of red.

The color also shows red in the Storyboard and the named color picker, even though the target dictates it to be blue - This is however not a problem for other elements, because once the target is run, the correct color is used - On everything except for the custom IBDesignable.

Whichever color is displayed in the named color picker is the one displayed in the IBDesignable. That color changes randomly whenever I shutdown and restart XCode.


Has anyone had this exact or a similar problem before? I am currently wondering at which point in the process the build doesn't go as expected.

Could this be an issue of not completely rebuilding the project each time I build it to run?

Any suggestions are highly appreciated.

Upvotes: 1

Views: 548

Answers (1)

Emiel Bon
Emiel Bon

Reputation: 11

I have the same problem. I have 2 targets and 2 xcassets files, one for each target. Both contain a color named "primary", which is blue for target A and orange for target B. Using UIColor(named: "primary") in code works as expected, the color changes depending on the selected target.

Switching the target does not update the Storyboard in Interface Builder with the correct colors though, "primary" keeps the value it had previously. However, at runtime the behavior is correct when setting "primary" as e.g. a background or tint color in the Storyboard.

The only exception is when assigning "primary" to an IBInspectable value in the Storyboard, then it sets the IBInspectable to the wrong color that it is displaying in Interface Builder, even when that color is not in the xcassets file of the selected target.

I have confirmed there is a <namedColor> tag added at the bottom of the Storyboard's XML, the IBInspectable appears to be using that value instead of the runtime value. When using named colors that are shared between the targets, there is no problem for IBInspectables.

Xcode version: 10.3 Deployment target: iOS 11.0

Upvotes: 1

Related Questions