查找自动调用函数的包

Find what bundle a function was called from automatically

我正在从事的一个项目最近由于我无法控制的原因分成了多个较小的项目。

我们在一个项目中有一些辅助方法来创建 shorthand 和键入安全图像请求...这样做的原因是围绕主题具有灵活性。也许一个主题 detailDisclosure 与另一个主题不一样。

语法如下所示

public extension UIImageView {
    convenience init(_ key: UIImage.Key) {
        self.init(image: UIImage(named: theme.imageName(for: key)))
    }
}

let imageView = UIImageView(.detailDisclosure)

它是姊妹函数

let image = UIImage(.detailDisclosure)

当所有图像和主题都位于同一个地方时,这是非常简单的事情。但是现在我们有不同的项目,在不同的资产文件夹中有不同的资产。

所以我必须添加的是这个......

convenience init(_ key: UIImage.Key, in locality: AnyClass? = nil) {
    self.init(image: UIImageView.localImage(named: key.rawValue, in: locality))
}

// Currently assumes this method and default assets are in the main bundle by default 
fileprivate static func localImage(named name: String, in locality: AnyClass?) -> UIImage? {
    let bundle = (locality != nil) ? Bundle(for: locality!) : Bundle.main
    return UIImage(named: name, in: bundle, compatibleWith: nil)
}

let image = UIImage(.detailDisclosure, in: ThisProjectTheme.self)

ThisProjectTheme 实际上可以是此捆绑包中的任何 class,从技术上讲,您也可以转到另一个捆绑包并以这种方式共享其资源。

不过,从消费者的角度来看,这种额外的努力是我希望避免的,而且我认为这对新手来说也很危险。

更好的是,除非此 API 的消费者指定不同的 locality,否则我们会自动为他们找到他们的位置;而不是转到主包的当前解决方案。

将来,这些请求中的大部分将来自拥有自己资产的项目。

我见过的例子 file: String = #file

convenience init(_ key: UIImage.Key, file: String = #file, in locality: AnyClass? = nil)

意味着我们显然可以破解它,但我想知道是否有一个优雅的解决方案来获取发件人或与此相关的捆绑包,而无需消费者隐式地将其发送给函数?

感谢您的宝贵时间

"what bundle a function was called from automatically"

虽然这听起来很有吸引力,但您 realllllly 不希望这样。当您发现 copy/pasting 从一个项目到另一个项目的某些代码导致其行为不同的那一刻,就是您失去理智的那一刻。

相反,我认为整个方法需要重新设计。首先,UIImage 似乎是错误的抽象点。相反,我会使用这样的东西:

import UIKit

class ImageProvider {
    let bundle: Bundle

    init(bundle: Bundle) {
        self.bundle = bundle
    }

    init(forMainClass mainClass: AnyClass) {
        self.init(bundle: Bundle(for: mainClass)!)
    }

    func image(
        named: String,
        with configuration: UIImage.Configuration? = nil
    ) -> UIImage {
        return UIImage(named: name, in: self.bundle, with: configuration)?
    }
}

每个应用程序都会创建自己的 ImageProvider,它会在自己的捆绑包中搜索资产。

这有几个主要优点:

  1. 接口可以很容易地提取到协议中,并且可以创建模拟实现以用于测试。
  2. 您有一个 point-of-entry 图像系统,它允许您处理缓存、主题、大小调整等。
  3. 您可以扩展它以将 look-up 处理成多个包 ("first search my app bundle, if not, try this framework's bundle")
  4. 您可以扩展它以使用枚举来识别图像,而不是原始字符串。