How to pass an image between view controllers without using segue - ios

I'm getting an error :
Thread 1:EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP,subcode=0x0)
while trying to pass the image that is selected from Photo library, to the other view controller.
Source ViewController -
#IBAction func myButtonTapped(_ sender: UIButton)
{
let secondVC = storyboard?.instantiateViewController(withIdentifier: "secondVC") as! secondVC
secondVC.passedVName = VNameTextField.text!
secondVC.passedCcName = DropTextBox.text!
secondVC.passedVImage = VImageView.image!
navigationController?.pushViewController(secondVC, animated: true)
}
Destination ViewController -
class secondVC: UIViewController
{
#IBOutlet weak var DisplayPassedImage: UIImageView!
#IBOutlet weak var ccNameDisplayLabel: UILabel!
#IBOutlet weak var VNameDisplayLabel: UILabel!
var passedVName = ""
var passedCcName = ""
var passedVImage = UIImage()
override func viewDidLoad()
{
super.viewDidLoad()
VNameDisplayLabel.text = passedVName
ccNameDisplayLabel.text = passedCcName
DisplayPassedImage.image = passedVImage // Error- Thread 1:EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP,subcode=0x0)
}
}
Note: 'PassedVName' and 'passedCcName' data are successfully passed to destination ViewController. if I try to pass 'passedVImage',I get an error.

You can use NotificationCenter to pass action/message to any viewController. Here you need to take UIImage object in AppDelegate (Means Globally) so you can pass it any where.
Ex.
1) You are in firstVC
2) In the firstVC choose the Image and add this image in the image object that you took in AppDelegate
3) Post your Notification in firstVC that you want to pass action
4) Add Observe on your SecondVC
5) You can get image from AppDelegate object (Global object).
Otherwise you can use Protocol.

In my limited experience with you should change .jpg to .png image

Related

IBOutlet References found nil when containing view controller is presented programmatically [duplicate]

This question already has answers here:
Instantiate and Present a viewController in Swift
(18 answers)
Closed 2 years ago.
I am building a running app and am trying to programmatically present a view controller when the start run button is tapped. However, when I tap the button after setting up the presenting view controller, any reference to an IBOutlet is found nil when unwrapping in the order that they are called.
It's worth noting that when I connect the two view controllers with "show" via storyboard instead, that everything works fine, but I want to present the view controller programmatically and in fullscreen rather than the cardlike presentation by default.
From the presenting view controller:
#IBAction func startRunTapped(_ sender: Any) {
let inRunVC = CurrentRunVC()
inRunVC.modalPresentationStyle = .fullScreen
self.present(inRunVC, animated: true, completion: nil)
}
From the presented view controller:
import UIKit
import MapKit
class CurrentRunVC: LocationVC {
#IBOutlet weak var sliderImageView: UIImageView!
#IBOutlet weak var swipeBGImageView: UIImageView!
#IBOutlet weak var durationLabel: UILabel!
#IBOutlet weak var paceLabel: UILabel!
#IBOutlet weak var distanceLabel: UILabel!
#IBOutlet weak var pauseButton: UIButton!
var startLocation: CLLocation!
var lastLocation: CLLocation!
var timer = Timer()
var runDistance = 0.0
var pace = 0
var counter = 0
override func viewDidLoad() {
super.viewDidLoad()
let swipeGesture = UIPanGestureRecognizer(target: self, action: #selector(endRunSwiped(sender:)))
sliderImageView.addGestureRecognizer(swipeGesture) //error unwrapping here
sliderImageView.isUserInteractionEnabled = true // and here
swipeGesture.delegate = self as? UIGestureRecognizerDelegate
}
//errors also on any other reference to an IBOutlet
I've confirmed that all IBOutlets are connected properly.
Storyboard:
Thanks in advance
You are not grabbing the correct storyboard instance of CurrentVC but you are creating a new one. Instead of let inRunVC = CurrentRunVC(), use
let runVC = self.storyboard?.instantiateViewController(withIdentifier: "CurrentRunVC") as! CurrentRunVC //set the identifier in the storyboard identity inspector
Your view controller's outlets are defined in the storyboard, and created when the view controller is loaded from the storyboard. When you just initialise a new view controller in this line:
let inRunVC = CurrentRunVC()
Then the system will look for a xib file with the same name as the view controller, which doesn't exist, which means it just loads a blank view with no connected outlets. All those implicitly unwrapped optionals are now nil.
Either make a new segue from the button to the same view controller, but a modal presentation, or add a reference to the presented view controller in the storyboard and then load it using the instatiate with identifier method of the current storyboard.

Xcode Swift - Pass Button Path Data Between View Controllers

My app has a category of things so when I press "Burger" button on my home viewcontroller it takes me to secondviewcontroller with more options (Buttons) like "spicy, mild, Fire". what I want to do is I want to save path of those button clicked on thirdviewcontroller as text.
For example on thirdviewcontroller a text says "Burger -> Spicy" or "Burger -> mind"
make sure I'm dealing with the button pressed in the path and not text entered.
How do I do that
One easy way is to keep two variables in the second and third view controller.
class FirstViewController : UIViewController {
#IBAction func buttonAction(_ sender: UIButton) {
let vc2 = ...// instantiate second view controller
vc2.textVal = sender.titleLabel!.text
//present vc2
}
}
Then in the second view controller get the text of the button and set it in a text
class SecondViewController : UIViewController {
var textVal: String?
#IBAction func buttonAction(_ sender: UIButton) {
let vc3 = ...// instantiate thrid view controller
let buttonText = sender.titleLabel!.text
vc3.textVal = "\(textVal) -> \(buttonText)"
//present vc3
}
}
Now in the third view controller set the label's text
class ThridViewController : UIViewController {
var textVal: String?
#IBOutlet weak var lblText: UILabel!
override func viewDidLoad() {
lblText.text = textVal
}
}
Hope it will help you.

viewDidLoad is not being called while pushing a viewController

Here am trying to navigate to another viewController by clicking on a button.
It is navigating to next viewController, but viewDidLoad() is not calling here
Here is the code which i wrote to navigate to another viewController on clicking on a button
#IBAction func nextButtonClicked(_ sender: Any) {
let OrdersVC = self.storyboard?.instantiateViewController(withIdentifier: “LoginViewController") as! LoginViewController
self.navigationController?.pushViewController(OrdersVC, animated: true)
}
and here is my viewController (which i need to navigate)
#IBOutlet weak var activeButton: UIButton!
#IBOutlet weak var upcomingButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
Here am able to get into the class, but viewDidLoad() itself it is not calling.
How should i achieve this ?
[![Here is my storyboard][1]][1]
Your problem is that the class is not settled in IB for that VC; make sure class you load and storyboard ID matches the one you want to load. For example, to load:
let OrdersVC = self.storyboard?.instantiateViewController(withIdentifier: “secondID") as! secondViewController
self.navigationController?.pushViewController(OrdersVC, animated: true)
Image:
Two things come to my mind when looking at your question:
Check that the nextButtonClicked method is connected to the button (the code there looks OK, so maybe it is just not executed).
Check if the viewDidLoad that you are speaking about is really in LoginViewController that you instantiate (and I hope you are testing the fact that viewDidLoad is called by setting a breakpoint on super.viewDidLoad()).
Just write folloiwng line in between your push code
#IBAction func nextButtonClicked(_ sender: Any) {
let OrdersVC = self.storyboard?.instantiateViewController(withIdentifier: “LoginViewController") as! LoginViewController
_ = OrdersVC.view // write this line
self.navigationController?.pushViewController(OrdersVC, animated: true)
}
It often happens when the identifier with which you instantiate your ViewController from the storyboard is incorrect. For e.g.
[[self getStoryboard] instantiateViewControllerWithIdentifier:MyVC];
If MyVC is the identifier of some other ViewController, this might happen.

Accessing image from prepare segue error [duplicate]

This question already has answers here:
Passing Image to another View Controller (Swift)
(4 answers)
Closed 5 years ago.
Normally, we link the image from storyboard to viewcontroller by IBOutlet by this code:
#IBOutlet private weak var resultImage: UIImageView!
we can update the image by calling this: resultImage.image = UIImage(named: "image"). It works ok
However, when i call this in the prepare for segue, it found nil:
let destinationDetail = segue.destination as! RestaurantViewController
destinationDetail.restaurantImage.image = UIImage(named: "image")
restaurantImage is an Outlet in RestaurantViewController: #IBOutlet weak var restaurantImage: UIImageView!
I dont understand why it found nil, please help!
Because view controlle haven't been set up yet. you can use IBOutlet after view is load.
In viewDidLoad or viewDidAppear of your destination viewController you will do something like this:
override func viewDidLoad() {
super.viewDidLoad()
resultImage.image = newImage
}

Passing array through segue in swift

I've been struggling for a few days now with passing an array from my SecondViewController to my FirstViewController using Swift.
From my research I found that segue with prepareForSegue would be a viable option but I can't seem to figure it out. What am I doing wrong?
My prepareForSegue in SecondViewController looks like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var DVC: FirstViewController = segue.destinationViewController as! FirstViewController
DVC.mySeguedArray = myIncomeArray
}
My FirstViewController looks like this:
class FirstViewController: UIViewController {
#IBOutlet weak var textView: UITextView!
var myIncomeArray: [Income] = []
var mySeguedArray: [Income] = []
override func viewDidLoad() {
super.viewDidLoad()
myIncomeArray = mySeguedArray
}
Also worth mentioning is that I'm sure I'm populating the array in the SecondViewController as I'm testing it by printing out the size of the array when adding new Income objects to it. But the array in FirstViewController just returns 0 when checking it size after segue.
Edit: Added picture of storyboard
StoryBoard
Did you know that array in Swift are value type. So, when you assign array to some other variable or pass it to some method, the value is passed; not the reference to actual object. When you pass your array to second view controller, it copies the content of your original array. You are then adding to this array which do not change the content of original array.
I would suggest you to create some kind of callback or delegate pattern from second view controller to first view controller to inform the changes such that first view controller would also modify the original array content.
Here is a small portion of code that will help you understand this,
let originalArray = ["a", "b", "c"]
var newArray = originalArray
newArray.append("d")
print(originalArray) // prints ["a", "b", "c"]
print(newArray) // prints ["a", "b", "c", "d"]
You can use protocol to pass data between view controllers
protocol YourFirstViewControllerDelegate: class {
func onButtonClicked(yourString: [String])
}
For passing data from first view controller to second in your Main view Controller when you want to show your first view controller:
you should set main view controller to your view controller delegate, yourFirstViewController.setDlegate(self)
In FirstViewController you should raise an event to main with onButtonClicked([String])
In onButtonClicked([String]) you can call secondViewController and pass your array with onSecondViewController([String])
class MainViewController: UIViewController,YourFirstViewControllerDelegate{
var yourString = [String]()
weak var vcFirst: FirstViewController?
weak var vcSecond: SecondViewController?
func onFirstViewController(){
if (self.vcFirst == nil){
self.vcFirst = self.storyboard?.instantiateViewController(withIdentifier: "FirstViewController") as? FirstViewController
self.vcFirst!.view.translatesAutoresizingMaskIntoConstraints = false
self.vcFirst?.setDelegate(youeFirstViewControllerDelegate: self)
}
self.setActiveController(viewController: self.vcFirst)
}
func onSecondViewController(yourString:[String]){
if (self.Second == nil){
self.Second = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController
self.vcSecond!.view.translatesAutoresizingMaskIntoConstraints = false
self.vcSecond.setArray(yourArray: self.yourArray)
}
self.setActiveController(viewController: self.vcSecond)
}
....// your view controller method
func onButtonClicked(yourString: [String]){
self.yourString = yourString
onSecondViewController(yourString:self.yourString)
}
In your First view controller
class FirstViewController: UIViewController{
weak var yourFirstViewControllerDelegate: YourFirstViewControllerDelegate?
var yourString = ["test1","test2"]
// all your overide method should be here
func setDelegate(yourFirstViewControllerDelegate: YourFirstViewControllerDelegate){
self.yourFirstViewControllerDelegate = yourFirstViewControllerDelegate
}
func onButtonClicked(){
self.yourFirstViewControllerDelegate.onButtonClicked(self.yourString)
}
In your second view controller
class SecondViewController: UIViewController{
var yourString = [String]
// all your overide method should be here and you can use your [String]
func setArray(yourString:[String]){
self.yourString = yourString
}
}
I have not Mac OS to check my code now please just read this code not copy, I'll edit this code tomorrow
Your code looks fine, use the following prepareforsegue as it helps figure out where the problem could be
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segueIdInStoryboard" {
if let DVC = segue.destinationViewController as? FirstViewController{
DVC.mySeguedArray = myIncomeArray
} else {
print("Data NOT Passed! destination vc is not set to firstVC")
}
} else { print("Id doesnt match with Storyboard segue Id") }
}
class FirstViewController: UIViewController
{
#IBOutlet weak var textView: UITextView!
var myIncomeArray: [Income]!
var mySeguedArray: [Income]!{
didSet{
myIncomeArray = mySeguedArray //no need to call viewDidLoad
}
}
}

Resources