tableView.reloadData() causes crash in Swift - ios

I read a question asked on Stackoverflow about making a view controller transparent so when it is shown the parent view controller can still be seen behind. I was able to do so:
However now when I click add subject the table view does not add the subject to my tableview like so (this is the view that appears behind the above view when the "+" button is tapped):
but if i exit to my main menu and come back to the table view it displays the list like so (which is what I want when I tap "Add Subject).
I think this is due to tableView.reloadData() being in my ViewWillAppear function.
With this in my mind i added tableViewClass.tableView.reloadData to the "Add Subject" button action in order to reload data as soon as the button is pressed however I get fatal error: found nil while unwrapping optional value and it highlights tableViewClass.tableView.reloadData
I know that the parent view controller (one with the table view) is not killed once the New Subject view controller appears in order to show it behind. This is why "ViewWillAppear" is never called.
Im still a little confused as to why its crashing though... here is my code for my button:
#IBAction func btnAddTask_Click(sender: UIButton){
subMngr.addSubjectMonA(txtSubject.text, time1: txtTime.text, time2: txtTime2.text, col: monAview.ColorValue)
self.view.endEditing(true)
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context: NSManagedObjectContext = appDel.managedObjectContext!
var newCell = NSEntityDescription.insertNewObjectForEntityForName("SubjectsEntity", inManagedObjectContext: context) as NSManagedObject
newCell.setValue(txtTime.text, forKey: "starttime")
newCell.setValue(txtSubject.text , forKey: "title")
newCell.setValue(txtTime2.text , forKey: "endtime")
newCell.setValue(monAview.ColorValue, forKey: "color")
context.save(nil)
txtSubject.text = ""
txtTime.text = ""
txtTime2.text = ""
MondayAClass.TableView.reloadData() // ERROR HERE
dismissViewControllerAnimated(true, completion: nil)
}
Any help would be appreciated, thanks :)
EDIT
Here is my code to present the view controller and make it transparent:
#IBAction func addInfo(sender: AnyObject) {
let story: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let monAadd = story.instantiateViewControllerWithIdentifier("MondayAadd") as MondayAadd
monAadd.view.backgroundColor = UIColor.clearColor()
monAadd.modalPresentationStyle = UIModalPresentationStyle.Custom // If this line is taken out everything works fine
self.presentViewController(monAadd, animated: true, completion: nil)
}

fatal error: found nil while unwrapping optional value
This is Swift's way of saying that you attempted to access a nil value. Ensure that you have an owning relationship between the table view and its view controller, and this shouldn't happen.

Related

Warning: Attempt to present ZMNavigationController on **.ViewController whose view is not in the window hierarchy

Guys i am facing an odd problem with NavigationController. Existing answers did not help at all !!!!
Here is basic scenario of the app:
There are two views - Main and Second view
In main view there is a button when i happen to tap goes into second view using segue.
In second view after i enter a certain field in text view and click on a button called "join" it triggers "joinMeeting()" function
and meeting should be joined.
However, when i do that debugger shows me:
"Warning: Attempt to present on
<***.ViewController: *****> whose view is not in the window
hierarchy!"
So i have read most of the tread and given that it happens because of viewDidAppear method but i have nth to be done before viewDidAppear. Everything happens after button is clicked.
joinMeeting() is successfully called and print method returns 0 which means no issue(https://developer.zoom.us/docs/ios/error-codes/) and successful SDK connection however after this "Warning" error is shown in debugger and nothing happens in the app.
If it helps following is the code that triggers joinBtn:
/**
Triggers when Join Button is clicked from second view.
*/
#IBAction func joinMeeting(_ sender: Any) {
if( activityID.text == "" ) {
let alert = UIAlertController(title: "Field is Blank", message: "Activity ID cannot be blank.", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
return;
}
let ms: MobileRTCMeetingService? = MobileRTC.shared().getMeetingService()
if ms != nil {
ms?.delegate = self;
// //For Join a meeting
let paramDict: [AnyHashable: Any] = [
kMeetingParam_Username: kSDKUserName,
kMeetingParam_MeetingNumber: activityID.text!,
]
let ret: MobileRTCMeetError? = ms?.joinMeeting(with: paramDict)
print("onJoinaMeeting ret:\(String(describing: ret))")
}
}
Please help if anyone knows or have an idea on what i am missing here.
Here is what solved the issue:
Storyboard Configuration:
ViewController --Segue: Show--> JoinViewController
#IBAction func onClickJoin(_ sender: AnyObject) {
//Main storyBoard
let initialVC = UIStoryboard(name: "Main", bundle:nil).instantiateInitialViewController() as! UIViewController
let appDelegate = (UIApplication.shared.delegate as! AppDelegate)
appDelegate.window?.rootViewController = initialVC
//Rest of the code
}
Just Add Following code on that controller in which you want to perform calling:
override func viewWillAppear(_ animated: Bool) {
let appDelegate = UIApplication.shared.delegate as? AppDelegate
appDelegate?.window?.rootViewController = self
}
Unfortunately, none of the above solutions worked for me.
So Here is my solution.
Add this line
MobileRTC.shared().setMobileRTCRootController( self.navigationController)
=> When user taps of Join Call Button.
Make sure these conditions should meet as well.
ViewController which is used to open the ZOOM meeting should be a part of root navigation controller
DO NOT present modally the current Zoom Meeting Joining View Controller. Always push it to the root navigation controller.

Change order in Navigation Controller

I'm working with Swift3. I have an App with the VCs as in the picture.
In the Mainmenu-VC the user triggers the Input-segue. User enters a firstname in the Input-VC. This triggers the Select-segue to Select-VC to select a surname and trigger Selected-segue to Details-VC.
From the Mainmenu-VC the user can also access the Details-VC. Back via NavigationControllerMechanism to Mainmenu-VC.
I want to change the NavigationControllerMechanism 'history', so that when the user enters from the Details-VC via the Selected-segue, the previous VC is changed from Select-VC to Mainmenu-VC.
So basically when in the Details-VC, the Back always returns to Mainmenu-VC.
I have tried combining various solutions from the web, without succes.
Is this possible?
Yes it is.
The View-Controller stack is stored in currentViewController.navigationController?.viewControllers.
So you should make something like :
//In Your Details VC :
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard let stack = self.navigationController?.viewControllers else { return }
//get the mainMenu VC
let mainVC = stack.first!
// Rearrange your stack
self.navigationController?.viewControllers = [mainVC, self]
//Now you can press "bac" to Main VC
}
you want to change navigation stack in this way you can manipulate
let myprofile = storyboard.instantiateViewController(withIdentifier: "Profile1ViewController") as! Profile1ViewController
let sourseStack = self.navigationController!.viewControllers[0];
var controllerStack = self.navigationController?.viewControllers
let index = controllerStack!.index(of: sourseStack);
controllerStack![index!] = myprofile
self.navigationController!.setViewControllers(controllerStack!, animated: false);
to go to RootViewController
dispatch_async(dispatch_get_main_queue(), {
self.navigationController?.popToRootViewControllerAnimated(true)
})

Passing data between two view controllers are not working

I am trying to pass some data between two view controllers, but it doesn't work..
This is the data i am trying to pass(these has items from parse.com - the same code is in both view controllers):
var userFile = [PFFile]()
var createdAt = [NSDate]()
var objID = [String]()
This is the button for open the view controller(inside the first view controller i am trying to send data FROM):
#IBAction func openButtonAction(sender: AnyObject) {
let modalVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
modalVC.userFile = self.userFile
modalVC.createdAt = self.createdAt
modalVC.objID = self.objID
print("USERFILE: \(modalVC.userFile.count)")
presentViewController(modalVC, animated: true, completion: nil)
}
The view controller is a ModalViewController.xib connected to ViewStoryModalViewController.swift
This is the viewDidLoad in the view controller i am trying to send data TO:
override func viewDidLoad() {
super.viewDidLoad()
print("USERFILECOUNT: \(self.userFile.count)")
}
My problem is that this is the messages i get in xCode output:
What might be wrong here? Any suggestions?
xCode output tells that an array self.userFile contains zero elements, It doesn't mean that it is passed wrong. It is just empty.
print("USERFILECOUNT: \(self.userFile.count)")
Check if it is empty before passing it to modal vc.
Try this code
You first need to present after that try to set variable.
IBAction func openButtonAction(sender: AnyObject) {
let modalVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
print("USERFILE: \(modalVC.userFile.count)")
presentViewController(modalVC, animated: true, completion: nil)
modalVC.userFile = self.userFile
modalVC.createdAt = self.createdAt
modalVC.objID = self.objID
}

Swift : fatal error: unexpectedly found nil and EXC_BAD_INSTRUCTION

I m new to Xcode and i m building a project with a login button. After clicking the login with details in the text field, it will redirect to the second view which is the scroll view controller. However, i got two parts of "Error"
Normally, it work with a normal view controller(login and move to the second view). I have just recreate a view controller to a scroll view controller and it did not work.
By the way, I got a build success but i just got error when i try to "login"
Can anyone explain why i got the thread error and the fatal error?
How can i resolve the problem?
login view Controller
#IBAction func LoginBtn(sender: AnyObject) {
LoginIn()
}
func LoginIn(){
let user = PFUser()
user.username = usernameTF.text!
user.password = passwordTF.text!
PFUser.logInWithUsernameInBackground(usernameTF.text!,
password:passwordTF.text! , block: { (User: PFUser?, Error
:NSError? ) -> Void in
if Error == nil{
dispatch_async(dispatch_get_main_queue()){
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let MainVC : UIViewController = Storyboard.instantiateViewControllerWithIdentifier("scrollV") as UIViewController
self.presentViewController(MainVC, animated: true, completion: nil)
}
}
else{
NSLog("Wrong!!!!")
}
})
}
Scroll View Controller
import UIKit
class ScrollViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
let V1 : ScrollViewController = ScrollViewController(nibName: "ScrollViewController", bundle: nil)
self.addChildViewController(V1)
self.scrollView!.addSubview(V1.view!)
V1.didMoveToParentViewController(self)
}
You are doing some forced unwrapping, which is not recommended (in general forced stuff in Swift is not recommended), and it will crash your application if the variable being unwrapped is nil. That's why forced unwrap is recommended only when you're 100% sure that you have a valid value in your optional.
In your case, it seems that V1.view! causes the crash, and this might be caused by the fact that V1 didn't successfully loaded from the nib.
Swift has made it very easy to work with nullable values. Just don't force unwrap and use optional binding instead.
#Cristik is correct. Instead of force unwrapping the variable, you should check to see if it is instantiated using the "if let" statement:
if let scrollView = self.scrollView {
if let subView = V1.view {
scrollView.addSubview(subView)
}
}

Welcome Screen on Launch

I want a way for the user to have a welcome screen / tutorial on the first launch of the app. If it isn't the first launch of the app, then it open as it usually would.
I already have the welcome screen tied to a button function if the app opens normally. I'm using BWWalkThroughViewController. Here's my code for the button function:
#IBAction func showWalkThroughButtonPressed() {
// Get view controllers and build the walkthrough
let stb = UIStoryboard(name: "MainStoryboard", bundle: nil)
let walkthrough = stb.instantiateViewControllerWithIdentifier("walk0") as! BWWalkthroughViewController
let page_one = stb.instantiateViewControllerWithIdentifier("walk1") as UIViewController
let page_two = stb.instantiateViewControllerWithIdentifier("walk2") as UIViewController
let page_three = stb.instantiateViewControllerWithIdentifier("walk3") as UIViewController
let page_four = stb.instantiateViewControllerWithIdentifier("walk4") as UIViewController
let page_five = stb.instantiateViewControllerWithIdentifier("walk5") as UIViewController
// Attach the pages to the master
walkthrough.delegate = self
walkthrough.addViewController(page_one)
walkthrough.addViewController(page_two)
walkthrough.addViewController(page_three)
walkthrough.addViewController(page_four)
walkthrough.addViewController(page_five)
self.presentViewController(walkthrough, animated: true, completion: nil)
}
func walkthroughCloseButtonPressed() {
self.dismissViewControllerAnimated(true, completion: nil)
}
That code is located in the MyTableViewController.swift file.
Here's what I can't figure out:
I want the view controllers to show on first launch. Once the user finishes the tutorial, they can press the Close button and it will close. I have the code to check if it's the app's first launch. It's located in the AppDelegate.swift file. Here's that code:
// First Launch Check
let notFirstLaunch = NSUserDefaults.standardUserDefaults().boolForKey("FirstLaunch")
if notFirstLaunch {
print("First launch, setting NSUserDefault")
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "FirstLaunch")
}
else {
print("Not first launch.")
}
return true
So how do I get the welcome screen to launch on first launch? Do I have to create a function in AppDelegate to handle that, and if so what do I have to do to make the tutorial the initial view controller for just the first launch?
I believe what you need to do is already covered here: Programmatically set the initial view controller using Storyboards. If that doesn't work for you add more notes on why the implementation failed. A google search on "programatically change uiviewcontroller on launch ios" will yield other similar links.

Resources