2017-11-27 2 views
0

Ich mache eine Mac-Anwendung, und ich habe ein Problem beim Anhängen von Text an eine NSScrollView, wenn ich eine Funktion aus einer anderen Klasse aufrufen.Text an NSScrollView anhängen - Thread 1: Schwerwiegender Fehler: Unerwartet gefunden Null beim Entpacken ein Optionaler Wert

Ich habe diese Funktion auf meinem Viewcontroller Klasse:

import Cocoa 

class PopoverVC1: NSViewController { 

let popover1 = NSPopover() 

class func loadView() ->PopoverVC1 { 
    let vc = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), 
bundle: nil).instantiateController(withIdentifier: 
NSStoryboard.SceneIdentifier(rawValue: "Popover1")) as! PopoverVC1 
    vc.popover1.contentViewController = vc 
    return vc 
} 

override func viewDidLoad() { 
    super.viewDidLoad() 

    popover1.behavior = .transient 
    popover1.contentViewController = self 
} 

func showPopover (view: NSView){ 
popover1.show(relativeTo: view.bounds, of: view, preferredEdge: .maxY) 

} 

@IBOutlet weak var radioOption1: NSButton! 
@IBOutlet weak var radioOption2: NSButton! 
@IBOutlet weak var radioOption3: NSButton! 


@IBAction func clickOption(_ sender: NSButton) { 
    switch sender { 
    case radioOption1: popover1.performClose(sender) 

    case radioOption2: let vc = ViewController() 
     vc.myPrint(string: "This is a test") 

    default: print ("hello") 

    } 
} 
} 

, als ich eine PopoverVC1 Klasse, die eine Klasse zu einem popover ist ich verwende:

import Cocoa 

class ViewController: NSViewController { 


@IBOutlet weak var oneYes: NSButton! 
@IBOutlet weak var oneNo: NSButton! 
@IBOutlet weak var notesArea: NSScrollView! 


override func viewDidLoad() { 
    super.viewDidLoad() 
    // Do any additional setup after loading the view. 

} 

override var representedObject: Any? { 
    didSet { 
    // Update the view, if already loaded 
    } 
} 

func myPrint (string: String){ 
    let mystring = string 
    let myNotes = notesArea.documentView as? NSTextView 
    let text = myNotes?.textStorage! 
    let attr = NSAttributedString(string: mystring) 
    text?.append(attr) 

} 

let popover1 = NSPopover() 
@IBAction func oneClicked(_ sender: NSButton) { 


    switch sender { 
    case oneYes: let vc = PopoverVC1.loadView() 
     vc.showPopover(view: sender) 

    case oneNo: 
    let myNotes = notesArea.documentView as? NSTextView 
    let text = myNotes?.textStorage! 
    let attr = NSAttributedString(string: "test") 
    text?.append(attr) 

    default: print ("") 
    } 
} 
} 

Allerdings habe ich eine bekam Fehler wenn ich den Radiobutton "oneNo" drücke, sollte die Funktion "myPrint" aufrufen und das Argument übergeben.

Gewinde 1: Fatal error: gefunden unerwartet null, während ein optionaler Wert Abwickeln

ich einige Tests gemacht und als ich diese gleiche Funktion „MyPrint“ nennen, aus der ViewCotroller Klasse funktioniert es gut.

Irgendwelche Ideen?

+1

Wo wird vc und notesArea erstellt? –

+1

'notesArea' muss null sein, wenn Sie es verwenden. – Ryan

+0

Hallo @Ryan, kannst du mir ein Beispiel geben? Ich bin neu zu swift :( – Caico

Antwort

1

Ihr Problem ist in clickOption wenn Sie anrufen:

let vc = ViewController() 
vc.myPrint(string: "This is a test") 

Wenn Sie diese Methode aus dem Code aufrufen und die ViewController'sUIViews sind in einem Storyboard, die Verbindung aus dem Storyboard wird nicht vorgenommen eingerichtet. Deshalb lautet die notesArea Null, wenn Sie die Funktion myPrint aufrufen. In diesem Fall erstellen Sie eine neue Kopie von ViewController und es wird nicht dieselbe sein, die das Popover erstellt hat.

Es gibt einige Möglichkeiten, wie Sie das Problem lösen können, das Sie erreichen möchten. Einer von ihnen ist bekannt als delegate. Dies ist eine Möglichkeit für Sie, die ViewController's Methoden wie Ihre popover erben sie zu nennen. Sie können ein Tutorial here ausprobieren. Die Idee ist, dass wir in Ihrer popover einen Verweis auf die ViewController haben möchten, damit Sie die Funktionen in der aufrufen können. Dann ist die ViewController, die der entspricht, verantwortlich für die Behandlung des Methodenaufrufs.

Also lassen Sie uns eine namens PrintableDelegate erstellen und haben Sie Ihre ViewController Klasse entsprechen. Dann in Ihrem popover, können Sie einen Verweis auf die ViewController als weak var namens delegate haben (Sie können verwenden, was immer Sie wollen, aber delegate ist Standard). Dann können wir die im Protokoll PrintableDelegate beschriebenen Methoden aufrufen, indem wir einfach delegate?.myPrint(string: "Test") schreiben. Ich habe einen Teil Ihres irrelevanten Codes aus meinem Beispiel entfernt.

protocol PrintableDelegate { 
    func myPrint(string: String) 
} 

class ViewController : UIViewController, PrintableDelegate { 

    func myPrint (string: String){ 
     let mystring = string 
     let myNotes = notesArea.documentView as? NSTextView 
     let text = myNotes?.textStorage! 
     let attr = NSAttributedString(string: mystring) 
     text?.append(attr) 
    } 

    @IBAction func oneClicked(_ sender: NSButton) { 
     let vc = PopoverVC1.loadView() 
     // Set the delegate of the popover to this ViewController 
     vc.delegate = self 
     vc.showPopover(view: sender) 
    } 
} 

class PopoverVC1: NSViewController { 

    // Delegates should be weak to avoid a retain cycle 
    weak var delegate: PrintableDelegate? 

    @IBAction func clickOption(_ sender: NSButton) { 
     // Use the delegate that was set by the ViewController 
     // Note that it is optional so if it was not set, then this will do nothing 
     delegate?.myPrint(string: "This is a test") 
    } 
} 
+0

Brillanter Allen! Nach 3 Tagen auf der Suche nach einer Lösung, hat es endlich funktioniert! Danke vielmals. Und auch, danke für die Erklärung! – Caico

Verwandte Themen