segue with Dictionary SWIFT - ios

Another question which just should be simple but I am again stumped
I have created a dictionary from a log in.
It is full of values. I now want to segue to a new View controller and take the data with me
So I set up
typealias JSONDict = [String:AnyObject]
func prepareForSegue(segue: UIStoryboardSegue, sender: JSONDict!) {
if (segue.identifier == "toHome"){
var svc = segue.destinationViewController as! OtherViewController
svc.toPass2 = parsed!
Parsed shows as JSONDict - all seems well
Over on OtherViewcontroller I set up to catch it:
var toPass2:JSONDict = JSONDict()
this builds for me quite happily and segues as expected.
But when I
println("check data: \(toPass2)")
I get [:]
Nothing.
It seems to me I have built it - but nothing is coming. I could pass individual values - but all I rally want to do is bring the dictionary with me
I also tried the same thing with the unparsed data string - and this too got me a zero result.
Any help appreciated

in your OtherViewController try this:
class OtherViewController: UIViewController {
var toPass2: JSONDict? {
didSet {
println(toPass2)
}
}
}

Related

How do I pass my array data coming from api to another ViewController?

I'm new in iOS.
I'm trying to pass my array data to another view controller through prepareforsegue method.
And this api is called inside the #IBAction func ButtonTapped( ).
class FirstVc {
var location = [Any]()
self.clientrequest.request(url: "http://api.details.in/api/users/alllocation", method: .GET, completion: {
res , err in
let json = try! JSONSerialization.data(withJSONObject: res , options: .prettyPrinted)
let decode = try! JSONDecoder().decode(SelectLocation.self, from:json)
self.location = decode.states
//I'm getting all locations here
print(self.location)
})
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is SecondVc
{
let vc = segue.destination as? SecondVc
//here I'm assigning the variable and while I'm printing location here then also I'm getting the value
vc?.mineSpillere2 = self.location
}
}
class SecondVc{
#IBOutlet weak var selectState: UILabel!
var mineSpillere2 = [Any]()
override func viewDidLoad() {
//While I'm trying to print mineSpillere2 here I', getting []
selectState.text = mineSpillere2 as? String
}
}
One problem might be that you don't actually assign the variable (because vc may be nil). Also you may want to use segueIdentifiers, especially if you have more than one. To make sure that you do so, you may want to use something like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? SecondVc //, segue.identifier = "YOUR_SEGUE_ID"
{
vc.mineSpillere2 = self.location
} else { print("SecondVc couldn't be initialised!") }
}
First, the problem is that web service request is not executed asynchronously but synchronously. In other words, your segue is already performed before decode.states is assigned to the location variable.
The solution is to call performSegue function in the completion block:
self.clientrequest.request(url: "http://api.details.in/api/users/alllocation", method: .GET, completion: {
res , err in
let json = try! JSONSerialization.data(withJSONObject: res , options: .prettyPrinted)
let decode = try! JSONDecoder().decode(SelectLocation.self, from:json)
self.location = decode.states
self.performSegue(identifier: "your identifier",
sender: nil)
//I'm getting all locations here
print(self.location)
})
Second,
Make sure your segue is assigned from VC1 to VC2 not Button to VC2.
There are several way to pass this in another ViewController. Good way is make a model class and pass model object to another vc .
Or might be another short and easy solution is make Global variable. So you can access it from any ViewController class. like
var myGloblArray= [Any]()
//add your result array in this array , you can access it from second VC Directly.
class FirstVc {
...
}

Cannot take values from other view controller Swift

I want to take user settings details from this view controller and read these details to the previous view controller. I have tried many different ways, but I cannot take values until I visit this view controller
I have tried first method from this page Pass Data Tutorial
This method is also not working. I think it is very simple, but I cannot figure out the right way to do it.
class SetConvViewController: UIViewController {
var engS = "engS"
#IBOutlet weak var swithEnglish: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
if let eng2 = defaults.value(forKey: engS)
{
swithEnglish.isOn = eng2 as! Bool
}
}
let defaults = UserDefaults.standard
#IBAction func switchEng(_ sender: UISwitch) {
defaults.set(sender.isOn, forKey: engS)
}
}
If I understand you correctly from this part - „but I cannot take values until I visit this view controller” - your problem lies with the fact, that until you visit your settings, there is no value for them in UserDefaults.
If you are reading them using getObject(forKey:) method, I’d recommend you to switch to using getBool(forKey:), since it will return false even if the value has not been set yet for that key ( docs )
Anyhow, if you want to set some default/initial values you can do so in your didFinishLaunching method in AppDelegate :
if UserDefaults.standard.object(forKey: „engS”) == nil {
// the value has not been set yet, assign a default value
}
I’ve also noticed in your code that you used value(forKey:) - you should not do that on UserDefaults - this is an excellent answer as to why - What is the difference between object(forKey:) and value(forKey:) in UserDefaults?.
On a side note, if you are using a class from iOS SDK for the first time, I highly recommend looking through its docs - they are well written and will provide you with general understanding as to what is possible.
I would recommend you to store this kind of data as a static field in some object to be able to read it from any place. e.g.
class AppController{
static var userDefaults = UserDefaults.standard
}
and then you can save it in your SetConvViewController like
#IBAction func switchEng(_ sender: UISwitch) {
AppController.userDefaults.set(sender.isOn, forKey: engS)
}
and after that you can just read it from any other view controller just by calling
AppController.userDefaults
Using segues you can set to any destination whether it be next vc or previous:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "PreviousVC" {
if let prevVC = segue.destination as? PreviousViewController {
//Your previous vc should have your storage variable.
prevVC.value = self.value
}
}
If you're presenting the view controller:
Destination vc:
//If using storyboard...
let destVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DestinationViewController") as! DestinationViewController
destVC.value = self.value
self.present(destVC, animated: true, completion: nil)
Previous vc:
weak var prevVC = self.presentingViewController as? PreviousViewController
if let prevVC = prevVC {
prevVC.value = self.value
}

Passing data between view controllers through segue

I have a MapViewController with a prepareForSegue(_:sender:)method, which I intend to use to send data to LandmarkTableViewController, and is called when a button is pressed.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationvc = segue.destinationViewController
if let landmarkvc = destinationvc as? LandmarkTableViewController {
if let identifier = segue.identifier {
let library = Landmark(name: "Run Run Shaw Library", properties: ["Chinese Kanji", "Gray", "Green Plants"])
let bank = Landmark(name: "Hang Seng Bank", properties: ["Chinese Kanji", "Green"])
switch identifier {
case "showLibrary" : landmarkvc.passedLandmark = library // pass data to LandmarkTableViewController
case "showBank" : landmarkvc.passedLandmark = bank // pass data to LandmarkTableViewController
default : break
}
}
}
}
The LandmarkTableViewController is properly set up to display the String array properties, with one String on each row. So what I intend to do is pass the appropriate data for the table to properties according to which button was pressed, and let LandmarkTableViewController display the corresponding properties.
class LandmarkTableViewController: UITableViewController {
var properties = [String]()
var passedLandmark = Landmark(name: "temp", properties: ["temp"]) // initially set to default value
override func viewDidLoad() {
super.viewDidLoad()
loadSampleProperties()
}
func loadSampleProperties() {
self.properties = passedLandmark!.properties
}
// other methods....
}
class Landmark {
var name: String
var properties: [String]
init?(name: String, properties: [String]) {
self.name = name
self.properties = properties
// Initialization should fail if there is no name or if there is no property.
if name.isEmpty || properties.isEmpty {
return nil
}
}
However, when I run the code, only temp is displayed in the table view. I've been stuck on this for a long time now, so any help is much appreciated!
Edit: loadData() inside of viewDidLoad() is changed to the correct loadSampleProperties(). I made an error while posting the code to the question.
I think this should solve your problem if not double check your identifiers
and you can make sure to data passing with adding print(passedLandmark) to viewDidLoad() or breakpoint to make sure you getting the data
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationvc = segue.destinationViewController
if let landmarkvc = destinationvc as? LandmarkTableViewController {
if segue.identifier == "showLibrary" {
let library = Landmark(name: "Run Run Shaw Library", properties: ["Chinese Kanji", "Gray", "Green Plants"])
landmarkvc.passedLandmark = library
}
if segue.identifier == "showBank" {
let bank = Landmark(name: "Hang Seng Bank", properties: ["Chinese Kanji", "Green"])
landmarkvc.passedLandmark = bank
}
}
}
Hope this will helps
Code is missing from your quote, so I can't be sure, but I assume your loadData() method is the one that reloads the table view data with Landmark you've passed in prepareForSegue. If that is the case:
viewDidLoad() is called before prepareForSegue, so that all the views and elements of the destinationViewController are loaded and ready to use. Thus, in your case, the table view is loaded with your "temp" data and nothing makes it reload when you set the proper one.
You have two options:
You could call loadData()/reloadData() in viewWillAppear for example, which is called after prepareForSegue(). Bare in mind that viewWillAppear will possibly be called again in some other navigation.
Otherwise, you could instantiate and present/push the new controller in your parent view controller, instead of using the segue.

Passing data to another ViewController in Swift

Before I begin, let me say that I have taken a look at a popular post on the matter: Passing Data between View Controllers
My project is on github https://github.com/model3volution/TipMe
I am inside of a UINavigationController, thus using a pushsegue.
I have verified that my IBAction methods are properly linked up and that segue.identifier corresponds to the segue's identifier in the storyboard.
If I take out the prepareForSegue: method then the segue occurs, but obviously without any data updating.
My specific error message is: Could not cast value of type 'TipMe.FacesViewController' (0x10de38) to 'UINavigationController' (0x1892e1c).
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
if segue.identifier == "toFacesVC" {
let navController:UINavigationController = segue.destinationViewController as! UINavigationController
let facesVC = navController.topViewController as! FacesViewController
facesVC.balanceLabel.text = "Balance before tip: $\(balanceDouble)"
}
}
Below is a screenshot with the code and error.
side notes: using Xcode 6.3, Swift 1.2
A couple of things:
1: change your prepareForSegue to
if segue.identifier == "toFacesVC" {
let facesVC = segue.destinationViewController as! FacesViewController
facesVC.text = "Balance before tip: $\(balanceDouble)"
}
2: add a string variable to your FacesViewController
var text:String!
3: change the FacesViewController viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
balanceLabel.text = text
}
The reasons for all the changes: the segue destinationViewController is the actual FacesViewController you transition to -> no need for the navigationController shenanigans. That alone will remove the "case error", but another will occur due to unwrapping a nil value because you try to access the balanceLabel which will not have been set yet. Therefore you need to create a string variable to hold the string you actually want to assign and then assign that text in the viewDidLoad - at the point where the UILabel is actually assigned.
Proof that it works:
4: If you want display two decimal places for the balance you might change the String creation to something like (following https://stackoverflow.com/a/24102844/2442804):
facesVC.text = String(format: "Balance before tip: $%.2f", balanceDouble)
resulting in:

App crashes when passing Dictionary in prepareForSegue

So, I've done this a million times, but today, it seems like my brain has come to a halt and I'm completely stuck on this... Here it goes:
I've got to pass a JSON responseDict to a CollectionViewController via a Push Segue. The response is a timeline feed from Instagram.
In my sourceVC the Dictionary is defined like this: var timelineResponse: [String : AnyObject]? and in my destinationVC the response Dictionary is defined the same way var responseDict: [String : AnyObject]? Although I've tried to define it all sorts of way to see if that was the problem.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
if (identifier == "photoSegue") {
//This println correctly outputs the contents of the dict, so I know that the dict is not nil before passing it.
println("sending timelineResponseDict to PhotoCollView with following data: \(timelineResponse)")
// I've tried the following two methods of passing the dict to my PhotoCollView
// (segue.destinationViewController as PhotoCollectionView).responseDict = timelineResponse!
let toVC: PhotoCollectionView = segue.destinationViewController as PhotoCollectionView
toVC.responseDict = timelineResponse!
toVC.stringResp = "Test"
}
}
}
As you can see, I tried to pass a test string, to see if that worked, which it did. So it seems to be the Dictionary type it doesnt want to pass along. But why?
SOLVED
I was trying to pass type AnyObject to a Dictionary, and hence the crash. Sorry for wasting a bit of time here! :/ I appreciate the comments guys!

Resources