As you can appreciate in this pic we have an App with three different VC's and a Last one with some variable data depending of the options selected on the previous ones.
So, for instance, in this case the user had selected a blue color, a suited style and a L as size.
Our idea is to pass data from the first VC, second VC, and the third VC to the gaps in Last VC.
Any suggestions? It would be very appreciated.
Create a model class where you can store those properties in :
class MyChoices {
var color : String? // or you could use enums for each of them
var style : String? // that would be a better choice, but for the
var size : String? // sake of simplicity I use strings in this example
}
then you pass a variable of type MyChoices from one VC to another in your prepareForSegue method
EDIT (some more info, see answer from FactorJose)
In VC 1 add your variable
class VC1: UIViewController {
#IBOutlet weak var nextOutlet: UIButton!
#IBOutlet weak var colourLabel: UILabel!
var choice : MyChoice?
...
and then further on :
#IBAction func redButton(sender: AnyObject) {
nextOutlet.hidden = false
colourLabel.text = "Red colour selected"
choice.color = "Red"
}
for all those IBActions.
then in your prepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let nextVC = segue.destinationViewController as! VC2
nextVC.choice = self.choice
}
VC2 and VC3 are very similar again
Hi all! As you can appreciate in this pic we have an App with three different VC's and a Last one with some variable data depending of the options selected on the previous ones.
So, for instance, in this case the user had selected a blue color, a suited style and a L as size.
Our idea is to pass data from the first VC, second VC, and the third VC to the gaps in Last VC.
Any suggestions guys? It would be very appreciated
Code :
class VC1: UIViewController {
#IBOutlet weak var nextOutlet: UIButton!
#IBOutlet weak var colourLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
nextOutlet.hidden = true
}
#IBAction func redButton(sender: AnyObject) {
nextOutlet.hidden = false
colourLabel.text = "Red colour selected"
}
#IBAction func blueButton(sender: AnyObject) {
nextOutlet.hidden = false
colourLabel.text = "Blue colour selected"
}
#IBAction func greenButton(sender: AnyObject) {
nextOutlet.hidden = false
colourLabel.text = "Green colour selected"
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {}
}
VC2 and VC3 are the same as VC1 (same outlets and buttons)
lastVC
#IBOutlet weak var colourLabel: UILabel!
#IBOutlet weak var styleLabel: UILabel!
#IBOutlet weak var sizeLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
And the last class to store the strings
import UIKit
class MyChoices {
var colour : String?
var style : String?
var size : String?
}
What can we do?
An alternative to Glenn's answer is to use NSUserDefaults. Think of it like a mini key-value database for PropertyLists.
You can add a new key-value to it with
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(clothingColor, forKey: "Clothing Color")
And then retrieve a previously saved key-value by doing
let defaults = NSUserDefaults.standardUserDefaults()
let clothingColor = defaults.objectForKey("Clothing Color")
Since the user defaults is shared and stored in disk, the information will persist across your different view controllers. It also respects encapsulation, which is good object orientation practice, since your size controller won't have to know anything about color or style and vice versa.
Related
I am recreating a simple app that is a paramedic case logger, effectively it is a bunch of buttons or textfields that get their .text value time stamped and pasted into a UItextView field to create a chronological list of action to refer back to when a paramedic writes up their patient notes.
I have created a tab bar controlled app using the Xcode template.
I have created the UIbuttons and UItextfields that create and paste the string into a test UItextview on the same field.
I have created a func that creates the time stamp string
I run into trouble getting the same string to show on the UItextview on the 2nd view.
RESEARCH
As I am only new to this I have read lots of posts on here with user defaults, segues, delegates/protocols and cannot seem to effectively implement these in my specific circumstance (still not super sure I understand those enough yet to do it).
I have got the point that I have saved the string into a user.default value and then I can use that value in the 2nd view with a func to insert the text and clear the user.default value but I cannot seem to get the function to run from the first view? (get the encounter nil value error).
I feel like this should be a pretty simple process, so not getting it to function is very frustrating...
QUESTION
So I was hoping someone might be able to demo the simple way to take a UItextField.text input from FirstViewController and then when a UIbutton is pressed on FirstViewController pass the string to SecondViewController and insert it into a UITextView field (I don't want to display the 2nd view).
From this demo I'm hoping I can reverse engineer a solution into my code as a learning opportunity without just having my exact code handed to me on a silver platter.
import UIKit
class FirstViewController: UIViewController, UITextFieldDelegate {
// View OUTLETS
#IBOutlet weak var customNoteField: UITextField!
#IBOutlet weak var reportTextViewFieldTemp: UITextView!
#IBOutlet weak var lastEntryTV: UITextView!
#IBOutlet weak var caseIDTF: UITextField!
// Class VARIABLES
let timeButtonArray = ["blank0", "Call Received1", "Dispatched2", "Enroute3", "On Scene4", "At Patient5", "Depart Scene6", "At Hospital7", "Available8",]
// VIEW DID LOAD STUFF
override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboardWhenTappedAround()
self.customNoteField.delegate = self
}
//TIMING BUTTON PRESSED
#IBAction func timeButtonPressed(_ sender: UIButton) {
//GATHER DATA
let timingButtonInput = timeButtonArray[sender.tag]
let DTGstamp = dateTimeStamp()
//FORM STRING
let buttonData = ("\(DTGstamp) \(timingButtonInput) \n")
//SEND buttonDATA TO ReportViewController
/*??? The part I need help with*/
}
//CUSTOM ENTRY UITextfield PRESSED
#IBAction func customNoteDone(_ sender: Any) {
//GATHER DATA
let DTGstamp = dateTimeStamp()
let customNote = customNoteField.text
//FORM STRING
let customData = ("\(DTGstamp) \(customNote) \n")
//TEST FOR EMPTY TEXT
if customNote != "" {
//SEND customDATA TO ReportViewController
/*??? The part I need help with*/
}
//FUNCTION TO GENERATE DATE,TIME GROUP AS CONSTANT
func dateTimeStamp() -> String {
var date = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "ddLLLyy HH:mm:ss"
print (dateFormatter.string(from: date))
return (dateFormatter.string(from: date))
}
}
//
// ReportViewController.swift
// EMS Case Logger
//
// Created by Allan Ravenscroft on 3/3/19.
// Copyright © 2019 Allan Ravenscroft. All rights reserved.
//
import UIKit
class ReportViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var reportTextViewField: UITextView!
#IBOutlet weak var reportEmailButton: UIButton!
#IBOutlet weak var reportEditButton: UIButton!
#IBOutlet weak var reportClearButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
hideKeyboardWhenTappedAround()
reportEditButton.layer.cornerRadius = reportEditButton.frame.height / 2
reportEmailButton.layer.cornerRadius = reportEmailButton.frame.height / 2
reportClearButton.layer.cornerRadius = reportClearButton.frame.height / 2
}
//Actions when the clear button is pressed
#IBAction func clearButtonPressed(_ sender: Any) {
reportTextViewField.text = ""
}
//Actions when the edit button is pressed
#IBAction func editButtonPressed(_ sender: Any) {
}
//Actions when the email button is pressed
#IBAction func emailButtonPressed(_ sender: Any) {
showMailComposer(bodytext: reportTextViewField.text)
}
}
I know this is not a demo, but maybe can help you
Make a new NSObject file
inside the class put a new variable
import UIKit
class test: NSObject {
var a:String = ""
}
at your ViewController declare a new var referencing the class
let testVar = test()
in your customNote checker
test.a = customNote
then at your 2nd ViewController, do the same thing
let testVar = test()
testVar.a //this is your customNote String
hope this helps
I'm relatively new to programming and this is my first attempt at developing an iOS without following a tutorial, so please bear with me.
I have a custom table view called 'CupboardViewController' that returns four string labels based on a custom UITableViewCell class called 'ItemTableViewCell'. I want to be able to show those four labels in a separate view controller called 'detailViewController' when a user clicks on a table item.
This is the code I have but it's crashing with no obvious error message when the segue is called. Please help!
CupboardViewController
override func prepareForSegue(segue: UIStoryboardSegue,
sender: AnyObject!) {
// sender is the tapped `UITableViewCell`
let cell = sender as! ItemTableViewCell
let indexPath = self.tblItems.indexPathForCell(cell)
// load the selected model
let titleToPass = itemMgr.items[indexPath!.row].name
let detail = segue.destinationViewController as! detailViewController
// set the model to be viewed
detail.titleToPass = titleToPass
}
}
detailViewController
#IBOutlet weak var titleDetailLabel: UILabel!
#IBOutlet weak var qtyDetailLabel: UILabel!
#IBOutlet weak var dateDetailLabel: UILabel!
#IBOutlet weak var descriptionDetailLabel: UILabel!
var titleToPass: String!
var qtyToPass: String!
var descriptionToPass: String!
var dateToPass: String!
override func viewDidLoad() {
super.viewDidLoad()
titleDetailLabel.text = titleToPass
qtyDetailLabel.text = qtyToPass
dateDetailLabel.text = dateToPass
descriptionDetailLabel.text = descriptionToPass
}
// Do any additional setup after loading the view.
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
ItemTableViewCell
#IBOutlet weak var itemTitle: UILabel!
#IBOutlet weak var itemSubtitle: UILabel!
#IBOutlet weak var itemSubDetail: UILabel!
#IBOutlet weak var dateDetail: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
It is definitely best to avoid the force unwrap ! as much as possible, so I'd definitely recommend using guard let or if let in most cases. In addition to saving you from crashes, they also offer some great ways to see exactly where your code is failing that are otherwise tougher to track down.
For example, you have this line, which returns an optional NSIndexPath
let indexPath = self.tblItems.indexPathForCell(cell)
Rather than force unwrapping this optional, you can modify the line slightly to make it handle nil, and also add a print to tell you that this line failed, like this:
guard let indexPath = self.tblItems.indexPathForCell(cell) else {
print("No index path returned.")
return
}
If the value is not nil you can operate with the indexPath constant like you normally would. You'll probably want to continue this approach with most of these optionals, unless you're 100% sure they won't be nil in any situation.
As for your particular crash, you can correct me if I'm wrong, but I suspect it's because you have those four variables on your detailViewController that are being accessed in viewDidLoad, but you're only setting one of them in the segue. This means that in viewDidLoad you will be trying to access those (and they have the ! too), and since it won't find anything it'll crash immediately. See if fixing that, and getting rid of some of the !s helps.
I'm trying to make app that takes info from the two text fields and randomly selects one of the sentences and places it in a label on another view controller. I'm a student in the Mobile Apps 1 class so I'm new to this. If you could explain it as much as possible it will be greatly appreciated. Happy new year!
My code:
class twoIdeasViewController: UIViewController {
#IBOutlet weak var twoIdeaContinueButton: UIButton!
#IBOutlet weak var twoIdea2TextField: UITextField!
#IBOutlet weak var twoIdea1TextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Enter Ideas"
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
let twoIdea1:String = twoIdea1TextField.text!
let twoIdea2:String = twoIdea2TextField.text!
return true
}
func prepareForSegue(segue: UIStoryboardSegue, Object: AnyObject?){
let twoIdeaFinal = segue.destinationViewController as! twoFinalViewController
twoIdeaFinal.twoIdea = //the variable that will contain the randomizer
}
}
Make use of arc4random_uniform() to generate a random number that controls which of the two text fields you wish to extract and send text from. Also, you seem to need to fix up your prepateForSegue method: you need to match the segue identifier with the identifier of your 2nd view controller (set in attributes inspector while selecting this other view controller in your storyboard).
#IBOutlet weak var twoIdea2TextField: UITextField!
#IBOutlet weak var twoIdea1TextField: UITextField!
// ...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
/* Get the new view controller using segue.destinationViewController.
Pass the randomly chosen text view text to the UILabel of the
new view controller. */
/* Here: you need to match with the identifier of your
VC 'twoFinalViewController' (set in attributes inspector) */
if segue.identifier == "twoFinalVC" {
let viewController = segue.destinationViewController as! ViewController
let random = arc4random_uniform(2)
viewController.twoFinalLabel.text = (random == 0) ? (twoIdea1TextField.text ?? "") : (twoIdea2TextField.text ?? "")
}
}
For a detailed description covering segue communication between two view controllers (UITableViewController and UIViewController), see the following thread
Global variable and optional binding in Swift
You can use something like that
func getRandomString() -> String
{
let randomNumber = arc4random_uniform(2) + 1
switch randomNumber
{
case 1:
return twoIdea1TextField.text!
case 2:
return twoIdea2TextField.text!
default:
return ""
}
}
I have no time, but I think that with an enum is simpler than what I did.
I am using a master-detail model in Swift.
However, I want to send a class object created in detail view back to master view. I wrote a unwind function in the master view, but I cannot see the back button in the detail view so I cannot ctrl+drag it to the exit.
Does anyone know how to set the back button to make it visible?
Rather than worrying about hooking up something to the back button, you can update the model directly as the user updates the fields in the detail view controller. To do this you can pass a reference to some model object that contains the properties to be updated (make sure that's a reference type, e.g., a class, and not a struct, though).
For example:
class Person {
var firstName: String?
var lastName: String?
}
class MasterViewController: UIViewController {
#IBOutlet weak var firstNameLabel: UILabel!
#IBOutlet weak var lastNameLabel: UILabel!
var person = Person()
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destination = segue.destinationViewController as? DetailViewController {
destination.person = person
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
firstNameLabel.text = person.firstName
lastNameLabel.text = person.lastName
}
}
class DetailViewController: UIViewController,UITextFieldDelegate {
var person: Person?
#IBOutlet weak var firstNameTextField: UITextField!
#IBOutlet weak var lastNameTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
firstNameTextField.text = person?.firstName
lastNameTextField.text = person?.lastName
}
// Note, I specified the detail view controller to be the delegate
// for the two text fields in IB: I then can detect when editing is
// done and act accordingly.
func textFieldDidEndEditing(textField: UITextField) {
switch textField {
case firstNameTextField:
person?.firstName = textField.text
case lastNameTextField:
person?.lastName = textField.text
default:
assert(false, "unidentified textField \(textField)")
}
}
}
You can have master view controller update itself in viewDidAppear, like I did above, or, better, you could add observers for the model properties. But hopefully it illustrates the basic idea.
I think we all have been through problems in Swift. I wasn't able to find the correct answer for my question. I've tried over and over again.
I've represented an image where it explains how our app should works.
Users can select an option per view. So in a last one the Labels will change depending of each choose.
I hope you can give me a hand with that guys. Thanks
class ViewController1: UIViewController {
#IBOutlet weak var colorLabelSelected: UILabel!
#IBOutlet weak var nextOutlet: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
nextOutlet.hidden = true
}
#IBAction func greenButton(sender: AnyObject) {
colorLabelSelected.text = "You have selected a green BG color"
nextOutlet.hidden = false
}
#IBAction func blueButton(sender: AnyObject) {
colorLabelSelected.text = "You have selected a blue BG color"
nextOutlet.hidden = false
}
#IBAction func pinkButton(sender: AnyObject) {
colorLabelSelected.text = "You have selected a pink BG color"
nextOutlet.hidden = false
}
}
ViewController 2 and ViewController 3 are like ViewController 1
And I have created a .swift class called Attributes but It's empty for now.
I don't know how to make this work.
When you push your next viewController, override prepareForSegue method, get reference to your destinationViewController and pass to it information you need. This will help pass that data around.
Or create a singleton object, some kind of model, where you write the value user has selected on the first screen, and then on the second screen - you read the data from that singleton object.
Define your model, for example:
class MyData {
var background = UIColor()
var title = ""
var level = ""
}
Use appDelegate. In AppDelegate.swift,
var myData = MyData()
In other screens, for instance first screen, use
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.myData.background = yourColor
Same to others
use prepareForSeguefor your concept
for example
#IBAction func pinkButton(sender: AnyObject) {
colorLabelSelected.text = "You have selected a pink BG color"
nextOutlet.hidden = false
self.performSegueWithIdentifier("thirdController", sender: self)
}
override func prepareForSegue(segue:(UIStoryboardSegue!), sender:AnyObject!)
{
if (segue.identifier == "thirdController")
{
var svc = segue!.destinationViewController as! thirdController
print("i set the loading thingy")
svc.toPass = colorLabelSelected.text
}
}
ThirdViewController
create the global variable like
var toPass:String!
for tutorial reference see this link
you have to create array and create one property of array in second and third class and pass color in secondviewcontroller and in secondviewcontroller add title in array of property and pass it to thirdviewcontroller
you can easily manage using create property.