getting BAD_EXC_INSTRUCTION and Optional.None swift - ios

I'm now very confused.
I am trying to set a label in one viewController by inputting text into a textbox on a secondView controller and pressing a button. When I do this however, I get a Optional.None error while trying to set the label - but the text is passed back as I can println it just fine from the 1st viewController...
I'm just using "HI" for testing purposes (saves time).
I obviously left out a lot of code here - if there is anything else you need please say.
First View Controller:
#IBAction func btnOptions(sender : AnyObject) {
var view: SecondViewController = SecondViewController()
self.presentViewController(view, animated: true, completion: nil)
}
func setLabel(text: String)
{
println(text)
lblTester.text = text
}
Second View Controller:
#IBAction func btnTester(sender : AnyObject) {
var first: ViewController = ViewController()
first.setLabel("HI")
self.dismissModalViewControllerAnimated(true)
}

lblTester is an outlet so before view is loaded it is nil (an optional value) or you are not initialised it, so you need to check for lblTester exist or not before setting value i.e
func setLabel(text: String)
{
println(text)
if let label = lblTester {
lblTester.text = text
}
}

Related

How to send back data using Closures in Swift iOS?

I'm following this tutorial to send data back using Closures.
https://betterprogramming.pub/5-ways-to-pass-data-between-view-controllers-18acb467f5ec
in this tutorial point no 4 that is "Closures". I have two VC's one for selecting pet (FormsVC) and one for displaying selected pet (ProfileVC).
below is a code for ProfileVC:
// ProfileVC
// MARK: - Set Fav Pet Name
func setPetName(pet: String) {
lblFavouritePet.text = pet
}
// MARK: - Button Select Your Fav Pet Event
#IBAction func btnSelectYourFavPet_Event(_ sender: UIButton) {
let vc = FormsVC()
self.present(vc, animated: true)
}
below is a code for FormsVC:
// FormsVC
// MARK: - Variable Declaration
var favoritePet = String()
// MARK: - viewDidLoad Method
override func viewDidLoad() {
super.viewDidLoad()
setUpFormsVC()
}
// MARK: - Set Up FormsVC
func setUpFormsVC() {
btnDog.titleLabel?.text = "Dog"
btnCat.titleLabel?.text = "Cat"
btnRabbit.titleLabel?.text = "Rabbit"
btnBird.titleLabel?.text = "Bird"
}
// MARK: - Button Selected Pet Event
#IBAction func selectedPetEvent(_ sender: UIButton) {
favoritePet = sender.titleLabel?.text ?? "Dog"
}
// MARK: - Selected Pet Name
func getFavoritePet() -> String {
return favoritePet
}
// MARK: - Button OK Event
#IBAction func btnOk_Event(_ sender: UIButton) {
let vc = ProfileVC()
self.dismiss(animated: true, completion: {
vc.setPetName(pet: self.getFavoritePet())
})
// problem occurs when I dismiss FormsVC after selecting pet, the label displaying selected pet name (lblFavouritePet) throwing error of "Unexpectedly found nil while implicitly unwrapping an Optional value"
}
}
Problem occurs when I dismiss FormsVC after selecting pet, the label displaying selected pet name (lblFavouritePet) throwing error of "Unexpectedly found nil while implicitly unwrapping an Optional value". I have no idea why it is found nil because I have assigned favoritePet's value of selected pet. Sorry for this dumb question, Could anyone help me ?
As #matt mentioned, you should take the presenting view controller, not create the new instance. It's stated in the tutorial you use:
if let vc = presentingViewController as? Profile...
Your app crashes, because you use storyboards, and lblFavoritePet is an #IBOutlet implicitly unwrapped optional, hence, you should initialize it from the storyboard. But you initialize it without using the storyboard, and the property remains nil.
So, don't make a new instance, use the code that is stated in the tutorial.
And follow the naming conventions.
First of all, you have to declarer the closer where you want to pass data.
// FormsVC
// MARK: - Variable Declaration
let completion: ((String)->Void)? = nil
// MARK: - Button OK Event
#IBAction func btnOk_Event(_ sender: UIButton) {
completion?(self.getFavoritePet())
self.dismiss(animated: true)
}
The second part is you have to write the code to receive the data
// ProfileVC
// MARK: - Button Select Your Fav Pet Event
#IBAction func btnSelectYourFavPet_Event(_ sender: UIButton) {
let vc = FormsVC()
vc.completion = { petName in
self.setPetName(pet: petName)
}
self.present(vc, animated: true)
}

Value of type 'UIViewController' has no member 'newExerciseDelegate'

I've searched for a solution to this problem, even tried following a few tutorials to try to solve this, but for some reason I'm ending up with the same issue. I'm attempting to pass a custom object to a different view controller, but every time I try I get the error "Value of type 'UIViewController' has no member 'newExerciseDelegate'"
My delegate:
protocol exerciseDelegate {
func savedExercise(newExercise: Exercise)
}
my sending VC uses the following code:
var newExerciseDelegate: exerciseDelegate!
.
.
.
#IBAction func saveExerciseWasPressed(_ sender: UIButton) {
if (checkFields() == true){
newExercise = Exercise(name: exerciseNameField.text!, weight: Int32(weightField.text!)!, reps: Int32(numberOfRepsField.text!)!, sets: Int32(numberOfSetsField.text!)!, muscleGroupFocus: .cardio)
newExerciseDelegate.savedExercise(newExercise: newExercise)
dismiss(animated: false, completion: nil)
}
}
My receiving VC uses the following code:
#IBAction func addExerciseBtnWasPressed(_ sender: Any) {
guard let newExerciseVC = storyboard?.instantiateViewController(withIdentifier: "NewExerciseVC") else { return }
newExerciseVC.newExerciseDelegate = self // error present on this line
presentDetail(newExerciseVC)
}
I'm sure it's a stupid mistake, but I'm not seeing it. Any help is appreciated, thank you.
You should specify which class it is.After the code know which class actually it is, then you can access it's public objects, methods, variables etc.
#IBAction func addExerciseBtnWasPressed(_ sender: Any) {
guard let newExerciseVC = storyboard?.instantiateViewController(withIdentifier: "NewExerciseVC") as? NewExerciseViewController else { return }
newExerciseVC.newExerciseDelegate = self
presentDetail(newExerciseVC)
}
If you are accessing that delegate which is declared in your ViewController then you should call in the below way.
let childOne = self.storyboard?.instantiateViewController(withIdentifier:"WhatsNewViewController") as? WhatsNewViewController
You have to downcast the instantiated view controller to your custom view controller class:
guard let newExerciseVC = storyboard?.instantiateViewController(withIdentifier: "NewExerciseVC") as? YourViewControllerClass else { return }
newExerciseVC.newExerciseDelegate = self
Also you should use a capital E for your protocol's name.

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
}

How to pass information back with view controllers

I have a view controller and one table View Controller. I go from VC One to VCTable. On VCTable, I select a(cell) data from type string that I store in value. When I press a cell, I would like to send that data back to VC One.
and show in button or label.
How to do this using Storyboards?
you should take a look at protocols / delegation:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html
First Solution: Using CallBack
In your VCOne:
#IBAction func goToViewController2(sender: AnyObject) {
let vc2 = storyboard?.instantiateViewControllerWithIdentifier("ViewController2") as! ViewController2
vc2.callback = ({ string in
self.myString = string
})
presentViewController(vc2, animated: true, completion: nil)
}
in your VCTable:
create a callback variable:
var callback: ((String) -> Void)?
in your didSelectRowAtIndexPath method, send it to VCOne by:
callback?(textField.text!)
Second Solution: Using Reference
#IBAction func goToViewController2(sender: AnyObject) {
let vc2 = storyboard?.instantiateViewControllerWithIdentifier("ViewController2") as! ViewController2
vc2.vc1 = self
presentViewController(vc2, animated: true, completion: nil)
}
in your VCTable:
create this variable:
var vc1: ViewController?
in your didSelectRowAtIndexPath method, send it to VCOne by:
vc1?.myString = textField.text!
Third Solution: Using Delegate see the link as #Andre Slotta said.
FourthSolution: Using CenterNotification Googling for this :).
Hope this help :)

fatal error on calling function from another class

I'm having trouble on calling the function from a different class. I have this:
class ViewController: UIViewController {
func addToOrder(orderNumber:String) {
orderCount.text = orderNumber
}
}
Now in my other class:
class TableViewController: UITableViewController {
func addToOrder(button: UIButton) {
ViewController().addToOrder("100")
//I also tried
var menu = ViewController()
menu.addToOrder("100")
}
}
I'm getting error on this line
orderCount.text = orderNumber
with this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
You can use NSNotificationCenter for that.
Follow this step:
first of all add this in your first viewController where you want to update text:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshTable:", name: "refresh", object: nil)
}
Which will add an observer when your load your first view and also add this helper method which will call when you come back to this view:
func refreshTable(notification: NSNotification) {
let orderDetail = NSUserDefaults.standardUserDefaults().integerForKey("order") //this will read your integer which you will save on second view.
orderCount.text = "\(orderDetail)"
}
In your next view add this code when you are coming back to previous view.
#IBAction func goBack(sender: AnyObject) {
//store your int here
NSUserDefaults.standardUserDefaults().setInteger(100, forKey: "order")
//send notification to first view.
NSNotificationCenter.defaultCenter().postNotificationName("refresh", object: nil, userInfo: nil)
self.dismissViewControllerAnimated(true, completion: nil)
}
Hope this will help.
It's orderCount (which probably is a UILabel) which is nil at initialization-time. If this is a IBOutlet created in a storyboard, you will need to store your text as a separate property, and set the text of your Label to this property in your ´viewDidLoad´ method

Resources