检查 Swift 中未初始化的非可选值?

Check for uninitialized non optional value in Swift?

我有一些代码已经运行了很长时间但突然导致运行时崩溃。这可能是因为这是它第一次获得 nil 值(由于某些故障或其他原因),但无论如何我的应用程序现在在启动时崩溃。

密码是:

 @objc func download(surl: NSString, completion : @escaping (NSData) -> Void ) {
print("surl to download is:",surl)//CRASHES HERE if surl is uninitialized.

它在错误指示的行上崩溃:

Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)

运行时出现错误的控制台截图如下:

这是调试器中的一行,它在崩溃时表示它已“统一化”。

如果 surl 是非可选的,是否还有检查未初始化的情况?

我不愿意将 surl 更改为可选的,因为此方法在应用程序中有很多地方被调用,我担心在方法中更改它会导致其他问题中断。

所以想找出一种方法来测试 surl 是否未初始化,return 如果可能的话。

感谢您的任何建议。

编辑:

我在调用上述方法的方法中尝试了not nil的测试,并通过了not nil测试。但是如果你试图用它做一些事情,它就会崩溃。此外,在崩溃后在控制台中打印它会给出:(NSString) $R2 = <uninitialized>

截图如下:

可能是您的 Swift 代码是从 Objective-C 调用的,并且 Objective-C 将 nil 发送到 Swift。这可以解释为什么你会在链的末尾崩溃,只有在实际使用该值的地方。

请注意,Objective-C 将愉快地将 nil 值传递给不接受 nil 的 Swift 函数,并且 Swift 将愉快地转发 1 nil 值到只允许非 nil 的地方,仅在它实际尝试使用该值的地方崩溃。

从我在你的堆栈跟踪中看到的,这似乎是问题所在:Objective-C -[IDModel updateCa..] 方法调用 Utilities.downloadImag... Swift 方法,它转发对 Utilities.download(surl.. 的调用,当尝试使用该值时,链中的最后一个函数发生崩溃。

为了将更改的影响降到最低,您可以做的是“重载”函数,一个带有可选的 surl 用于 Objective-C 世界,另一个用于Swift 世界:

@objc(download) func objcDownload(surl: NSString?, completion : @escaping (NSData) -> Void ) {
    guard let surl = surl else {
        // handle this problems
        return
    }
    // forward to the worker function
    download(surl: surl, completion: completion)
}

// @nonobjc might not be needed, depending of the class declaration
// but being explicit doesn't hurt
@nonobjc func download(surl: NSString, completion : @escaping (NSData) -> Void ) {
    // same code, no changes needed
}

这样:

  • Objective-C 代码将看到相同的功能,无需更改
  • Objective-C 桥的 Swift 实现可以检查 nils
  • Swift代码仍然可以使用,现在@nonobjc下载功能。

如果你不相信我关于从 Objective-C 传递到 Swift 的 nil 值,这里有一个例子来证明这一点:

// in a header file, imported in the bridging header
@interface ObjCWorker: NSObject

+ (void)sendNilToSwift;

@end

// in the corresponding .m file
@implementation ObjCWorker

+ (void)sendNilToSwift {
    NSString *shouldNotBeNil = nil;
    [SwiftWorker doWorkWithNonNull:shouldNotBeNil];
}
@end
// in a Swift file
class SwiftWorker: NSObject {
    
    @objc static func doWork(with string: NSString) {
        delegateWorkToSomeOtherMethod(string)
    }
    
    static func delegateWorkToSomeOtherMethod(_ string: NSString) {
        delegateWorkToAnotherMethod(string)
    }
    
    static func delegateWorkToAnotherMethod(_ string: NSString) {
        print(string)
    }
}

现在,只要写 ObjCWorker.sendNilToSwift(),你就会发生完全相同的崩溃。

1请注意,这目前仅适用于 Objective-C 参数:NSString、NSData、...、桥接 Swift 类型,例如字符串、数据当它们从 Objective-C 端作为 nil 值发送时,用空值初始化。