提问人:user6631314 提问时间:11/12/2020 最后编辑:user6631314 更新时间:11/12/2020 访问量:373
在 Swift 中检查未初始化的非可选值?
Check for uninitialized non optional value in Swift?
问:
我有一些代码已经运行了很长时间,但突然导致运行时崩溃。这可能是因为它第一次获得零值(由于一些故障或其他原因),但无论如何,我的应用程序现在在启动时崩溃。
代码为:
@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 是否未初始化,如果可能的话返回。
感谢您的任何建议。
编辑:
我已经在调用上述方法的方法中尝试了非零测试并通过非零测试。但是,如果您尝试用它做某事,它就会崩溃。此外,在崩溃后在控制台中打印它会产生:(NSString) $R2 = <uninitialized>
这是屏幕截图:
答:
可能是你的 Swift 代码是从 Objective-C 调用的,而 Objective-C 向 Swift 发送 nil。这可以解释为什么你会在链的末端崩溃,只有在实际使用值的地方才会崩溃。
请注意,Objective-C 会很乐意将 nil 值传递给不接受 nil 的 Swift 函数,并且 Swift 也会很乐意将1 该 nil 值转发到只允许非 nil 值的地方,只有在它实际尝试使用该值的地方才会崩溃。
从我在堆栈跟踪中看到的内容来看,这似乎是问题所在:Objective-C 方法调用 Swift 方法,该方法将调用转发给 ,并且当尝试使用该值时,崩溃发生在链中的最后一个函数上。-[IDModel updateCa..]
Utilities.downloadImag...
Utilities.download(surl..
为了将更改的影响降到最低,您可以做的是“重载”函数,一个是 Objective-C 世界的可选函数,另一个是 Swift 世界的函数:surl
@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 类型(如 String、Data)在从 Objective-C 端作为 nil 值发送时以某种方式初始化为空值。
评论
surl
nil
NS...