Update: this is regarding a Mac app created with the Document-based Application template in Xcode, and I’m overriding
override func readFromFileWrapper(fileWrapper: NSFileWrapper, ofType typeName: String, error outError: NSErrorPointer) -> Bool
I’m trying to read in a file from an NSFileWrapper and it seems like I can't get away from having at least one !
in there.
First, I tried
if let rtfData = files["textFile.rtf"]?.regularFileContents,
newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
So I get this error
Value of optional type 'NSData?' not unwrapped; did you mean to use '!' or '?'?
And I have to either cast regularFileContents as NSData!
or I have to force unwrap it in the NSMutableAttributedString's initializer (data: rtfData!
).
So then I tried
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
}
}
Which results in
Cannot find an initializer for type 'NSMutableAttributedString' that accepts an argument list of type '(data: NSData??, options: [String : String], documentAttributes: nil, error: nil)'"
So I have to change the initializer to say data: rtfData!!
, which I'm not even sure what that means.
Or, I can cast regularFileContents as NSData?
, and then I can only use one !
in the initializer.
Update: Here's another thing I’ve tried since posting. I figured the double ?
in NSData??
could be due to me optionally unwrapping the NSFileWrapper (files["textFile.rtf"]?
) so I tried this:
if let rtfWrapper = files["textFile.rtf"],
rtfData = rtfWrapper.regularFileContents,
newString = NSMutableAttributedString(data: rtfData, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
The compiler still wants me to force unwrap NSData.
I am pretty thoroughly confused.
What is NSData??
, why is it “doubly” optional, why is it the result of .regularFileContents
, and how can I safely, without !
-ing all the way, get the NSData and pass it to the NSMutableAttributedString’s intializer?
Another update
I figured maybe the files
constant could be the source of another optional wrapping:
let files = fileWrapper.fileWrappers
But the compiler won't let me if let
it. If I try, for example,
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
}
}
}
}
The compiler gives this error:
Bound value in a conditional binding must be of Optional type
About fileWrapper.fileWrappers
The fileWrapper
variable is a parameter of the method, which is
override func readFromFileWrapper(fileWrapper: NSFileWrapper, ofType typeName: String, error outError: NSErrorPointer) -> Bool
You can use optional binding for the file first, and then proceed from there:
if let file = files["textFile.rtf"],
contents = file.regularFileContents,
newString = NSMutableAttributedString(data: contents, options: [NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType], documentAttributes: nil, error: nil) {
text = newString
return true
}
If you're using fileWrappers
dictionary (a [NSObject : AnyObject]
), you have to do some additional casting. This example is using a file I happen to have in that file wrapper, but hopefully it illustrates the idea:
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)
}
}