Displaced Hoser
Displaced Hoser

Reputation: 911

Can't unwrap optional without forced unwrapping/nil error

I'm working on a text editor and am having trouble with string optionals. I want to use a textView's string method; since it's an optional, Xcode insists that I unwrap it. When I use forced unwrapping (which is what Xcode recommends) I get runtime errors; I'd prefer to use optional chaining so that nil values don't cause a crash. But I can't get optional chaining to work.

To get open and save working, I'm trying to use self.textViewOne.string = self.text in windowControllerDidLoadNib and self.text = self.textViewOne.string in dataOfType. But I get crashes of "unexpectedly found nil while unwrapping an Optional value". Documentation tells me I should use if-let or even if-var to do this properly, but I can't; when I try to add if-let or if-var, I get an "Expected pattern" error, probably because the self.text variable already exists - but I don't know how else to unwrap properly.

In dataOfType I even tried to unwrap it with a kludgey regular if-then statement:

if ((self.textViewOne.string) != nil)
{
    self.text = self.textViewOne.string
}
else
{
   self.text = ""
}

but even that doesn't work: Xcode still insists on a ! after self.textViewOne.string, and with or without the ! I still get a "fatal error: unexpectedly found nil while unwrapping an Optional value".

EDIT: Here's the complete code for the Document class as it currently stands (including a bit of tinkering after the original post, but still getting the error):

import Cocoa

class Document: NSDocument {

@IBOutlet var textViewOne: NSTextView!

@IBOutlet var textViewTwo: NSTextView!

var text = ""

override init() {
    super.init()
    // Add your subclass-specific initialization here.
}

override func windowControllerDidLoadNib(aController: NSWindowController) {

    // The window has loaded, and is ready to display.
    // Take the text that we loaded earlier and display it in the text field

    super.windowControllerDidLoadNib(aController)

    self.textViewOne.string = self.text

}

override class func autosavesInPlace() -> Bool {
    return true
}

override var windowNibName: String? {
    // Returns the nib file name of the document
    // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this property and override -makeWindowControllers instead.
    return "Document"
}

override func dataOfType(typeName: String?, error outError: NSErrorPointer) -> NSData? {

    // Convert the contents of the text field into data, and return it

    if (self.textViewOne == nil)
    {
        println ("self.textViewOne is nil.")
    }

    if let someText = self.textViewOne.string {
        self.text = someText
    } else {
        self.text = ""
    }

    return self.text.dataUsingEncoding( NSUTF8StringEncoding, allowLossyConversion: false)

}

override func readFromData(data: NSData, ofType typeName: String?, error outError: NSErrorPointer) -> Bool {

    // Attempt to load a string from the data; if it works, store it in self.text

    if data.length > 0
    {
        let string = NSString( data: data, encoding: NSUTF8StringEncoding)
        self.text = string!
    }
    else
    { self.text = "" }

    return true

 }

}

Upvotes: 0

Views: 946

Answers (1)

JAL
JAL

Reputation: 42489

What about using an if let to unwrap a non-nil value from self.textViewOne?

if let someText = self.textViewOne.string {
    self.text = someText
} else {
    self.text = ""
}

Upvotes: 3

Related Questions