首页 > 解决方案 > 检查 Swift 中未初始化的非可选值?

问题描述

我有一些代码已经运行了很长时间,但突然导致崩溃 ar 运行时。这可能是因为这是它第一次获得 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)

这是运行时发生错误的控制台的屏幕截图在此处输入图像描述

这是调试器中的一行,它说它在崩溃时是“unitiailized”的。

在此处输入图像描述 如果 surl 是非可选的,是否有任何未初始化的检查?

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

所以想找出一种方法来测试 surl 是否未初始化并在可能的情况下返回。

感谢您的任何建议。

编辑:

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

这是屏幕截图:

在此处输入图像描述

标签: iosswiftstringnulloptional

解决方案


可能是您的 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 实现可以检查 nil
  • Swift 代码仍然可以使用 now @nonobjcdownload 功能。

如果你对从 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 类型(如 String、Data)在从 Objective-C 端作为 nil 值发送时以某种方式被初始化为空值。


推荐阅读