Root View Controller Swift - ios

I have a function in my app delegate which appends an item to an array in my a file named ViewController.swift, and then I want to reload a tableview in that same file. I attempt to do so like so:
let vc = ViewController()
let navigationController = UINavigationController(rootViewController: vc)
window!.rootViewController = navigationController
println(vc.messages)
//1 vc.messages.append(message.data.message as! String)
//2 vc.MessageTableView?.reloadData()
The lines numbered 1,2 are where I set breakpoints. It appears to break after line numbered 2.
The exact error I get is
fatal error: unexpectedly found nil while unwrapping an Optional value
I believe my problem is that I am setting the root view controller incorrectly.
Edit #1
Window is declared up top.
If i run my code like this:
let vc = ViewController()
messages.append(message.data.message as! String)
vc.MessageTableView?.reloadData()
println(messages)
Then I can see that the correct data is put into the array (Which i made global for this scenario) but the table does not get updated in the View controller.

You have to reload data inside your ViewController
Put the reload inside viewDidAppear() or sth like that
It's an error because you just init a controller, but your views is not ready yet, they are being initialized.
After viewDidLoad, you can call your views, but not before.
So that's why your table is nil
Beside that, why do you need to reload your table even when you don't see it, right ?

What is the implementation of your delegate function?
After you put the tableview in the storyboard,You have to connect the tableview to the ViewController.swift.
Control drag from the tableview to the top of the viewcontroller (the yellowcircle) , there will be a black popup , do that two times and for each time click on datasource and delegate.
Then in the viewcontroller.swift file implement the functions they show in this tutorial. You don't have to modify the AppDelegate.swift file!
https://www.weheartswift.com/how-to-make-a-simple-table-view-with-ios-8-and-swift/

if you want you viewcontroller to be the rootviewcontroller al you have to do is click on the viewcontroller in storyboard and then in the utilities-> attributes inspector -> check the box "is initial view controller"
https://www.dropbox.com/s/qfd9jqeos7ueq1w/Screen%20Shot%202015-06-25%20at%207.40.46%20PM.png?dl=0

Related

Collection View returns nil when called in function

I want to run a function which involves adding a sublayer to a collection view. However when I run the function the app crashes saying Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value When I print the collection view it shows up in the log as none so I know the collection view is the problem. The view has already been loaded when I call the function and I can see all of it's cells. The function is being called from another class, which I think might have something to do with the problem.
Here is the function that I am calling...
func displayCircle() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
//change the fill color
shapeLayer.fillColor = UIColor.green.cgColor
//you can change the stroke color
shapeLayer.strokeColor = UIColor.green.cgColor
//you can change the line width
shapeLayer.lineWidth = 3.0
print(shapeLayer)
print(collectionView)
collectionView!.layer.addSublayer(shapeLayer)
}
Here is how I am calling this function from another class...
ViewController().displayCircle()
EDIT: This is my storyboard layout...
What could the problem be?
As you can see, I am using a page view controller. Hope this helps
There's likely a few issues here.
If you wanted to say ViewController.displayCircle() then displayCircle would need to be a static function. But I don't think that was your intention, you probably don't want to do that in this case, and also your static function syntax is wrong (ViewController().displayCircle() is wrong). But moving on... :)
ViewController().displayCircle() isn't how you properly reference the collectionView. First you need a reference to the other view controller. Then inside displayCircle you need to grab a reference to the collectionView if it's in another View Controller. So that would be otherViewController.collectionView provided the collectionView is public of course, and provided you have a reference to that other view controller somehow. Note that you can't just make a new reference of the other view controller, otherwise you'll be adjusting the layer on the new instance, not the original.
Last but not least, you're force unwrapping the collectionView - don't do that. Your app will crash if it's ever nil. Instead, take advantage of Swift's paradigms:
if let collView = collectionView {
collView.layer...// etc
}
This last bit isn't the issue, but just good practice.
If the collectionView is part of this same viewController, use self:
self.collectionView.layer.addSublayer(shapeLayer)
If the collectionView is in a different viewController, as it seems to be, you would need to get a reference to that view controller. How you do this depends on the structure of your app. You mention using a UIPageViewController and presumably both the view controllers are presented on it.
From one view controller, you can refer to another like this:
let pvc = self.parent as? UIPageViewController // Or your custom class
let targetViewController = pvc.viewControllers[index] as? YourTargetViewControllerClass
You might need to figure out what index you need. An alternative is to make sure each child view controller of the UIPageViewController has its own subclass, then find the one you want like this:
let pvc = self.parent as? UIPageViewController
let viewControllers = pvc.viewControllers.filter { $0 is CustomSubclass }
if let viewController = viewControllers.first as? CustomSubclass {
viewController.displayCircle()
}
As the other answer states, using ViewController() creates a brand new view controller instance, not the one that already exists.
This
ViewController()
creates a new instance other than the presented one ,when you reference the collectionView from it it's actually nil as you have to load the VC either from storyboard / xib , so you have to use delegate to reference the current VC that contains the collectionView

How to set a walkthrough/introduction screen?

I am new developer and I am struggling with my Walkthrough screen for my application.
I have created it, but when I click continue to my main screen, the app crashes.
Here is the code I have under my "continue" button:
#IBAction func skipButtonTapped(_ sender: AnyObject) {
let nextView: FirstViewController = self.storyboard?.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
let appdelegate = UIApplication.shared.delegate as! AppDelegate
appdelegate.window!.rootViewController = nextView
}
and the error I get is :
Could not cast value of type 'UITabBarController' (0x19f33c0d8) to 'Iwin.FirstViewController' (0x100057220).
I think the Problem is in the name of the name of the identifier which in my case is "FirstViewController"
This is the storyboard ID of my TabBarController, which should be the first screen of my app.
Attached I have uploaded a picture too.
The error you are seeing probably has to do with the forced conversion (as!) you do on the first line of the function. You're doing the following:
Calling instantiateViewController(withIdentifier:), which Apple API Documentation says returns UIViewController (in this case, it's returning UITabBarController, a subclass)
Force converting a UITabBarController to a FirstViewController, which fails.
This is because forced conversion guarantees that the resulting value won't be nil, but it doesn't guarantee that it won't fail (crash). UITabBarController is simply not convertible, because it does not extend/implement FirstViewController.
My guess is that even though you've given that view controller the identifier "FirstViewController", but it's just a regular old UITabBarController. Double check in Interface Builder that this View Controller is actually an instance of your FirstViewController class.
Looking at your photo, the "Class" field has the default value of UITabBarController -- this should be the first thing you try to change. Fill in FirstViewController, and let me know if it works.

UIViewController initWithNibNamed:bundle: initialized two objects?

I have a UIViewController that I have had in a storyboard for a while with no problems. As my application grew, and I was using that view controller in more and more places, I realized that I should probably make it more portable, rather than have so many segues to it from hither and yon across the board. I've done splits like this before, so I did what I figured was logical here. I selected that view controller, cut it, and pasted into an empty .xib file. After changing each call to performSegueWithIdentifier to an init(nibName:bundle:) and presentViewController, I get a crash, with an object found unexpectedly nil in viewDidLoad()...
I set the value of this object after each init(...) call, just before presenting the view controller. The nil object is called from viewDidLoad(). This is a problem. I just set this, and now it's gone?!
I overrode the init(...) method, and found that self in init(nibName:bundle:) doesn't have the same memory address as self in viewDidLoad(). Also strange.
I overrode the other init() methods, and found that, after I call to present my view, my object is being instantiated again via init(coder:)! The self in here happens to be the exact self where my property is found nil!
The only reason I see for init(coder:) to be called at all is that I am loading my view from a .xib, but I thought this was handled in init(nibNamed:bundle:)? According to the docs, I do indeed get a call to init(coder:) if I'm loading from a storyboard, and doesn't touch the former... It also says that the nib isn't loaded until the controller's view is queried. If I understand it correctly, my view shouldn't get queried until I present the view. As the crash happens only when I present it, the issue likely stems from that.
I'm stuck here. I still need to get this contextual information to the view controller before it's presented. I've even tried making a proxy class to do the instantiating and property setting before presentation, but I still can't shake this second instance! I get one from init(nibName:bundle:), and another from init(coder:). Neither gets presented, and the latter gives me a nil object error. Any help at all in understanding why this is, and how I might work around this bug (feature?) would be much appreciated. Thank you!
Update:
On a whim, I decided to paste the view controller back into the storyboard, separate from the main hierarchy, and try instantiating it by its identifier. It worked! Not entirely sure how, but by George it worked! Now my question is this: Why?? What is so terribly evil and taboo about .xibs that Xcode and iOS won't tell me? I'm not a little flummoxed by this behavior. I'll keep trying with the .xib, if only to keep Xcode from yelling at me about entrance points...
I don't know what dark magic Xcode is doing, but here's two helper methods I wrote to easily instantiate any Storyboard VC - you just need the Storyboard name and VC identifier (optionally, otherwise will initial VC). By splitting up my VCs into many different Storyboards, I avoid dealing with xibs while still keeping things simple. One loads it into a nav controller of your choice, the other just returns it by itself:
struct StoryboardHelper {
///instantiates a VC with (optional) identifier viewController from storyboardName, pushes it to hierarcy of navigationController, and runs setup block on it, animated specifies whether the push is animated
internal static func showStoryboard(storyboardName: String, viewController: String?, navigationController: UINavigationController, animated: Bool = true, setup: (UIViewController) -> () ){
let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
let destinationVC = viewController != nil ? storyboard.instantiateViewControllerWithIdentifier(viewController!) : storyboard.instantiateInitialViewController()!
setup(destinationVC)
navigationController.pushViewController(destinationVC, animated: animated)
}
///instantiates and returns a VC with (optional) identifier viewController from storyboardName
internal static func instantiateViewControllerFromStoryboard(storyboardName: String, viewController: String?) -> UIViewController{
let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
return viewController != nil ? storyboard.instantiateViewControllerWithIdentifier(viewController!) : storyboard.instantiateInitialViewController()!
}
}

adding UIPageViewController to a view controller's container view

I'm trying to Add my pageViewController to a container view on my main viewController . For that , I have added these codes
addChildViewController(pageViewController!)
self.sliderView.addSubview(pageViewController!.view)
pageViewController!.didMoveToParentViewController(self)
But when I run the app ,it's looks like this :
http://i.stack.imgur.com/0Sf17.jpg
I want to add my pageViewController in the yellow containerView which name is sliderView .
What's wrong with that?
Thanks
Please provide more code as the given example code works pretty well.
Possible causes could be the forced unwrap of your pageViewController. Additionally ensure that the controller is properly instantiated from Storyboard like
guard let vc = storyboard?.instantiateViewControllerWithIdentifier("YourViewControllerID") as? YourViewControllerClass else
{
return
}
sliderView.addSubview(vc.view)
vc.didMoveToParentViewController(self)
You can set YourViewControllerID directly within the Storyboards Identity Inspector

Navigation Segue not Working properly iOS Swift

My segue is returning with an error (unwrapping an optional value) from this line > self.navigationController?....
In my code...
let nextScreen = self.storyboard!.instantiateViewControllerWithIdentifier("onboarding-what") as? ViewController
self.navigationController?.pushViewController(nextScreen!, animated: true)
This above code is implemented in my onboarding-start view controller
This is my storyboard set up...
the last view controller has the id of "onboarding-what".
I've read the documentation for the navigation controller but can't seem to find my problem. Does anyone have a solution?
You can use performSegueWithIdentifier rather than pushViewController if you connected them in storyboard
However did you fill "onboarding-what" in the storyboardId field?
pls check this image
Also "onboarding-what" view controller should be instance of ViewController
(There's not default class called "ViewController" only "UIViewController" or "NSViewController" for osX.)
Obviously nextScreen is nil. It is most likely that "onboarding-what" identifier is incorrect

Resources