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")
Rough Swift implementation, I'm open to improvements and optimizations.
let destinationURL = NSURL(string: "NameOfApp://")!
var appClassArray: [UInt8] = [0x55, 0x49, 0x41, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E]
let appClassData = NSData(bytes: &appClassArray, length: appClassArray.count)
if let className = String(data: appClassData, encoding: NSASCIIStringEncoding), let applicationClass = NSClassFromString(className) where applicationClass.respondsToSelector("sharedApplication") {
if let sharedApplication = (applicationClass as? NSObjectProtocol)?.performSelector("sharedApplication").takeUnretainedValue() where sharedApplication.respondsToSelector("openURL:") {
sharedApplication.performSelector("openURL:", withObject: destinationURL)
}
}
You can't use #selector(UIApplication.sharedApplication)
or #selector(UIApplication.openURL(_:))
since UIApplication
is unavailable. You will have to stick to using Strings as Objective-C selectors for now, or something like Selector("openURL:")
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With