How to use image contained in Resource framework from main module? - ios

I made embed framework Resources.framework to encapsulate Resources like images and colors.
When I put image resources to main module's storyboard,
InterfaceBuilder present all images correctly, But compiled application didn't present Images. Why? Color resources are presented. Images only.
Can I use image resources from embed frameworks?

As of Xcode 12.1, I do not believe there is a way to do this.
The reason is that when you configure an images using storyboards Xcode defaults to assuming those images are located in the bundle for the current module, and the Attributes inspector does not provide a way to specify an alternate module, as it does in the case of view controller classes:
View controller attribute inspector with Module property
But in code this is easy to accomplish using the in:Bundle? parameter for initializing a UIImage, which tells the app to look in a specific bundle for the image resource at runtime.
guard
let bundleURL = Bundle.main.url(forResource: "[bundle filename without extension]", withExtension: "bundle"),
let bundle = Bundle(url: bundleURL) else { return }
let image = UIImage.init(named: "[image name]", in: bundle, compatibleWith: nil)
It is likely an oversight on Apple's part to allow Xcode to show image resources from other modules in the image name field, but not properly link them when compiling storyboards. I hope they fix this.
Beware of using color assets from other modules as well:
While they appear to work, it is only because when you assign color assets in a storyboard, Xcode actually encodes the color information from the asset in the storyboard file itself. One sign this is not intended to work is that if you define a Color Set asset with a variation for Dark Appearance, only the Any Appearance color will be used (even in dark mode). Color Set assets in the same module, however, work normally.
Color Set Asset with Any Appearance and Dark Appearance

Related

Loading images and color codes from xcasset inside a bundle

In order to support multiple brands, i am keeping the images and assets in bundle. Each bundle has different images and color codes based on brand. So how to fetch images and color code inside of a custom bundle.
If its syntax you are after, it here --
Load image from bundle with iOS
Specifically --
UIImage(named: <#T##String#>, in: <#T##Bundle?#>, compatibleWith: <#T##UITraitCollection?#>)
UIColor(named: <#T##String#>, in: <#T##Bundle?#>, compatibleWith: <#T##UITraitCollection?#>)
If you are concerned with the architecture --
I'd create an enum with all the Brands that you support with their corresponding Bundles as a computed property. Then I'd add simple methods to get image & colour based on brand in extensions of UIColor & UIImage (so you want have pass bundle every time). Those extension methods (returning colour & image) will use the methods mentioned above along with current Brand (assuming it's a global).
If current brand is not global then you can write a helper struct or something that has the current brand & will provide methods that return colour & image.
Pass bundle every time to the methods above.
I'd go with (1)

iOS dark mode - image assets not redrawn

I'm implementing the dark mode for iOS. The problem occurs with the images:
I've opened the Assets.xcassets and changed the "appearances" "to Any, Dark"
Of course I've added the new image.
Unfortunately the images are not being redrawn when overriding the environment interface style in xcode.
I've tried catching the traitCollectionDidChange method in my viewController and it is properly called. I could set the new image (origImage_dark), but shouldn't it be automatic? That's what the asset settings are made for. I'm using the .alwaysOriginal rendering of the image.
Running the app with dynamic resolve of the image helped:
let image = UIImage(named: "someImage")
let asset = image?.imageAsset
let resolvedImage = asset?.image(with: traitCollection)
After this, reverting back to the original way of setting the images seemed to work. Xcode, thanks a lot!

How to render xcassets from Framework in Storyboard with proper tint?

Given: A main app, 'Main' and a linked framework 'Icons' in Swift 4 and Xcode 10.
Problem: In main app on storyboard, images from Icons framework display but do not show proper tint.
Icons framework has an xcassets with icon images all rendered as template
Icons framework has been linked into and embedded into Main
Icons.xcassets has been copied by reference into Main
Here is the class from Icons framework that initializes the image for use in Main:
public class KeyWordItem {
public let keyWord:String
public let keyWordImage:UIImage
public let keyWordPrompt:String
/// A failable initializer for a keyword item. nil will be returned if the icon image is not found.
///
/// - Parameter keyWord: The keyword in lowercase, ie., character, scene, conflict, etc.
public init?(using keyWord:String) {
let bundle = Bundle(for: type(of:self))
guard let prompt = keyWordDictionary[keyWord],
let image = UIImage(named:keyWord, in: bundle, compatibleWith:nil) else {
return nil
}
self.keyWord = keyWord
self.keyWordPrompt = prompt
self.keyWordImage = image.withRenderingMode(.alwaysTemplate)
}
}
Note: The icon images are not in the main bundle so you have to get the bundle from the framework. Additionally, when using a storyboard, the only way I could get the images to render at all in Main was to copy (reference only) Icons framework's xcassets folder into Main.
My preference is to keep the Icons framework as UI-lite as I can so I do not want to include a special ViewController in the framework which then would be used in a Main storyboard by referencing Icons as a module.
As proposed by Augie, the image will render with proper tint if a runtime attribute for tintColor is set in the storyboard, but this seems a little less than elegant. (But, hey, it does solve the problem...)
Question 1: How can I get what is a framework's xcassets images marked as render as template, to properly tint in a storyboard outside of the framework?
Question 2: Is this the best approach to handle the requirement to keep all of my icon's and menu items together and not littered all over my Main App?
Thanks in Advance,

How to override images in a storyboard which is within a framework

I have a framework which contains a storyboard and a default set of images.
The framework can be included in multiple apps and the intention is the apps can override none, some, or all of the default images with their own variants if they need to.
The problem I am facing is that I haven't found a solution which works for all scenarios, for example:
If the framework contains an image called Person and the framework is used by app A which supplies it own version of Person, and the framework is used by app B which does not supply its own version of Person then:
If the framework sets the image using code such as:
let image = UIImage.init(named: "Person")
someImageView.image = image
Then when app A is run its variant of the Person image is found and displayed correctly. (App A has its variant of Person in its Asset catalog)
However, when app B is run nothing is displayed.
On the other hand if I don't set the image using code (i.e. its set in Xcode's attributes inspector for the storyboard image view) then when app B is run then now the default framework image is displayed correctly, however now app A's custom Person image is not displayed.
Is there a way I can successfully cover these three scenarios:
a default image is in the framework and neither app A nor app B
wish to override it with their custom image
default image is in
the framework and app A wants to override it but app B does not.
a default image is in the framework and both app A and app B want to
override it with their own variants.
(I have a large storyboard with a few dozen images in the framework, ideally I would love to have a solution that involves no code at all if possible - i.e. the default image name is set via Xcode's attribute inspector for the image views and if an app provides its own version of the image in its asset catalog that image is automatically displayed)
This code works, but seems a bit clunky and it would be great if there is a codeless solution possible instead - just using xcode/storyboard settings for example.
extension UIViewController {
func getImage(name:String) -> UIImage?
{
var bundle = Bundle.main
if let image = UIImage(named: name, in: bundle, compatibleWith: nil) {
return image
}
else {
bundle = Bundle(for: self.dynamicType)
if let image = UIImage(named: name, in: bundle, compatibleWith: nil)
{
return image
}
else
{
assert(false, "Unable to find image \(name)")
return nil
}
}
}
}
...
theImage.image = getImage(name: "Person")

IOS Changing Main Bundle preference in XIB

I have a custom Resource bundle where i'll have all my images and localization files inside it.
When I assign some images in xib I have to type the entire path where image resides inside my bundle for example MyResource.bundle/Images/Event/xxx.png.
Which means in xib it always taking apps main bundle for images.
Here my question is is there any possibility is there like I can change the default bundle preference to MyResource.bundle/Images So that I can see the image in xib when assigning to a uiimageView or any other.
preference? in simple words its not possible because there is no property like that, so you need to find out a way to achieve this, but i have used bundle for resources but not have this kinda problem because bundle is logical path
My solution is add one image manager to manage your image resource. I mean when you need an image, you just call your manager's method passing in the image name. And your image manager will read the correct image file from corresponding bundle and return it based on device's language.

Resources