PAYATHON 2026

Swift 集成 Objective-C HDFC iOS SDK 时崩溃

支付小周

结论

问题不在于 Storyboard 与 XIB 混用,也不是 Bridging Header 导致的。崩溃表明,HDFC SDK 的 Interface Builder 文件与运行时实际加载的 Objective-C 类不一致:

  • Unknown class CreditCardCell:运行时找不到 CreditCardCell 的实现。常见原因是 .m 文件或静态库未被链接,或者 XIB 中的 Custom Class 配置有误。
  • not key value coding-compliant for the key makePaymentButton:XIB 中仍保留名为 makePaymentButton 的 IBOutlet 连接,但实例化的对象没有这个属性,或者连接到了错误的对象。

类加载和 IBOutlet 连接都要修复。只重新拖拽控件引用,或只修改 Bridging Header,都无法解决问题。

先确认 CreditCardCell 确实进入应用

Bridging Header 只是让 Swift 在编译阶段看到 Objective-C 声明。它不会自动编译 .m 文件,也不会自动复制 XIB。

如果 SDK 以源码形式提供,至少应包含:

// CreditCardCell.h
#import <UIKit/UIKit.h>

@interface CreditCardCell : UITableViewCell

@end
// CreditCardCell.m
#import "CreditCardCell.h"

@implementation CreditCardCell

@end

逐项检查:

  1. CreditCardCell.m 已加入当前 App Target。
  2. Target 的 Build Phases → Compile Sources 中包含 CreditCardCell.m。
  3. CreditCardCell.xib 已勾选正确的 Target Membership。
  4. Build Phases → Copy Bundle Resources 中包含 CreditCardCell.xib。
  5. 如果 HDFC SDK 是静态库,对应的 .a 或 framework 已加入 Link Binary With Libraries。
  6. Bridging Header 只需导入需要向 Swift 暴露的头文件:
#import "CreditCardCell.h"
#import "PaymentViewController.h"

如果 SDK 是静态库,类仍未被加载,可以根据 SDK 的打包方式,在 Other Linker Flags 中尝试加入:

-ObjC

先不要使用 -all_load。它可能引发重复符号问题,只有确认静态库存在链接裁剪时才需要考虑。

修正 CreditCardCell.xib 的 Custom Class

打开 CreditCardCell.xib,选中最外层的 table view cell,在 Identity Inspector 中确认:

Class: CreditCardCell

如果 CreditCardCell 是 Objective-C 类,Module 通常留空,或者选择该类实际所属的 framework/module。不要误填 Swift App 的模块名。

还要检查:

  • XIB 的根对象确实是 UITableViewCell。
  • Reuse Identifier 与代码中使用的标识一致。
  • Custom Class 没有误配到 File's Owner、Content View 或其他对象。
  • XIB 中的类名与 Objective-C 类名大小写完全一致。

可以用下面的代码检查 Objective-C 运行时能否找到该类:

if NSClassFromString("CreditCardCell") == nil {
    assertionFailure("CreditCardCell has not been linked into the application")
}

如果 SDK 将类放在动态 framework 中,运行时名称也可能带有模块前缀。具体名称由 SDK 的打包方式决定,不能只根据 Bridging Header 判断。

正确加载 Cell 的 XIB

如果由项目代码注册这个 Cell,应从包含该类和 XIB 的 bundle 加载,不要固定使用 Bundle.main:

let sdkBundle = Bundle(for: CreditCardCell.self)
let nib = UINib(nibName: "CreditCardCell", bundle: sdkBundle)

tableView.register(
    nib,
    forCellReuseIdentifier: "CreditCardCell"
)

使用时:

guard let cell = tableView.dequeueReusableCell(
    withIdentifier: "CreditCardCell",
    for: indexPath
) as? CreditCardCell else {
    fatalError("CreditCardCell.xib or its reuse identifier is configured incorrectly")
}

如果 XIB 位于独立的 resource bundle 中,就要从对应的 resource bundle 加载,不能用上面的 Bundle(for:) 假设资源和类位于同一个 bundle。

修复 makePaymentButton 连接

NSUnknownKeyException 表示 XIB 解档时尝试执行类似操作:

[object setValue:button forKey:@"makePaymentButton"];

但 object 对应的类没有 makePaymentButton 属性。

打开崩溃时加载的所有相关 XIB,重点检查 Payment Screen 的主 XIB 和 CreditCardCell.xib。在 Connections Inspector 中查找 makePaymentButton,再根据按钮的实际归属进行处理。

按钮属于 Payment View Controller

控制器头文件应声明这个 IBOutlet:

// PaymentViewController.h
@interface PaymentViewController : UIViewController

@property (weak, nonatomic) IBOutlet UIButton *makePaymentButton;

@end

XIB 中应这样配置:

  • 将 File's Owner 的 Custom Class 设置为 PaymentViewController。
  • 将按钮连接到 File's Owner 的 makePaymentButton。
  • 不要将这个连接挂到 CreditCardCell、根 UIView 或其他对象上。

创建控制器时也要使用正确的 bundle:

let bundle = Bundle(for: PaymentViewController.self)

let paymentViewController = PaymentViewController(
    nibName: "PaymentViewController",
    bundle: bundle
)

navigationController?.pushViewController(
    paymentViewController,
    animated: true
)

按钮确实属于 CreditCardCell

属性必须声明在 Cell 类中:

// CreditCardCell.h
@interface CreditCardCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UIButton *makePaymentButton;

@end

XIB 中的连接应从 CreditCardCell 根对象连到按钮,而不是从 File's Owner 连接。

当前代码已经删除该属性

如果新版类中已没有 makePaymentButton,需要在 Connections Inspector 中删除 XIB 残留的旧连接。这类失效连接旁通常会出现黄色警告标志。

只删除代码中的属性还不够。XIB 仍会保存旧的 outlet 名称,并在运行时尝试为它赋值。

如果修改后仍然崩溃

检查 SDK 的文件是否来自同一版本。以下组合都会直接引发这类异常:

  • 新版 Objective-C 类搭配旧版 XIB。
  • 旧版静态库搭配新版资源文件。
  • App 中存在两个同名的 CreditCardCell.xib。
  • 主工程复制了一份 SDK 的 XIB,同时 framework 内又包含另一份。
  • XIB 连接的是 makePaymentButton,但实际属性已经改名。
  • SDK 的类实现没有被链接,导致 XIB 被当作基础 UIKit 对象加载,随后在设置 outlet 时崩溃。

清理这些问题后,执行一次 Clean Build Folder,删除 App 并重新安装,排除构建产物中仍残留旧资源的情况。

正确状态是:运行时能够解析 CreditCardCell,XIB 从正确的 bundle 加载,makePaymentButton 也只连接到真正声明该 IBOutlet 的对象。

备注:内容仅供参考。