是否可以从 swift 包中加载 nib 文件?

问题描述

我创建了一个 UICollectionView Xib 文件和类文件作为 swift 包。可以访问类文件中的方法,但在我的项目中加载 nib 文件时出现错误

链接https://github.com/PranayChander/package1

项目链接https://github.com/PranayChander/packman

导入 UIKit 导入包1

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.register(UINib(nibName: "PackageCollectionViewCell",bundle: nil),forCellWithReuseIdentifier: "cell")
    }
}

extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView,numberOfItemsInSection section: Int) -> Int {
        return 10
    }
    
    func collectionView(_ collectionView: UICollectionView,cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell",for: indexPath) as! PackageCollectionViewCell
        cell.configureCell(title: "Pram",subtitle: "dasd")
        return cell
    }
}


import UIKit

open class PackageCollectionViewCell: UICollectionViewCell {
    @IBOutlet open weak var titleLabel: UILabel!
    @IBOutlet open weak var subtitleLabel: UILabel!
    
    open override func awakeFromNib() {
        super.awakeFromNib()
    }
    
    open func configureCell(title: String,subtitle: String) {
        self.titleLabel.text = title
        self.subtitleLabel.text = subtitle
    }
}

Stach 跟踪: 2020-12-21 14:20:37.806065+0530 packman[4341:195092] *** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无法在捆绑包中加载 NIB:”NSBundle /Library /Developer/CoreSimulator/Devices/B98131CA-B121-42B2-A0F5-FC48066C3179/data/Containers/Bundle/Application/95A42061-D137-4F35-94CE-58B8915189C6(name'Collection'Packed'Packed'Packed' *** 首先抛出调用堆栈: ( 0 核心基金会 0x00007fff20420af6 __exceptionPreprocess + 242 1 libobjc.A.dylib 0x00007fff20177e78 objc_exception_throw + 48 2 核心基金会 0x00007fff204209d4 -[NSException initWithCoder:] + 0 3 UIKitCore 0x00007fff24290813 -[UINib instantiateWithOwner:options:] + 495 4 UIKitCore 0x00007fff23d864db -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewCategory:] + 907 5 UIKitCore 0x00007fff23d86bdb -[UICollectionView dequeueReusableCellWithReuseIdentifier:forIndexPath:] + 88 6 packman 0x000000010e766d19 $s7packman14ViewControllerC010collectionB0_13cellForItemAtSo012UICollectionB4CellCSo0iB0C_10Foundation9IndexPathVtF + 313 7 packman 0x000000010e766ef5 $s7packman14ViewControllerC010collectionB0_13cellForItemAtSo012UICollectionB4CellCSo0iB0C_10Foundation9IndexPathVtFTo + 165 8 UIKitCore 0x00007fff23d71546 -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:isFocused:notify:] + 410 9 UIKitCore 0x00007fff23d713a6 -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:] + 31 10 UIKitCore 0x00007fff23d769cc -[UICollectionView _updateVisibleCellsNow:] + 6148 11 UIKitCore 0x00007fff23d7bc48 -[UICollectionView layoutSubviews] + 351 12 UIKitCore 0x00007fff24bf25b8 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2924 13 QuartzCore 0x00007fff27aa2c33 -[CALayer layoutSublayers] + 258 14 QuartzCore 0x00007fff27aa91a5 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 575 15 QuartzCore 0x00007fff27ab4f47 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 65 16 QuartzCore 0x00007fff279f4408 _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 496 17 QuartzCore 0x00007fff27a2b1ef _ZN2CA11Transaction6commitEv + 783 18 UIKitCore 0x00007fff246ae47e __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 81 19 核心基金会 0x00007fff2038f120 CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK + 12 20 核心基金会 0x00007fff2038e534 __CFRunLoopdoblocks + 434 21 核心基金会 0x00007fff20388f44 __CFRunLoopRun + 899 22 核心基金会 0x00007fff203886d6 CFRunLoopRunSpecific + 567 23 图形服务 0x00007fff2bededb3 GSEventRunModal + 139 24 UIKitCore 0x00007fff24690e0b -[UIApplication _run] + 912 25 UIKitCore 0x00007fff24695cbc UIApplicationMain + 101 26 libswiftUIKit.dylib 0x00007fff54d1e5f2 $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGGSgSSSgAJtF + 98 27 包装工 0x000000010e7677da $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 122 28 包装工 0x000000010e76774e $s7packman11AppDelegateC5$mainyyFZ + 46 29 包装工 0x000000010e767829 主 + 41 30 libdyld.dylib 0x00007fff202593e9 开始 + 1 ) libc++abi.dylib:以未捕获的 NSException 类型异常终止 *** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无法在捆绑包中加载 NIB:”NSBundle /pranaychander/Library/Developer/CoreSimulator/Devices/B98131CA-B121-42B2-A0F5-FC31706 /Containers/Bundle/Application/95A42061-D137-4F35-94CE-58B8915189C6/packman.app>(已加载)',名称为'PackageCollectionViewCell'' 以 NSException 类型的未捕获异常终止 CoreSimulator 732.18.6 - 设备:iPhone 11 Pro (B98131CA-B121-42B2-A0F5-FC48066C3179) - 运行时:iOS 14.3 (18C61) - 设备类型:iPhone 11 Pro

enter image description here

解决方法

您的代码在 NIB 的应用程序包中查找,但找不到(就像在框架包中一样):

无法在捆绑中加载 NIB:'NSBundle /pranaychander/Library/Developer/CoreSimulator/Devices/B98131CA-B121-42B2-A0F5-FC48066C3179/data/Containers/Bundle/Application/914D41376 94CE-58B8915189C6/packman.app>

要么使用框架的标识符来获取正确的包:

let bundle = Bundle(identifier: "com.bundleID.of.the.framework")
collectionView.register(UINib(nibName: "PackageCollectionViewCell",bundle: bundle)....

或者在框架 API 中提供一个工厂函数来获取现成的视图。

,

Apple 在文章 Bundling Resources with a Swift Package

中说

在访问资源时始终使用 Bundle.module。包不应假设资源的确切位置。

所以你应该使用这个静态变量作为包参数。

,

如果您严格发布 SPM 框架,则可以按照推荐使用上面列出的 Bundle.module。但是,如果您像我和其他人一样,仍然需要支持 Pod 等。我将 Bundle.module 拉入我的框架并使用 MyFramework.module 作为我的 Bundle。

public class MyFramework: NSObject {
    static let bundleName = "MyFramework"

    public static let bundle = Bundle(for: Self.self)!

    /// Returns the resource bundle associated with the current Swift module. This is required for SPM use
    public static var module: Bundle = {
        let bundleName = "MyFramework" // May be "MyFramework_MyFramework" for you

        let candidates = [
            // Bundle should be present here when the package is linked into an App.
            Bundle.main.resourceURL,// Bundle should be present here when the package is linked into a framework.
            Bundle(for: MyFramework.self).resourceURL,// For command-line tools.
            Bundle.main.bundleURL
        ]

        for candidate in candidates {
            let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle")
            if let bundle = bundlePath.flatMap(Bundle.init(url:)) {
                return bundle
            }
        }
        return MyFramework.bundle
    }()
}

一旦你有了它,你就可以使用 MyFramework.module