简体   繁体   中英

Swift Package Manager - Setting Custom Classes in storyboard in package fails

I am trying to implement a support for Swift Package Manager for an iOS framework that we used to link in our main project with Carthage. The framework's name is "OptionsSheetKit"

The framework contained a UIViewController that is a replica of UIAlertController with the .sheet appearance, and a storyboard that has the view controller's design.

When i make an instance of the view controller from within the framework like this:

let content = UIStoryboard(name: "OptionsSheet", bundle: .module).instantiateViewController(withIdentifier: PickerViewController.identifier) as? PickerViewController

The app compiles and runs however all custom set classes are no longer set and i get this warning in the debug area of XCode:

2021-02-23 17:19:15.606835+0200 OptionsSheetKitExample[23732:6479875] [Storyboard] Unknown class _TtC31OptionsSheetKit_OptionsSheetKit19SheetViewController in Interface Builder file.
2021-02-23 17:19:15.607631+0200 OptionsSheetKitExample[23732:6479875] [Storyboard] Unknown class _TtC31OptionsSheetKit_OptionsSheetKit19SheetViewController in Interface Builder file.
2021-02-23 17:19:15.608020+0200 OptionsSheetKitExample[23732:6479875] [Storyboard] Unknown class _TtC31OptionsSheetKit_OptionsSheetKit19SheetViewController in Interface Builder file.
2021-02-23 17:19:15.608378+0200 OptionsSheetKitExample[23732:6479875] [Storyboard] Unknown class _TtC31OptionsSheetKit_OptionsSheetKit19SheetViewController in Interface Builder file.
2021-02-23 17:19:15.608776+0200 OptionsSheetKitExample[23732:6479875] [Storyboard] Unknown class _TtC31OptionsSheetKit_OptionsSheetKit19SheetViewController in Interface Builder file.

My Package.swift looks like this:

// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "OptionsSheetKit",
    platforms: [
        .iOS(.v12)
    ],
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "OptionsSheetKit",
            targets: ["OptionsSheetKit"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "OptionsSheetKit",
            dependencies: []),
    ]
)

This is how the class is set in the storyboard, but it fails to find it.

故事板自定义类

Maybe it fails to get the module right.

I know that for SwiftPM .storyboard is a known file, and it automatically makes a resource bundle for the package, and i can see that resource bundle in the app's main bundle with file name OptionsSheetKit_OptionsSheetKit.bundle , i know its bundle identifier has to be OptionsSheetKit-OptionsSheetKit-resources , so its all in there.

The only way i managed to make it work is by instantiating the ViewController with the iOS 13+ method UIStoryboard.instantiateViewController(identifier: String, creator: NSCoder) but its a workaround which as i had to do that not only for the view controller, but for each and every custom class i have set inside the controller's views, which makes the storyboard pointless.

Whats' more is that the app's min deployment target is iOS 12.2, so this will not cut it for me.

Do you guys have an idea why this fails? I tried setting the type parameter in the library's product to .dynamic as i know dynamic frameworks can have resources in their bundles, as i did that before, tried the .static type too, but couldn't make it work either way.

Is this a known bug, or simply SwiftPM still does not support this?

Thanks in advance!

I managed to fix it by adding @objc name in my view controller's class definition and use that name instead in the storyboard.

@objc(OBJCPickerViewController)
public final class PickerViewController { ... }

Thats how i used the OBJCPickerViewController name inside the storyboard

在此处输入图像描述

And all worked nice. I think the reason this works is because in Objective C there are no modules( thats why @objc classes have prefixes in their names ) and with @objc you are basically bypassing the class/module name mangling, making it really easy for storyboards to find your class.

I found out the solution here , so shout out to Marius Ilie for writing this down!

If any of you could propose a more elegant solution, please let me know so we could stop relying on objc to save us in our swift code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM