CampaignViewController Investigation Report
Issue
"Unknown class CampaignViewController in Interface Builder file" error when using SPM, while XIB files work perfectly.
Investigation Findings
1. Package.swift Analysis
✅ GOOD: CampaignViewController.swift
is properly included in SPM target
- File location:
SwiftWarplyFramework/SwiftWarplyFramework/screens/CampaignViewController.swift
- SPM path:
"SwiftWarplyFramework/SwiftWarplyFramework"
- The file is automatically included since no explicit
sources
parameter excludes it
2. File Structure Comparison
✅ GOOD: File is in correct location
-
CampaignViewController.swift
is inscreens/
directory (same as other working controllers) - Other working controllers:
ProfileViewController
,CouponViewController
,MyRewardsViewController
3. Class Declaration Analysis
❌ PROBLEM IDENTIFIED: Missing Convenience Initializer
CampaignViewController.swift:
@objc public class CampaignViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler, CLLocationManagerDelegate, WKUIDelegate, UIScrollViewDelegate {
@IBOutlet weak var webview: WKWebView!
// NO convenience initializer for storyboard loading
// NO explicit bundle handling
}
ProfileViewController.swift (WORKING):
@objc public class ProfileViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
// MARK: - Initializers
public convenience init() {
self.init(nibName: "ProfileViewController", bundle: Bundle.frameworkBundle)
}
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
4. Key Differences
Aspect | CampaignViewController | ProfileViewController (Working) |
---|---|---|
Convenience Init | ❌ Missing | ✅ Present with Bundle.frameworkBundle |
Bundle Handling | ❌ No explicit bundle | ✅ Uses Bundle.frameworkBundle |
Storyboard vs XIB | 📱 Storyboard-based | 📄 XIB-based |
Class Declaration | ✅ Public | ✅ Public |
Access Modifiers | ✅ Correct | ✅ Correct |
5. Root Cause Analysis
The issue is NOT with SPM inclusion but with bundle resolution for storyboard-based view controllers.
Why XIB controllers work:
- XIB controllers have explicit
Bundle.frameworkBundle
initializers - They handle bundle resolution correctly for SPM
Why CampaignViewController fails:
- Storyboard tries to instantiate the class but can't resolve the correct bundle
- No convenience initializer to guide bundle resolution
- SPM creates different bundle structure than CocoaPods
6. Bundle Structure Difference
CocoaPods:
- Bundle:
SwiftWarplyFramework.framework
- Storyboard can find classes easily
SPM:
- Bundle:
SwiftWarplyFramework_SwiftWarplyFramework.bundle
- Storyboard needs explicit bundle guidance
Recommended Solutions
Option 1: Add Bundle-Aware Initializers (Recommended)
Add the missing initializers to CampaignViewController.swift
:
// MARK: - Initializers
public convenience init() {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.frameworkBundle)
let vc = storyboard.instantiateViewController(withIdentifier: "CampaignViewController")
// Handle initialization properly
}
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
Option 2: Convert to XIB-based (Alternative)
Convert CampaignViewController
from storyboard to XIB format like other controllers.
Option 3: Update Storyboard Loading Code
Ensure any code that loads the storyboard uses Bundle.frameworkBundle
:
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.frameworkBundle)
let vc = storyboard.instantiateViewController(withIdentifier: "CampaignViewController")
Conclusion
The issue is specifically with storyboard bundle resolution in SPM, not with class inclusion or module specifications. The XIB files work because they have proper bundle-aware initializers, while the storyboard-based CampaignViewController
lacks this SPM-compatible initialization pattern.