fatal error on calling function from another class - ios

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

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)
}

Accessing ViewController's method in custom Class

I have made a func in ViewController, that can receive a string and change the title of a label, that is located on screen.
Here it is:
func setNewTitleForMainLabelOnScreen(text: String){
mainLabelOnScreen.cell?.title = text
}
What i want to do, is to call this function (viewController's method?) from another class.
Like that:
class MainLabelEditor{
func updateLabelOnScreen{
ViewController.setNewTitleForMainLabelOnScreen(text: "Hello")
}
}
Unfortunately, it doesn't work.
Here is what xcode says:
If I press return, it shows this:
The question is, how do i call setNewTitleForMainLabelOnScreen from MainLabelEditor?
I usually use NotificationCenter to deliver data from other ViewController.
ViewController
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(setNewTitleForMainLabelOnScreen), name: NSNotification.Name(rawValue: "changeTitle"), object: nil)
}
#objc func setNewTitleForMainLabelOnScreen(_ notification: Notification){
mainLabelOnScreen.cell?.title = notification.object as! String
}
: Specifies the value passed to NotificationCenter object as title.
Other UIViewController
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "changeTitle"), object: "titleTextValue")
: You can add the string value you want as the title to the object.
You can try:
public class func setNewTitleForMainLabelOnScreen(text: String){
mainLabelOnScreen.cell?.title = text
}
So it turns out, all you need to do is to type
ViewController().setNewTitleForMainLabelOnScreen(text: "Hello")
instead of
ViewController.setNewTitleForMainLabelOnScreen(text: "Hello")

How to send data back to previous screen IOS/Swift [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 2 years ago.
I am creating a library in IOS/swift that:
takes a user to a scene --> performs a task --> return to the initial scene that called the first while passing a payload back to the user
I have figured out how to take users back to the previous scene that called it, but my issue is how to send a payload back with it using thee code snippet below:
func switchToPreviousPage(){
self.dismiss(animated: true, completion: nil)
}
How do I achieve this?
In your scenario you can use either :
Delegation Pattern
Notification/Observer
Lets discuss each one :
1. Delegation :
If you have idea about Protocol in Swift you can do it easily.
first create a protocol with the required function you want to implement :
protocol FirstControllerDelegate: AnyObject {
func sendData(data: String)
}
Suppose your firstPage is FirstViewController, it has a UILabel and we have to assign a String to it from our secondPage means SecondViewController. the Structure of your FirstViewController may be like this :
class FirstViewController: UIViewController {
#IBOutlet weak var textLabel: UILabel!
#IBAction func gotoSecondPage() {
let secondVC = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
}
}
Now your FirstViewController has to confirm to this protocol and it will implement the sendData(data: ) method :
extension FirstViewController: FirstControllerDelegate {
func sendData(data: String) {
textLabel.text = data
}
}
Now as a feature of Protocol in iOS, Protocols can work as a Type(like Int, String). So just create a variable of type FirstControllerDelegate in your SecondViewController !
class SecondViewController: UIViewController {
weak var delegate: FirstControllerDelegate!
#IBAction func switchToPreviousPage() {
delegate.sendData(data: "Hello")
self.dismiss(animated: true, completion: nil)
}
}
You can now call the sendData(data:) function with the variable you created above !
At last you have to do oneThing just assign the delegate :
secondVC.delegate = self
It should be inside the gotoSecondPage() method !
2. Notification/Observer
With this, our basic idea is to send a Notification inside our app, and it can be observed by any where inside !
So our SecondViewController will send a Notification embedded with required data that we want to pass, and FirstViewController will receive the Notification and it will extract the data from the Notification !!
Each Notification has a specific name, which will differentiate it from other Notifications. we have to create the Name :
Notification.Name(rawValue: "com.app.notificationObserver")
Now the FirstViewController will be Observe to this specific notification :
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.changeLabelText(notifcation:)), name: Notification.Name("com.app.notificationObserver"), object: nil)
}
We have to define changeLabelText(notification:) method :
private func changeLabelTExt(notification: NSNotification) {
if let dataDict = notification.userInfo as NSDictionary? {
if let message = dataDict["data"] as? String {
self.textLabel.text = message
}
}
}
Finally, SecondViewController will trigger the Notification :
#IBAction func switchToPreviousPage() {
NotificationCenter.default.post(name: Notification.Name(rawValue: "com.app.notificationObserver"), object: ["data": "hello"])
self.dismiss(animated: true, completion: nil)
}
Thats All .....

Observers don't get called using NotificationCenter Swift 4.0

I have a two ViewControllers: ViewController and SecondViewController.
I added an observer to this two ViewControllers. In ViewController I also defined an IBAction to post the notification. I handle the notification via a closure in both ViewControllers. But only the closure in the ViewController gets called. The closure (and even the whole code) in the SecondViewController does not get called (I checked with debugger). The closure only contains a print-statement.
Here is my Code
//ViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let nc = NotificationCenter.default
nc.addObserver(forName: Notification.Name(rawValue:"MyNotification"), object: nil, queue: nil) { (notification) in
print("I'm the : \(type(of: self))")
}
}
#IBAction func sendNotification(_ sender: UIButton) {
let nc = NotificationCenter.default
nc.post(name: Notification.Name(rawValue:"MyNotification"), object: nil, userInfo: ["message":"Hello there!", "Date:":Date()])
}
}
The ScondViewController
//SecondViewController
import UIKit
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let nc = NotificationCenter.default
nc.addObserver(forName: Notification.Name(rawValue:"MyNotification"), object: nil, queue: nil) { (notification) in
print("I'm the: \(type(of: self))")
}
}
}
The closure in ViewController gets called but the closure in SecondViewController does not. Maybe the reason is that SecondViewController does not get initialized before I post the notification. But how would a solution look like?
Any help is appreciated.
If this is one-to-one relationship you can also use the Delegate pattern instead. Although you are right, the notification observer is not yet called because you do not initialise before the post. So there shouldn't be a reason for a function to be called in the SecondViewController.
So if you only need that to update a variable value, you can do that somewhere else in a Variables class where both ViewControllers have access.

getting BAD_EXC_INSTRUCTION and Optional.None swift

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
}
}

Resources