似乎无法避免在Swift

时间:2015-05-31 17:08:36

标签: swift cocoa nsdata optional nsfilewrapper

更新:这是关于在Xcode中使用基于文档的应用程序模板创建的Mac应用程序,我正在覆盖

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
        }

所以我收到了这个错误

  

可选类型'NSData?'的值没有打开;你的意思是用'!'还是'?'?

我必须要么强制转换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
    }
}

结果是

  

找不到类型'NSMutableAttributedString'的初始值设定项,它接受类型'的参数列表'(数据:NSData ??,选项:[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的结果,如何在没有!的情况下安全地 -in all,获取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
            }
        }
    }
}

编译器给出了这个错误:

  

条件绑定中的绑定值必须是可选类型

关于fileWrapper.fileWrappers

fileWrapper变量是方法的参数,即

override func readFromFileWrapper(fileWrapper: NSFileWrapper, ofType typeName: String, error outError: NSErrorPointer) -> Bool

2 个答案:

答案 0 :(得分:1)

你的专栏:

files["textFile.rtf"]?.regularFileContents

返回一个双重包装的可选项。一个用于字典查找,一个用于.regularFileContents。当你执行if let时,你打开了一次:这就是你错误的原因:

// Value of optional type 'NSData?' not unwrapped; did you mean to use '!' or '?'?

但是,在你的第二个版本中,如果rtfData为零,你只需检查 - 你不打开它:

if (rtfData != nil)

这为你提供了双重包装的选项。

解决问题的最简单方法是使用flatMap

if let rtfData = files["textFile.rtf"].flatMap({$0.regularFileContents}) {
    text = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil)
    return true
}

flatMap接受一个可选项,然后将其解包并将其放入返回可选项的函数中。如果原始可选项或从函数返回的值计算为nil,则整个事物的计算结果为nil。但它返回的价值只是单独包裹。

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两次。

答案 1 :(得分:1)

您可以先为文件使用可选绑定,然后从那里继续:

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)
    }
}