Search code examples
swiftcocoansviewdelegationnsviewcontroller

How to pass value from NSViewController to custom NSView of NSPopover?


By using the delegation protocol I have tried to pass a string (inputFromUser.string) from NSViewController - mainController to custom subclass of NSView of NSPopover - PlasmidMapView, to drawRect function, see code below. But, it didn’t work. I don’t know where a mistake is. Maybe there is another way to pass this string.

Update

File 1.

  protocol PlasmidMapDelegate {
    func giveDataForPLasmidMap(dna: String)
  }

  class MainController: NSViewController {

    @IBOutlet var inputFromUser: NSTextView!
    var delegate: plasmidMapDelegate?

    @IBAction func actionPopoverPlasmidMap(sender: AnyObject) {
         popoverPlasmidMap.showRelativeToRect(sender.bounds, 
             ofView: sender as! NSView, preferredEdge: NSRectEdge.MinY)

         let dna = inputDnaFromUser.string
         delegate?.giveDataForPLasmidMap(dna!)  
    }
}

File 2

class PlasmidMapView: NSView, PlasmidMapDelegate {

    var dnaForMap = String()

    func giveDataForPLasmidMap(dna: String) {
        dnaForMap = dna
    }       

    override func drawRect(dirtyRect: NSRect) {

    let objectOfMainController = MainController()
    objectOfMainController.delegate = self

        //here I have checked if the string dnaForMap is passed
         let lengthOfString = CGFloat(dnaForMap.characters.count / 10)

         let pathRect = NSInsetRect(self.bounds, 10, 45)
         let path = NSBezierPath(roundedRect: pathRect, 
             xRadius: 5, yRadius: 5)
         path.lineWidth = lengthOfString //the thickness of the line should vary in dependence on the number of typed letter in the NSTextView window - inputDnaFromUser
         NSColor.lightGrayColor().setStroke()
         path.stroke()
    }
 }

Solution

  • Ok, there's some architecture mistakes. You don't need delegate method and protocol at all. All you just need is well defined setter method:

    I. Place your PlasmidMapView into NSViewController-subclass. This view controller must be set as contentViewController-property of your NSPopover-control. Don't forget to set it the way you need in viewDidLoad-method or another.

    class PlasmidMapController : NSViewController {
        weak var mapView: PlacmidMapView!
    }
    

    II. In your PlacmidMapView don't forget to call needsDisplay-method on dna did set:

    class PlasmidMapView: NSView {
        //...
        var dnaForMap = String() {
            didSet {
                needsDisplay()
            }
        //...
    }
    

    III. Set dna-string whenever you need from your MainController-class.

    @IBAction func actionPopoverPlasmidMap(sender: AnyObject) {
         popoverPlasmidMap.showRelativeToRect(sender.bounds, 
             ofView: sender as! NSView, preferredEdge: NSRectEdge.MinY)
    
         let dna = inputDnaFromUser.string
         if let controller = popoverPlasmidMap.contentViewController as? PlasmidMapController {
             controller.mapView.dna = dna
         } else {
             fatalError("Invalid popover content view controller")
         }
    }