Swiftのコンポーネント化されたリソース管理

コンポーネント化されたリソースファイル管理スキームを学習した後のまとめ

起因

コンポーネント化する前は、すべてのコードとリソースファイルがメインプロジェクトにあり、多数の画像リソースが必然的に名前の競合を引き起こしていました。一般に、名前の競合を避けるために、モジュールの分割に従ってプレフィックスを追加するなど、厳密な命名規則が必要です。

同社はコンポーネント化されたソリューションを採用していますが、リソースファイルが分割されてメインプロジェクトに配置されていないため、コンポーネントとプロジェクトを維持するのは非常に困難です。メインプロジェクトのリソースファイルを対応するポッドに分割し、コンポーネントがそれを単独で管理できるようにします。このように、リソースファイルは各ポッドに分割されます。これにより、責任の分割がより合理的になり、外部の依存関係が減り、独立した操作が容易になります。

CocoaPodsが提供する機能

CocoaPodsは、、、、、これらの機能の選択およびこれらの機能の一部を組み合わせて使用​​した後のリソースファイルの最終的な保存パスを提供し、ユーザーによる画像ファイル、フォントファイル、ローカリゼーションファイル、およびその他のファイルのさまざまな処理をもたらしますuse_frameworks方法は不明です。static_frameworkresourceresource_bundles

組み合わせたシナリオでのリソースファイルのストレージパス

use_frameworks!、、、、およびの組み合わせが異なるstatic_frameworkリソースファイルの最終的なストレージパスが異なります。以下は、さまざまなシナリオでのパスの概要です。resource_bundlesresources

# use_frameworks! 动态库
# static_framework 静态库 podspec文件中不声明,默认为false
# resource_budles 生成独立的bundle
# resources 不生成独立的bundle,放置在.app根目录
# ---------------------------------------------------------------------------
use_frameworks! 
	static_framework = false
		resource_bundles: .app/Frameworks/pod_name.framework/pod_name.bundle/.
		resources: .app/Frameworks/pod_name.framework/.
	static_framework = true
		resource_bundles: .app/pod_name.bundle/.
		resources: .app/.

# use_frameworks!
	static_framework = false
		resource_bundles: .app/pod_name.bundle/.
		resources: .app/.
	static_framework = true
		resource_bundles: .app/pod_name.bundle/.
		resources: .app/.
复制代码

(.app /。はメインバンドルを表します)

さまざまなパスでの画像値の方法と違いについては、この記事を参照してください:[CocoaPodsリソース管理とアセットカタログの最適化](dreampiggy.com/2018/11/26/…カタログの最適化/)

ポッド内のタイプリソースファイルが最終的にメインバンドルに保存されると、メインプロジェクトのファイルと競合し、コンパイルでエラーが報告.xcassetsれることに注意してください。.xcassets

error: Multiple commands produce ‘/Users/gonghonglou/Library/Developer/Xcode/DerivedData/HoloResource-giqfnwiluvssbzbyvuhpkrjoewvd/Build/Products/Debug-iphonesimulator/HoloResource_Example.app/Assets.car’: \1) Target ‘HoloResource_Example’ (project ‘HoloResource’) has compile command with input ‘/Users/gonghonglou/holo/HoloResource/Example/HoloResource/Images.xcassets’ \2) That command depends on command in Target ‘HoloResource_Example’ (project ‘HoloResource’): script phase “[CP] Copy Pods Resources”

解决方法,在 Podfile 里添加:

install! 'cocoapods', :disable_input_output_paths => true
复制代码

Tip: resource+不使用use_frameworks! +assets时会编译失败,因为工程只会生成一份Assets.car文件

Showing All Messages

2022-03-26 20:42:51.046 ibtoold[25007:9169669] Launching AssetCatalogSimulatorAgent using native architecture.

/* com.apple.actool.errors */

:エラー:「AppIcon」という名前の複数のステッカーアイコンセットまたはアプリアイコンセットインスタンスがあります。

オフトピック:Xcode 10以降、新しいコンパイルシステムが導入されたため、ポッドにコードが変更された場合、プロジェクトに時間内にコンパイルできなくなりました。解決策も上記の方法です。

優先:Xcode10のビルドシステムリリースノート

リソース処理の実践

ImageUIImage

public extension Resource where Base: UIImage {

    /// 加载图片资源
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: s.resource_bundles中设置的名字 一般为组件名
    /// - Returns: description
    static func loadImage(name: String, bundleName: String) -> UIImage? {
        /// 静态库+独立bundle
        var image = loadImage1(name: name, in: bundleName)
        if image == nil {
            /// 动态库+独立bundle
            image = loadImage2(name: name, in: bundleName)
        }
        if image == nil {
            /// 动态库+非独立bundle
            image = loadImage3(name: name, in: bundleName)
        }
        if image == nil {
            // 根目录 .app/
            image = loadImage4(name: name, in: bundleName)
        }
        return image
    }
    
    /// 加载  .app/pod_name.bundle/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadImage1(name: String, in bundleName: String) -> UIImage? {
        let pathComponent = "/\(bundleName).bundle"
        return commonLoadImage(name: name, in: pathComponent)
    }

    /// 加载  .app/Frameworks/pod_name.framework/pod_name.bundle/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadImage2(name: String, in bundleName: String) -> UIImage? {
        let pathComponent = "/Frameworks/\(bundleName).framework/\(bundleName).bundle"
        return commonLoadImage(name: name, in: pathComponent)
    }

    /// 加载.app/Frameworks/pod_name.framework/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadImage3(name: String, in bundleName: String) -> UIImage? {
        let pathComponent = "/Frameworks/\(bundleName).framework"
        return commonLoadImage(name: name, in: pathComponent)
    }

    /// 加载.app/
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadImage4(name: String, in bundleName: String) -> UIImage? {
        return UIImage(named: name)
    }

    fileprivate static func commonLoadImage(name: String, in pathComponent: String) -> UIImage? {
        guard let resourcePath: String = Bundle.main.resourcePath else { return nil }
        let bundlePath = resourcePath + pathComponent
        let bundle = Bundle(path: bundlePath)
        return UIImage(named: name, in: bundle, compatibleWith: nil)
    }

}
复制代码

各コンポーネントUIImage.resource.loadImage(name: "图片名", bundleName: "组件名")呼び出しは、独自のバンドル内の画像にアクセスできます。

ここで説明する4つのパスが優先されます。

1.最初のアクセスは静的ライブラリ+2のパスでありresource_bundles、2番目はuse_frameworks!+ 3を使用するダイナミックライブラリパスであり、 +を使用するダイナミックライブラリパスresource_bundlesは再びアクセスされます4、最後にメインバンドルパスです。use_frameworks!resources

もちろん、最も推奨され、合理的な構成方法は、静的ライブラリを提供し、リソースファイルをresource_bundles格納です。

パスバンドル

この方法で画像をカプセル化できるため、このアイデアを参照して、バンドルを基本的なメソッドとしてカプセル化します。統合されたバンドル呼び出しメソッドを使用すると、他のリソースファイルへのアクセスがはるかに簡単になります。

public extension Resource where Base: Bundle {

    /// 加载图片资源
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: s.resource_bundles中设置的名字 一般为组件名
    /// - Returns: description
    static func loadBundle(in bundleName: String) -> Bundle? {
        var image = loadBundle1(in: bundleName)
        if image == nil {
            image = loadBundle2(in: bundleName)
        }
        if image == nil {
            image = loadBundle3(in: bundleName)
        }
        if image == nil {
            image = loadBundle4(in: bundleName)
        }
        return image
    }

    /// 加载  .app/pod_name.bundle/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadBundle1(in bundleName: String) -> Bundle? {
        let pathComponent = "/\(bundleName).bundle"
        return commonLoadBundle(in: pathComponent)
    }

    /// 加载  .app/Frameworks/pod_name.framework/pod_name.bundle/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadBundle2(in bundleName: String) -> Bundle? {
        let pathComponent = "/Frameworks/\(bundleName).framework/\(bundleName).bundle"
        return commonLoadBundle(in: pathComponent)
    }

    /// 加载.app/Frameworks/pod_name.framework/.
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadBundle3(in bundleName: String) -> Bundle? {
        let pathComponent = "/Frameworks/\(bundleName).framework"
        return commonLoadBundle(in: pathComponent)
    }

    /// 加载.app/
    /// - Parameters:
    ///   - name: 图片名
    ///   - bundleName: 组件名
    /// - Returns: description
    fileprivate static func loadBundle4(in bundleName: String) -> Bundle? {
        return Bundle.main
    }

    fileprivate static func commonLoadBundle(in pathComponent: String) -> Bundle? {
        guard let resourcePath = Bundle.main.resourcePath else { return nil }
        let bundlePath = resourcePath + pathComponent
        let bundle = Bundle(path: bundlePath)
        return bundle
    }

}
复制代码

デモリンクの練習

ありがたい

コンポーネント化されたリソースファイル管理ソリューション

おすすめ

転載: juejin.im/post/7079400388352278564
おすすめ