Call function in another ViewController (macOS) - swift

How can I communicate with another View Controller on Xcode Storyboards in any possible way?
Given the principle of encapsulation, the preferred way seems to be to call a function in the other ViewController.
(failed) ideas:
Using self.storyboard to instantiate a Controller with the specified Identifier, casting it to the correct View Controller subclass
instantiating the view controller with let c = specialViewController() [doesn't work because the instance's views haven't loaded]
connecting an IBOutlet to another NSViewController subclass [this one should work but doesn't]
Note: iOS solutions often are not the same as MacOS solutions
First failed idea code:
let spec_ref = self.storyboard!.instantiateController(withIdentifier: "specialSettings") as! SpecialSettings
spec_ref.save_spec_settings();
save_spec_function:
The spec_ref still cannot access IBOutlets in the other ViewController on the Storyboard, so it must not be the correct instance.

Related

PushViewController shows Black Screen

i have a problem with my App.
I´m not an experienced programmer, so maybe it´s just a simple solution. I thought this problem exists because i´m just trying things and play with my app so i made a new App and there´s the same problem.
When i push to a ViewController with navigationController?.pushViewController(PinkViewController(), animated: true).
I´m getting just a black screen. If i have a code like
Label.text = "String in viewdidload of the PinkViewController(). I get the following error at this line of code:
fatal error: Unexpectedly found nil while implicitly unwrapping an
Optional
I searched the web and i didn´t find any solutions for this problem. I hope you can help me.
The reason why it crashes is that your label is probably defined as an #IBOutlet that is connected to a UILabel in your storyboard's PinkViewController. However, when you instantiate PinkViewController with an empty constructor, you're not "using the storyboard-way" and your label outlet (which is non-optional, because it's likely to have an exclamation mark there) could not have been connected to the storyboard instance of your view controller.
So what you should do is one of these options:
If you defined PinkViewController in the storyboard, you'd have to instantiate it in a nib kind of way, for example:
In your Storyboard, select the view controller and then on the right side in the Identity Inspector, provide a Storyboard ID. In code you can then call this to instantiate your view controller and then push it:
let pinkViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "yourIdentifier")
Even better, you create a Segue in the storyboard by control-dragging from the current VC to PinkViewController. There's lots of tutorials for creating Segues online. Don't forget to provide an Identifier for the Segue in the Storyboard, if you want to trigger it programmatically. This can be done by calling
self.performSegue(withIdentifier: "yourIdentifier", sender: nil)
If you want to trigger that navigation upon a button click, you can even drag the Segue from the button to PinkViewController, that way you wouldn't even need to call it in code.
If you defined PinkViewController programmatically only (by creating a class named like that which conforms to UIViewController), you might wanna instantiate it with PinkViewController(nibName: nil, bundle: nil) (notice the arguments instead of an empty constructor) and then push it with your provided code.
Hope that helps, if not, please provide further code / project insight.

NSView not being deallocated

I've got a weird situation here that's almost certainly because I'm new to macOS development and I am missing some core knowledge.
I have a modal sheet that I'm displaying programmatically. (I'm not using a storyboard segue because it needs to be the result of a validation and so far I haven't seen a way to launch a segue programmatically - that's a sub-question here if anyone has advice)
Here's how I'm doing it:
searchVC = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "SearchSceneIdentifier") as? SearchViewController
if searchVC != nil {
searchVC!.searchTerm = searchTextField.stringValue
self.presentAsSheet(searchVC!)
}
This presents the sheet nicely and lets me interact with it. In it, I'm using a class which has a delegate in order to return asynchronous search queries.
Where this gets weird is that when I call
self.view.window!.close()
from inside the view controller, I don't think the view controller is getting deallocated. This seems to be because the delegate is still connected to it, even though the object that has this delegate is within the scope of the view controller itself. This delegate appears to be holding the view controller in memory.
I've gotten around this by doing this before closing the window:
search.delegate = nil
But this is not a good solution for other view controllers that have the same problem because they are inside windows and I don't want to have to catch the window closing then send some kind of notification to each in order to nil-ify their delegates.
Another approach that seems wrong as well is that I keep a reference to these windows in the application delegate and nil-ify it from there.
All of these seem like nasty solutions to the deallocation problem and my hope is that there is a cleaner way of doing this. In Objective-C, reference counts were always a problem but there were patterns to handle them cleanly.
Any advice appreciated.
I updated all my delegates to weak var and that has solved all of my problems with deallocation.

Reuse Storyboard ViewController - Parent / Child Viewcontroller

I want to make a ViewController base-class which I can reuse throughout the project.
I want to create a pop-up ViewController which I can adjust with multiple sub-classes which all share the same basic layout (inherited from the base-class). I would like the layout of the base class to be defined in a storyboard scene in an attempt to follow apple's guidelines (not using xib's). This also includes setting up all constraints in interface builder, and not in code.
All I want to do is the right thing :)
My problem is that if I start to subclass my ParentViewController (which has an associated scene in a Storyboard), the app won't let me show the ViewController. If I instantiate through the Storyboard ID, I can't cast it to my subclass. If I instantiate by creating an instance of the subclass-ViewController, it won't show, as the UI in the storyboard file is "locked" to the ParentViewController.
How do I make a base-ViewController with an associated scene in a storyboard file, which I can use various sub-classes (or the like).
To be concrete: I want to make a pop-up, which can vary slightly depending on the usage. I don't want to make init-methods for each variation, as that would defeat the purpose of attempting to split code.
Thanks for any help or comment!
object_setClass(Sets the class of an object.) will override instance of AViewController with BViewController Class. So on top of AViewController you can add some more methods.
when you have similar viewcontroller with small changes. you have to create different viewcontrollers. using this method you can create on basic viewcontroller with storyboard and reuse that viewcontroller .
class BViewController{
static func vcInstanceFromStoryboard() ->BViewController? {
let storyboard = UIStoryboard(name: "AViewController"), bundle: UIBundle.main)
let instance = storyboard.instantiateInitialViewController() as? AViewController
object_setClass(instance, BViewController.self) //
return (instance as? BViewController)!
}
.....
}
This is an example of how do we use it:
let vc = BViewController.vcInstanceFromStoryboard()
self.present(vc , animation : true)

Implement TouchBar functionality in Xcode Playgrounds

How can I implement a NSTouchBar in using only Xcode Playgrounds? I realize that NSTouchBar, and its accompanying methods including makeTouchBar() are contained within the NSResponder class, which is the superclass of NSView, NSViewController, NSWindow, and SKView (a subclass of NSView.)
It is for this reason that I'm a little unsure how to approach access the TouchBar. There are so many subclasses of NSResponder I'm unsure as to which one is the correct one. And to my knowledge I cannot even access all of them, including the NSWindow for the Playground, which I suspect may be the one I need to access.
My current setup is:
let containerView = SKView()
PlaygroundPage.current.liveView = containerView
let containterScene = SKScene()
containerView.presentScene(containterScene)
And in checking the responder chain, for the SKView I get:
<SKScene> name:'(null)' frame:{{-250, -250}, {500, 500}} anchor:{0.5, 0.5}
And for the SKScene:
<SKView: 0x7fba36037a00>
<NSView: 0x7fba32d6fe80>
<PlaygroundViewBridgeService: 0x7fba32d569e0>
<NSNextStepFrame: 0x7fba32d76e20>
<NSWindow: 0x7fba32e177e0>
For some reason, the SKScene and SKView are not within the same chain, and I can't seem to access any responder higher than the SKView. Is there a way to extend the functionality of the already existing NSWindow?
Another problem is that many tutorials on using the TouchBar require access to the AppDelegate, which I don't think I have in Xcode Storyboards.
Any help implementing the TouchBar in Storyboards would be greatly appreciated.
The solution is actually quite simple. Create a custom subclass of NSViewController and implement the TouchBar override functions within it.
Then implement the above code:
let containerView = CustomSKView()
let containterScene = CustomSKScene()
containerView.presentScene(containerScene)
With the following additions.
let containerViewController = CustomNSViewController()
containerViewController.view = containerView
PlaygroundPage.current.liveView = containerViewController.view
This sets your custom NSViewController within the responder chain, allowing it to take care of the Touch Bar. There is also no need to worry about the App Delegate.

OCUnit testing problems in UINavigationController

I create single view application with 1) Story board 2) ARC and 3) Unit Testing.
In view controller i drag on UIButton. and ViewContrller embedded with Navigation Controller (Using Interface).
It run fine in when i simply run the application, But when i run the application test case target then it aries problem.
vc is ViewController Object which i declare in .h file. and createPDFBtn is the object of UIButton.
Which thing i missing?
You are trying to call createPDFBtn on your view controller (self.vc). Since you do not have a method with this name you get an error message:
unrecognized selector sent to instance
Three possible problems and their solutions:
You may be calling the method on the wrong object - is vc your right object?
vc is correct but you do not have the createPDFBtn method implemented - implement the method.
you have implementet createPDFBtn in your vc object - is it a public or a private method? Is it in your .h file ?