How to use the PrepareForSegue method to transfer an object which has an unknown type in the receiving controller? - ios

I'm working on Xcode projects in Swift and I'm trying to transfer data from a "FirstViewController" to a "SecondViewController".
First of all, I receive some data by my user in the FirstViewController. I made a structure to put all these data in one single object that i try to transfer.
Here's my code :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToSecondViewController" {
let sentData:typeOfMyStrcuture = myObject()
let secondVC = segue.destination as! SecondViewController
secondVC.sentData = sentData
}
}
In my SecondViewController I have :
var sentData: typeOfMyStructure!
The problem is : since the type of the object i'm sending is unknown in my SecondViewController, i got the following error : "Cannot find type 'typeOfMyStructure' in scope".
I tried to write the same structure in my SecondViewController for it to recognize the type but I get this error : "Cannot assign value of type 'FirstViewController.typeOfMyStructure' to type 'SecondViewController.typeOfMyStructure'
Thanks by advance for your precious help !

Two options:
if typeOfMyStructure is created inside the first view controller declare in the second view controller
var sentData: FirstViewController.typeOfMyStructure!
Declare typeOfMyStructure outside of any view controller
Side note: Please name structs and classes with a starting capital letter

Related

xcode sigabrt error when using array

I'm trying to get an array working on xcode 9.4.1 between viewcontrollers but keep getting a sigabrt error within part of the first few lines. When playing the simulation the segues that use the array information work, but the segues that don't rely on the array information or are linked to it in any way end up resulting in a SIGABRT error within the array's code. Anyone know what's going wrong?
This is the code;
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let VC = segue.destination as! ViewController_array
if segue.identifier == "grade1"{
VC.gradeLabel = "Grade 1"
VC.display = "information goes here1"
}
if segue.identifier == "grade2"{
VC.gradeLabel = "Grade 2"
VC.display = "information goes here2"
}
}
(and the last few lines continue on as such for each grade)
The error with the code is somewhere within the first line - the receiver on the other viewcontroller is perfectly fine and no other viewcontrollers relate to the same code, it's just something within this first one here.
The sender viewcontroller is named 'ViewController' and the receiver is 'ViewController_array'
The error message it's resulting in is;
objc[11314]: Class VCWeakObjectHolder is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/AVConference.framework/Frameworks/ViceroyTrace.framework/ViceroyTrace (0x12d8504d0) and /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/AVConference.framework/AVConference (0x12c97ce38). One of the two will be used. Which one is undefined.
Could not cast value of type 'UIViewController' (0x10fee11f0) to 'test2.ViewController_array' (0x10d40a710).
2018-08-18 21:06:07.764832+1000 test2[11314:111648] Could not cast value of type 'UIViewController' (0x10fee11f0) to 'test2.ViewController_array' (0x10d40a710).
(lldb)
You need to assign class name
ViewController_array
to the VC inside IB
Have a look at the error message:
Could not cast value of type 'UIViewController' (0x10fee11f0) to 'test2.ViewController_array'
That means that the view controller, that you are trying to segue to, is an instance of the class UIViewController and not ViewController_array. Forced casting UIViewController to ViewController_array will always fail since it is ViewController_array who is the subclass of UIViewController, not the other way around.
You have to make sure that you are setting the right view controller class in the identity inspector in the storyboard:

Add data in segue won't recognize SecondViewController class when running

So here is my first view controller class:
import UIKit
class AboutUsTableViewController: UITableViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let volunteerPageVC = segue.destination as! DedicatedVolunteerViewController
// Idk why I have to use 'as!' instead of 'as'. Xcode made me do it
volunteerPageVC.person = "John Smith"
}
}
Here is my second view controller class:
import IUKit
class DedicatedVolunteerViewController: UIViewController {
var person: String?
#IBOutlet weak var HeaderTitle: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
HeaderTitle.text = "About " + person!;
}
}
On my Main Storyboard, each of the cells on the AboutUsTableView segue to the DedicatedVolunteerViewController. I want to ability to have one view controller that can be used multiple times (i.e. people's profiles).
When I click on any of the cells in the table view, I get these errors:
2016-12-26 11:44:27.075 MyApp iOS[8350:493673] Unknown class _TtC20MyApp_iOS31DedicateVolunteerViewController in Interface Builder file.
2016-12-26 11:44:29.698 MyApp iOS[8350:493673] Unknown class _TtC20MyApp_iOS31DedicateVolunteerViewController in Interface Builder file.
I'm confused since when I compile the app, it gives no error saying about "Unknown class" or an error saying I need to add/import DedicatedVolunteerViewController into AboutUsTableViewController to be able to use it. I even tried to import it, but Xcode wouldn't let me and kept giving me errors.
P.S. I've a lot of trouble considering most places online give documentation on older versions of swift or obj-c which make it hard to find out how to use new versions of code.
It sounds like the class name is wrong in your storyboard scenes. Go follow the segue(s) from your table view controller to your second view controller. Then select the scene for the destination view controller, select the view controller itself, and select the "identify inspector." Check the class of the destination view controller. From the error you're getting, it sounds like it's class is _TtC20MyApp_iOS31DedicateVolunteerViewController instead of DedicateVolunteerViewController.
Swift uses 'optionals' which essentially means a nullable object. Optionals can have a valid value or nil. It is recommended that you use the 'guard' statement to handle optionals.
So, your prepareForSegue should look like:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let volunteerPageVC = segue.destination as? DedicatedVolunteerViewController else {
//Handle the nil value, log, etc
return
}
volunteerPageVC.person = "John Smith"
}
The ! is explicitly unwrapping the optional - meaning it MUST have a value or the app will crash. You should avoid using them where possible and use the ? as I show above instead with a guard statement. In the code above, it attempts to cast the segue.destination to a DedicatedVolunteerViewController but if it can't, it will fall into the guard statement (meaning the result was nil).
There's a lot of good information about optionals on Apple's site. Check out: Swift Basics
As for your specific error, it looks like a simple mis-spelling. The error is referring to 'DedicateVolunteerViewController' (missing a 'd') and your class name is 'DedicatedVolunteerViewController'

unwind segue pass data to different viewcontrollers

I have an app which have 4 different forms. these forms can be completed by clicking the different questions and being lead to a viewcontroller which holds the options. lets call this the OptionViewController. Now I have 4 different forms with different options but all using OptionViewController to pull data from the database, I need to unwind the segue and pass data.
Since there might be 4 different view controllers it might be coming from, I need to make sure that the information is passed properly, i.e. identify if the destinationviewcontroller the unwindsegue is performing the first, second, third or fourth viewcontroller.
I thought I might do something like this
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "optionSelected" {
if segue.destinationViewController == FirstViewController {
//pass data
} else if segue.destinationViewController == SecondViewController {
//pass data
}
}
}
But obviously I cannot perform segue.destinationViewController == FirstViewController
What should I actually be doing? Or should i just create one OptionViewController for every form, which would solve my problem, but I am not sure if overall the app performance will drop due to the increase of view controllers
Thanks for any help in advance
To test if the destination view controller is of a specific class, use the Swift keyword is:
if segue.destinationViewController is FirstViewController {
Alternatively, you can assign the viewController to a variable using optional binding with an optional cast:
if let dvc = segue.destinationViewController as? FirstViewController {
// dvc will have type FirstViewController so you can access specific
// properties of FirstViewController using dvc
}

Passing data between two View Controllers which aren't connected by a segue [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 7 years ago.
I know that you can pass information between two view controllers if they are connected by a segue using
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard let destinationViewController = segue.destinationViewController as? searchTermViewController else { return }
destinationViewController.courseCodes = selectedCourses
}
}
The above code gives an error if there is no segue because of the .destinationViewController. How do i pass information between to arbitrary view controllers without having to set up a global variable?
You can set up a delegate pattern in order to do this.
Here are the steps for setting up the delegate pattern between two objects, where object A is the delegate for object B, and object B will send messages back to A. The steps are:
Define a delegate protocol for object B.
Give object B an optional delegate variable. This variable should be weak.
Make object B send messages to its delegate when something interesting happens, such as when it needs a piece of information. You write delegate?.methodName(self, . . .)
Make object A conform to the delegate protocol. It should put the name of the protocol in its class line and implement the methods from the protocol.
Tell object B that object A is now its delegate.
Here is a tutorial to give you a working example https://www.youtube.com/watch?v=9LHDsSWc680
Go to your storyboard, select the second view controller, go to the Identity inspector tab and give a StoryBoard ID value. This should be a unique value to identify your view controller.
Now in your first view controller', you can run this code. This will basically create an object of the second view controller, set the property value (for transferring data) and push it (same as the segue does)
let ctrl = self.storyboard?.instantiateViewControllerWithIdentifier("detailsView")
as? SecondViewController
ctrl?.userId = 250 // data to pass.
self.navigationController?.pushViewController(ctrl!, animated: true)
provided userId is a variable in your SecondViewController class. Replace
detailsView with the storyboard id value you gave earlier.
class SecondViewController: UIViewController {
var userId : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// do something with self.userId
}
}

Swift - passing values via segue

I'm trying to pass few variables via a segue. Initially I capture 6 variables on the first screen which I would like to pass on to the second view controller.
Each variable is captured through a text box capturing an integer and I called them T1, T2, T3 ... T6. At present I refer to the value through T1.text.toInt()!. Before I pass these values via segue, should I first create a variable like var T1 = T1.text.toInt()! ?
What is the best way of designing this?
inside prepareForSegue you have access to the UIController instance that will open:
class FirstPageUIViewController:UIViewController {
...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var controller = (segue.destinationViewController as! MyNextViewController)
controller.T1 = "value to pass"
}
}
This means you define you variables in MyNextViewController (the controller for your second screen) and the variables are already set when your MyNextViewController instance takes over control.
You also might decide to name your variables starting with small letters according to the swift style guide.

Resources