Willjay
Willjay

Reputation: 6459

How to pass data from AppDelegate to ViewController after didSet?

I create an os X project and use Main Menu to open file directory and show the contents on tableview.

In my AppDelegate.swift:

class AppDelegate: NSObject, NSApplicationDelegate {
    var filePath: String = String() {
        didSet {
            // Pass filePath to ViewController
        }
    }

    @IBAction func openFile(sender: AnyObject) {
        let myOpenDialog = NSOpenPanel()
        myOpenDialog.canChooseDirectories = true
        if(myOpenDialog.runModal() != 0) {
           self.filePath = myOpenDialog.URL!.path!
     }
}      

My ViewController.swift:

class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
    @IBOutlet weak var fileTableView: NSTableView!
    private var objects: NSMutableArray! = NSMutableArray()
    var fileDirectory: String = String() {
           didSet {
              showFileList(fileDirectory)
           }
    }
    func showFileList(fileDirectory: String) {
    var contentsInFolder: NSArray?
    var isDir : ObjCBool = false

    // Remove last loaded objects
    self.objects.removeAllObjects()

    if NSFileManager.defaultManager().fileExistsAtPath(fileDirectory, isDirectory:&isDir) {
        if isDir {
            contentsInFolder = try! NSFileManager.defaultManager().contentsOfDirectoryAtPath(fileDirectory)
            for id in contentsInFolder! {
                if ((id as! String).rangeOfString(".MOV") != nil) {
                    self.objects.addObject(id)
                }
            }
        }
    }
        self.fileTableView.reloadData()
    }

    // MARK: - Table View
    func numberOfRowsInTableView(tableView: NSTableView) -> Int
    {
        return self.objects.count
    }
}

I got an error "fatal error: unexpectedly found nil while unwrapping an Optional value" when I run the self.fileTableView.reloadData() in ViewController.swift. Any idea how to fix it?

var vc = ViewController()
var filePath: String = String() {
    didSet {
        vc.fileDirectory = filePath
    }
}

Upvotes: 1

Views: 2652

Answers (2)

Willjay
Willjay

Reputation: 6459

var vc = ViewController() 

It will create another instance in AppDelegate and the display UI instance will not get the value pass via this way. I try to use NSNotification and Delegate method and my problem is solved.

AppDelegate.swift

var filePath: String = String() {
    didSet {
        NSNotificationCenter.defaultCenter().postNotificationName("refreshView", object: nil)
    }
}

ViewController.swift

var fileDirectory: String = String()
let delegate = NSApplication.sharedApplication().delegate as! AppDelegate

override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshView:", name: "refreshView", object: nil)
}

func refreshView(notification: NSNotification) {
    fileDirectory = delegate.filePath
}

By doing so, I can get the filePath from my AppDelegate.swift

Upvotes: 0

Roshan
Roshan

Reputation: 1937

When showFileList is called as part of the initialisation process for ViewController, the connection between fileTableView and your UITableView in the view is not yet set. Therefore, it is nil when self.fileTableView.reloadData() is executed.

Simply check for nil before calling reloadData:

 if(self.fileTableView != nil) self.fileTableView.reloadData()

On a side note, you should probably be doing this for self.objects as well. I'm guessing that self.objects is always initialised before self.fileTableView since it is declared before, but I don't know if it is documented behaviour in the Swift specification(would appreciate if someone who knows about this can chip in).

Upvotes: 0

Related Questions