0

I'm trying to make this function inside a VC into a function within an extension (because I need to access it in multiple VC's so I'm trying to return the attributedStringWithRtf so i can use it elsewhere.

func populateTextViewWithCurrentScene() {

    let fileURL = getFileURL()

    do {
        let attributedStringWithRtf:NSAttributedString = try NSAttributedString(
            url: fileURL,
            options: [.documentType: NSAttributedString.DocumentType.rtf],
            documentAttributes: nil
        )
        self.textViewOutlet.attributedText = attributedStringWithRtf
    }
    catch {
        print("failed to populate text view with current scene with error: \(error)")

    }

}

So far, I've tried this, following the guide here How could I create a function with a completion handler in Swift? and I've also tried a version declaring a var before the function. The error I'm getting on the below is Cannot call value of non-function type 'NSAttributedString'.

I know there are quite a few questions about this sort of thing but a lot are for old versions of Swift

func populateTextViewWithCurrentScene(rtfString: NSAttributedString) -> Void {

    let fileURL = getFileURL()
    do {
        let rtfString:NSAttributedString = try NSAttributedString(
            url: fileURL,
            options: [.documentType: NSAttributedString.DocumentType.rtf],
            documentAttributes: nil
        )
    }
    catch {
        print("failed to populate text view with current scene with error: \(error)")
    }
    rtfString()
}
nc14
  • 539
  • 1
  • 8
  • 26
  • What's wrong with the first function? The question has nothing to do with completion handlers. – vadian Jun 04 '19 at 16:00
  • 1
    You should read the [Function Parameters and Return Values](https://docs.swift.org/swift-book/LanguageGuide/Functions.html#ID160) section of the Swift book. Note that you have no need for a completion handler. Just a normal return value. – rmaddy Jun 04 '19 at 16:04
  • @vadian I'm wanting to use the output (the attributed string) to then set the .text property of a textView elsewhere in the code. So I need to return (I think) the attributed string .i.e. remove this line.... self.textViewOutlet.attributedText = attributedStringWithRtf so I can use the attributed string on multiple text views in multiple places in the code without writing it all out again – nc14 Jun 04 '19 at 16:04
  • @rmaddy I tried doing that but I can't access attributedStringWithRtf for the return? – nc14 Jun 04 '19 at 16:06
  • Show that attempt in your question. – rmaddy Jun 04 '19 at 16:07

1 Answers1

3

I went ahead and created an extension of UIViewController that should provide what you are looking for. Comments are included for each line to explain the decisions that I made.

Feel free to comment if some part is unclear, or does not work as expected.

import UIKit

// You mentioned wanting to extend your viewcontroller
// so I extend UIViewController to support that
extension UIViewController {
    // Returns an optional NSAttributedString, based upon successfully loading the file contents
    func loadString() -> NSAttributedString? {
        do {
            // Everything is cleaned up into a single return command,
            // including the getFileURL, which can be used as a parameter instead
            // of creating a variable for it
            return try NSAttributedString(url: getFileURL(),
                                          options: [.documentType: NSAttributedString.DocumentType.rtf],
                                          documentAttributes: nil)
        } catch {
            // If this fails, use your existing print command
            print("failed to populate text view with current scene with error: \(error)")
            // and then return nil to indicate that nothing was loaded
            return nil
        }
    }
}

This is building off of the comments below from you and rmaddy.

As referenced in my original comment, the solution was not consolidating the try & return, that was simply to streamline the code.

You can look at the function this way:

"I want to try and open a file that is located at getFileURL(), and would like to use some options I specify with my options: parameter. Since this action can fail, Xcode makes me use try. Assuming that this file is successfully opened, then return the contents back to the caller in the form of an NSAttributedString. However, if this fails, print out a message telling me why it failed and then return a nil to indicate that no data is returned."

CodeBender
  • 35,668
  • 12
  • 125
  • 132
  • 2
    I suggest renaming the method. – rmaddy Jun 04 '19 at 16:08
  • thanks for this one - the key (which I didn't know) was that you can pre-pend try with return (probably a silly omission but still relatively new to coding so I'm sure this will help others in the same situation) – nc14 Jun 04 '19 at 16:18
  • 2
    @nc14 The "key" has nothing to do with prepending `try` with `return`. You can easily write this as `let attrStr = try NSAttributedString(....)` followed by `return attrStr`. – rmaddy Jun 04 '19 at 16:32