【问题标题】:Find what bundle a function was called from automatically查找自动调用函数的包
【发布时间】:2019-07-12 03:15:27
【问题描述】:

由于我无法控制的原因,我正在处理的一个项目最近被拆分为多个较小的项目。

我们在一个项目中有一些帮助方法来创建速记和键入安全图像请求...这样做的原因是在主题方面具有灵活性。也许一个主题 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 实际上可以是此包中的任何类,从技术上讲,您也可以转到另一个包并以这种方式共享其资源。

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

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

未来大部分请求将来自拥有自己资产的项目。

例如,我见过 file: String = #file

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

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

感谢您的宝贵时间

【问题讨论】:

    标签: swift bundle xcasset


    【解决方案1】:

    “自动调用函数的包”

    尽管这听起来很吸引人,但您真的不希望这样。当您发现将一些代码从一个项目复制/粘贴到另一个项目时会导致其行为不同的那一刻,就是您失去理智的那一刻。

    相反,我认为整个方法都需要重新设计。一方面,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. 您有一个进入图像系统的单一入口点,允许您处理缓存、主题化、大小调整等。
    3. 您可以扩展它以处理对多个包的查找(“首先搜索我的应用包,如果没有,请尝试此框架的包”)
    4. 您可以扩展它以使用枚举来识别图像,而不是原始字符串。

    【讨论】:

    • 是的,这是一个非常重要的观点,我认为为了更简单的语法而试图猜测的道路太过分了。我认为在设置主题时,一个单独的类可能对我的实现(你还没有看到)来说有点太多了,我会要求提供能保存你的资产的捆绑包,它会完美地工作。谢谢你的理智。
    • “我认为一个单独的类对于我的实现来说可能有点太多了”为什么一个类太多了?
    • 我喜欢 UIImage 作为 api 的扩展,提供/弯曲将由主题完成。所以根据主题,我们可以在消费者指定的包中查看。
    • @Magoo 这并没有真正回答我的问题。以这种方式扩展 UIImage 是一种折中的方法,IMO。有一个连续体。一方面,您有一个不使用抽象而只使用原始 API 的位置。它可能不是最简洁的代码,但每个人都看过并熟悉它。另一方面,您将事物抽象化以使其更容易,但有一个初始学习曲线。扩展 UIImage 会使您处于中间位置,双方都有缺点,也没有任何好处
    猜你喜欢
    • 2018-08-05
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-03
    • 2012-10-09
    • 2017-02-15
    相关资源
    最近更新 更多