似乎无法避免在 Swift 中强制展开
Can’t seem to avoid force unwrapping in Swift
更新:这是关于 Mac 使用 Xcode 中基于文档的应用程序模板创建的应用程序,我正在覆盖
override func readFromFileWrapper(fileWrapper: NSFileWrapper, ofType typeName: String, error outError: NSErrorPointer) -> Bool
我正在尝试从 NSFileWrapper 中读取一个文件,似乎我无法避免其中至少有一个 !
。
首先,我尝试了
if let rtfData = files["textFile.rtf"]?.regularFileContents,
newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
所以我得到这个错误
Value of optional type 'NSData?' not unwrapped; did you mean to use '!' or '?'?
而且我必须强制转换 regularFileContents as NSData!
或者我必须在 NSMutableAttributedString 的初始化程序 (data: rtfData!
) 中强制解包它。
然后我尝试了
let rtfData = files["textFile.rtf"]?.regularFileContents
if (rtfData != nil) {
if let newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
}
这导致
Cannot find an initializer for type 'NSMutableAttributedString' that accepts an argument list of type '(data: NSData??, options: [String : String], documentAttributes: nil, error: nil)'"
所以我必须将初始化程序更改为 data: rtfData!!
,我什至不确定 是什么意思。
或者,我可以强制转换 regularFileContents as NSData?
,然后我只能在初始化程序中使用一个 !
。
更新:这是自发布以来我尝试过的另一件事。我认为 NSData??
中的双 ?
可能是由于我有选择地展开 NSFileWrapper (files["textFile.rtf"]?
) 所以我尝试了这个:
if let rtfWrapper = files["textFile.rtf"],
rtfData = rtfWrapper.regularFileContents,
newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
编译器仍然要我强制解包 NSData。
我很困惑。
什么是NSData??
,为什么它是“双重”可选的,为什么它是.regularFileContents
的结果,我如何安全,而不!
-一路走来,获取NSData并将其传递给NSMutableAttributedString的初始化器?
另一个更新
我认为 files
常量可能是另一个可选包装的来源:
let files = fileWrapper.fileWrappers
但是编译器不允许我 if let
它。例如,如果我尝试
if let files = fileWrapper.fileWrappers {
if let rtfFile = files["textFile.rtf"] {
if let rtfData = rtfFile.regularFileContents {
if let newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
}
}
}
编译器报错:
Bound value in a conditional binding must be of Optional type
关于fileWrapper.fileWrappers
fileWrapper
变量是方法的一个参数,即
override func readFromFileWrapper(fileWrapper: NSFileWrapper, ofType typeName: String, error outError: NSErrorPointer) -> Bool
你的线路:
files["textFile.rtf"]?.regularFileContents
Returns 双重包装可选。一种用于查字典,一种用于.regularFileContents
。当您执行 if let
时,您解包了一次:这就是为什么您的错误是:
// Value of optional type 'NSData?' not unwrapped; did you mean to use '!' or '?'?
但是,在你的第二个版本中,如果 rtfData
为 nil,你只需 检查 - 你不打开它:
if (rtfData != nil)
这为您提供了双重包装选项。
绕过它的最简单方法是使用 flatMap
:
if let rtfData = files["textFile.rtf"].flatMap({[=13=].regularFileContents}) {
text = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil)
return true
}
flatMap
接受一个可选的,并将其解包以将其放入 returns 一个可选的函数中。如果原始可选值或函数返回的值的计算结果为 nil,则整个事物的计算结果为 nil。但是它的值 returns 只是单独包装的。
flatMap
所做的基本上是:
if let lookup = files["textFile.rtf"] {
if let rtfData = lookup.regularFileContents {
let newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil)
text = newString
return true
}
}
这段代码也可以。两种方法都可以安全地解包 rtfData
两次。
您可以先对文件使用可选绑定,然后从那里继续:
if let file = files["textFile.rtf"],
contents = file.regularFileContents,
newString = NSMutableAttributedString(data: contents, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
如果您使用的是 fileWrappers
词典([NSObject : AnyObject]
),则必须进行一些额外的转换。这个例子使用的是我碰巧在那个文件包装器中的文件,但希望它能说明这个想法:
var text: NSString!
func someMethod(fileWrapper: NSFileWrapper) {
let files = fileWrapper.fileWrappers
if let file = files["test.json"] as? NSFileWrapper,
contents = file.regularFileContents,
newString = NSString(data: contents, encoding: NSUTF8StringEncoding) {
text = newString
println(text)
}
}
更新:这是关于 Mac 使用 Xcode 中基于文档的应用程序模板创建的应用程序,我正在覆盖
override func readFromFileWrapper(fileWrapper: NSFileWrapper, ofType typeName: String, error outError: NSErrorPointer) -> Bool
我正在尝试从 NSFileWrapper 中读取一个文件,似乎我无法避免其中至少有一个 !
。
首先,我尝试了
if let rtfData = files["textFile.rtf"]?.regularFileContents,
newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
所以我得到这个错误
Value of optional type 'NSData?' not unwrapped; did you mean to use '!' or '?'?
而且我必须强制转换 regularFileContents as NSData!
或者我必须在 NSMutableAttributedString 的初始化程序 (data: rtfData!
) 中强制解包它。
然后我尝试了
let rtfData = files["textFile.rtf"]?.regularFileContents
if (rtfData != nil) {
if let newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
}
这导致
Cannot find an initializer for type 'NSMutableAttributedString' that accepts an argument list of type '(data: NSData??, options: [String : String], documentAttributes: nil, error: nil)'"
所以我必须将初始化程序更改为 data: rtfData!!
,我什至不确定 是什么意思。
或者,我可以强制转换 regularFileContents as NSData?
,然后我只能在初始化程序中使用一个 !
。
更新:这是自发布以来我尝试过的另一件事。我认为 NSData??
中的双 ?
可能是由于我有选择地展开 NSFileWrapper (files["textFile.rtf"]?
) 所以我尝试了这个:
if let rtfWrapper = files["textFile.rtf"],
rtfData = rtfWrapper.regularFileContents,
newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
编译器仍然要我强制解包 NSData。
我很困惑。
什么是NSData??
,为什么它是“双重”可选的,为什么它是.regularFileContents
的结果,我如何安全,而不!
-一路走来,获取NSData并将其传递给NSMutableAttributedString的初始化器?
另一个更新
我认为 files
常量可能是另一个可选包装的来源:
let files = fileWrapper.fileWrappers
但是编译器不允许我 if let
它。例如,如果我尝试
if let files = fileWrapper.fileWrappers {
if let rtfFile = files["textFile.rtf"] {
if let rtfData = rtfFile.regularFileContents {
if let newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
}
}
}
编译器报错:
Bound value in a conditional binding must be of Optional type
关于fileWrapper.fileWrappers
fileWrapper
变量是方法的一个参数,即
override func readFromFileWrapper(fileWrapper: NSFileWrapper, ofType typeName: String, error outError: NSErrorPointer) -> Bool
你的线路:
files["textFile.rtf"]?.regularFileContents
Returns 双重包装可选。一种用于查字典,一种用于.regularFileContents
。当您执行 if let
时,您解包了一次:这就是为什么您的错误是:
// Value of optional type 'NSData?' not unwrapped; did you mean to use '!' or '?'?
但是,在你的第二个版本中,如果 rtfData
为 nil,你只需 检查 - 你不打开它:
if (rtfData != nil)
这为您提供了双重包装选项。
绕过它的最简单方法是使用 flatMap
:
if let rtfData = files["textFile.rtf"].flatMap({[=13=].regularFileContents}) {
text = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil)
return true
}
flatMap
接受一个可选的,并将其解包以将其放入 returns 一个可选的函数中。如果原始可选值或函数返回的值的计算结果为 nil,则整个事物的计算结果为 nil。但是它的值 returns 只是单独包装的。
flatMap
所做的基本上是:
if let lookup = files["textFile.rtf"] {
if let rtfData = lookup.regularFileContents {
let newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil)
text = newString
return true
}
}
这段代码也可以。两种方法都可以安全地解包 rtfData
两次。
您可以先对文件使用可选绑定,然后从那里继续:
if let file = files["textFile.rtf"],
contents = file.regularFileContents,
newString = NSMutableAttributedString(data: contents, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
如果您使用的是 fileWrappers
词典([NSObject : AnyObject]
),则必须进行一些额外的转换。这个例子使用的是我碰巧在那个文件包装器中的文件,但希望它能说明这个想法:
var text: NSString!
func someMethod(fileWrapper: NSFileWrapper) {
let files = fileWrapper.fileWrappers
if let file = files["test.json"] as? NSFileWrapper,
contents = file.regularFileContents,
newString = NSString(data: contents, encoding: NSUTF8StringEncoding) {
text = newString
println(text)
}
}