Segue doesn't work in macOS

2019-04-17 23:14发布

I have NSSlider in ViewController that must pass integer value to SecondViewController via segue of type Show and update a View every time I move it. So, moving slider I interactively shuffle images in SecondViewController's window.

I spent a week trying to implement such a behaviour of NSSlider but I failed. Maybe I made wrong connections in Interface Builder. I don't know. If you know any other method to make NSSlider work for shuffling images, tell me, please.

See updated answer for detailed information.

Really appreciate any help!!!

ViewController

import Cocoa

class ViewController: NSViewController {

    @IBOutlet weak var slider: NSSlider!

    @IBAction func passData(_ sender: NSSlider) {        
        func prepare(for segue: NSStoryboardSegue, sender: NSSlider?) {
            if segue.identifier!.rawValue == "SegueIdentifierForSecondVC" {
                if let secondViewController = segue.destinationController as? SecondViewController {
                    secondViewController.imagesQuantity = slider.intValue 
                }
            }
        }
    }
}

SecondViewController

import Cocoa

class SecondViewController: NSViewController {

    var imagesQuantity: Int = 1

    override func viewWillAppear() {
        super.viewWillAppear()

        print(imagesQuantity)
    }
}

But it doesn't work. What's wrong in my code?

Any help appreciated.

UPDATED ANSWER

VIEW CONTROLLER

import Cocoa

extension NSStoryboardSegue.Identifier {
    static let secondVC = NSStoryboardSegue.Identifier("SegueIdentifierForSecondVC")
}

class ViewController: NSViewController {

    @IBOutlet weak var slider: NSSlider!

    @IBAction func segueData(_ sender: NSSlider) {
        self.performSegue(withIdentifier: .secondVC, sender: slider)
    }
    override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
        if segue.identifier! == .secondVC {
            if let secondViewController =
                segue.destinationController as? SecondViewController {
                secondViewController?.imagesQty = slider.integerValue 
            }
        }
    }
}

SECOND VIEW CONTROLLER

import Cocoa

class SecondViewController: NSViewController {

    var imagesQty = 30  

    override func viewWillAppear() {
        super.viewWillAppear()
        //let arrayOfViews: [NSImageView] = [view01...view12]

        let url = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Desktop/ArrayOfElements")

        do {
            let fileURLs = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles]).reversed()
            let photos = fileURLs.filter { $0.pathExtension == "jpg" }

            for view in arrayOfViews {
                //"imagesQty" is here
                let i = Int(arc4random_uniform(UInt32(imagesQty-1)))
                let image = NSImage(data: try Data(contentsOf: photos[i]))
                view.image = image
            }
        } catch {
            print(error)
        }
    }
}

enter image description here

2条回答
Bombasti
2楼-- · 2019-04-17 23:37

The mistake is not in the code.

You have to connect the segue to the ViewController, not to the WindowController.

Connect the slider action to the IBAction (not to the segue) and the segue from ViewController to SecondViewController (not from the slider).

And if the class of the second view controller is SecondViewController it should be indicated in the window controller. Where does SecondVC come from?

enter image description here

And once again the suggestion to create an extension of NSStoryboardSegue.Identifier

extension NSStoryboardSegue.Identifier {
    static let secondVC = NSStoryboardSegue.Identifier("SegueIdentifierForSecondVC")
}

and to use it in these two methods. And force cast the segue.destinationController. It must not crash if everything is hooked up properly.

@IBAction func segueData(_ sender: NSSlider) {
    self.performSegue(withIdentifier: .secondVC, sender: nil)
}

override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
    if let identifier = segue.identifier, identifier == .secondVC {
        let secondViewController = segue.destinationController as! SecondViewController
        secondViewController.imagesQty = slider.integerValue
    }
}  

Finally NSImage got its own initializer taking an URL

let image = NSImage(contentsOf: photos[i])
查看更多
The star\"
3楼-- · 2019-04-18 00:01
@IBAction func passData(_ sender: NSSlider) {        
    func prepare(for segue: NSStoryboardSegue, sender: NSSlider?) {
        if segue.identifier!.rawValue == "SegueIdentifierForSecondVC" {
            if let secondViewController = segue.destinationController as? SecondViewController {
                secondViewController.imagesQuantity = slider.intValue 
            }
        }
    }
}

Should be

@IBAction func passData(_ sender: NSSlider) {        

}

func prepare(for segue: NSStoryboardSegue, sender: NSSlider?) {
    if segue.identifier!.rawValue == "SegueIdentifierForSecondVC" {
        if let secondViewController = segue.destinationController as? SecondViewController {
            secondViewController.imagesQuantity = slider.intValue 
        }
    }
}

Because you have a method inside another while they should be one after the other.

Now, you need to modify passData(_sender:). You need to call inside performSegue(withIdentifier:sender) inside it.
If will trigger at some point prepare(for:sender:). I'm saying at "some point" because there is at least a shouldPerformSegue(withIdentifier:sender:) call before the prepare(for:sender:) is called.

So now do:

@IBAction func passData(_ sender: NSSlider) {        
    self.performSegue(withIdentifier: "SegueIdentifierForSecondVC"  sender:nil)
}
查看更多
登录 后发表回答