PushViewController shows Black Screen - swift

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.

Related

Call function in another ViewController (macOS)

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.

Black screen with viewDidLoad after if else statement

I want my app to check at start conditionaly if a variable is correct or not. Based on that it should either go to an intro screen (where he can select a variable in my case select a team) or it should start the main view. After searching i found this code and edited it. But there still seems to be problems. First of all I dont have two identifier. The Intro has one but not the main view. My main View is called WeatherViewController and the Intro screen is called FirstScreenViewController. I also added a picture of my Main.storyboard.
I also googled a lot about conditional UINavigationController but I can only understand with a video and did not found a video about it.
I tried to use the code from here.
var id = hello ? "goToIntro" : "???"
self.window = UIWindow(frame: UIScreen.main.bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let WeatherViewController: UIViewController = mainStoryboard.FirstScreenViewController(withIdentifier: WVC has no identifier??) as UIViewController
self.window?.rootViewController = WeatherViewController
self.window?.makeKeyAndVisible()
if hello {
self.performSegue(withIdentifier: "goToIntro", sender: self)
} else {
/here nothing should happen. It should open the Main View
self.performSegue(withIdentifier: "???", sender: self)
}
Note: This answer was referring to the original question (before any edits) that was attempting a segue inside loadView().
You're supposed to manually create your controller's view in loadView. You're currently doing nothing, hence the black screen. Furthermore, if you are using a Storyboard or a xib for managing this controller you shouldn't be overriding loadView at all.
Having said that it might be a better idea to move this branching logic a step back, to "something" (a container controller like a UINavigationController or a custom one, or even directly setting the root controller of your window if it makes sense) that will present (or set) A or B based on some condition and thus avoid to load this controller altogether (have in mind that in your code, the controller is initialized, it will be part of the hierarchy and all the lifecycle methods will be called even if you segued directly to another one)
Finally, if you decide for some reason to override loadView you don't have to call viewDidLoad yourself, the system will call this method.

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.

Come back to the tabBarController, swift

Currently on my viewController : Upload, my button send the data to my database only if all the information are filled out, and I come back to the preview view (table View) with :
self.navigationController?.popViewControllerAnimated(true)
I would like, if it is possible, to come back to my main view on the tabBarController. I tried many things, like directly on the storyboard with Present modally segue to "TabBar controller", but I come back to the TabBar without sending my data to the database and without checking in the information are filled out..
How can I do it?
Thanks!
UITabBarController has a property selectedIndex with which you can switch the selected tab. So on completion after dismissing the UploadViewController you can run:
self.tabBarController?.selectedIndex = 0 // Index to select
It would probably be best to create a delegate for your UploadViewController to fire a function to do all the work in your previewVC on API call completion.
(Super late response...in case someone has similar questions, presumably in later version of Swift, such as mine which is Swift 5, iOS 13.2). Steps:
Be sure to set an id for your UITabBarController storyboard, e.g. "TabBarViewController"
Next, add the following to an action that has already been connected to a button:
let ID_TABBAR = "TabBarViewCOntroller"
#IBAction func returnToTabbar(_ sender: Any) {
let tabBarController = self.storyboard?.instantiateViewController(identifier:ID_TABBAR) as! UITabBarController
self.navigationController?.pushViewController(tabBarController, animated:true)
}
Referenced from one of the responses from this post.
Update: In case your Tab Bar View Controller also happens to be the root view controller, the two lines of the code in the returnToTabbar method above can be:
self.dismiss(animated:true, completion:nil);
self.navigationController?.popViewController(animated:true);
(ref.: See answer here, for Swift4 but works just fine in Swift5)

instantiateViewControllerWithIdentifier crashes app

I am trying to instantiate a ViewController defined in MainStoryBoard.storyboard using the code snippet shown in the pic below. I also assigned an identifier to the controller but app crashed with the error shown in pic saying "Storyboard doesn't contain a controller with identifier masterViewController" although you can clearly see in pic that its there.
Any help will be appreciated.
Just so you know, following solution didn't work for me: Crash with instantiateViewControllerWithIdentifier
Below is the snapshot that confirms that the storyboard object is same that is retrieved from viewcontroller and used to instantiateViewControllerWithIdentifer:.
SITUATION DESCRIPTION: I am trying to develop a custom SplitViewController (subclassed from UIViewController). This UIViewController is purely programmatic i.e. not based on IBInterface layout. However for its children i.e MasterViewController and DetailViewController I have made layouts in IBInterface. Now I am retrieving a UIStoryboard object in SplitViewController (purely programatic one) and passing it to a utility class shown here in the first pic that uses it to instantiate MasterViewController based on a layout in the Storyboard.
Hm, looks like if should work.
Try this:
Clean project and rebuild
Check if storyboard contains an instance of the correct storyboard
Fix by shaffooo (from comments below)
I rebuilt my storyboard and it fixed the issue I was having.
try to write the same name of your ViewController class into 'StoryBoard ID' in IB. Then edit the argument of your instantiateViewControllerWithIdentifier method with same string:
yourVCName *startingViewController = (yourVCName *)[self.storyboard instantiateViewControllerWithIdentifier:#"yourVCName"];