I'm having difficulty with IBOutlets. I'm trying to allow the user to input a goal (called nameOfRewardText) in a table view controller (LoLAddGoalsTableViewController) and then when they click "Done", have that goal show up in a label called "currentGoalTextField" in a different view controller (LoLGoalViewController). I had been trying to implement this using a Save segue, but was advised to use a protocol with a delegate instead (Updating text in ViewController using Save function). Now that I've replaced the Save segue with the protocol and delegate, the inputted "nameOfRewardText" text is not showing up in the "currentGoalTextField" label, I suspect because the IBOutlets are no longer tied together properly. I've attached the code and screenshots of the Outlets below to try to clarify where I'm at. Does anyone know how I could fix the IBOutlets or if there's something else I need to add to get this working? I deleted the line where I assign nameOfRewardText.text to be goal.goalText, so I think nameOfRewardText isn't getting assigned to var goal? Maybe I'm using too many names for this text (nameOfRewardText, goalText, and currentGoalTextField) and that's complicating things? Any help at all would be greatly appreciated, as I'm very new to this! Thank you everybody!
Here is the struct goal:
import UIKit
struct Goal {
var goalText: String
var pointsToCompleteGoal: Int
var pointsEarnedTowardsGoal: Int
var repeatGoal: Bool
init(goalText: String, pointsToCompleteGoal: Int, pointsEarnedTowardsGoal: Int, repeatGoal: Bool = false) { //Made String non-optional. If issue later, can revert.
self.goalText = goalText
self.pointsToCompleteGoal = pointsToCompleteGoal
self.pointsEarnedTowardsGoal = pointsEarnedTowardsGoal
self.repeatGoal = repeatGoal
}
}
Here is the public protocol:
import Foundation
import UIKit
protocol GoalDelegate: class {
func passGoal(_ goal: Goal?)
}
Here is where the delegate is created, and as you can see, the statement where I assign nameOfRewardText.text to be goal.goalText is now gone:
import UIKit
class AddGoalsTableViewController: UITableViewController {
var goal:Goal?
var delegate: GoalDelegate?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// HASHED OUT THE BELOW BECAUSE REPLACING WITH DELEGATE:
// if segue.identifier == "SaveGoal" {
// let pointsNeededInt = Int(pointsNeededText.text!)
// let pointsEarnedInt = Int(goalProgressText.text!)
// goal = Goal(goalText: nameOfRewardText.text!, pointsToCompleteGoal: pointsNeededInt!, pointsEarnedTowardsGoal: pointsEarnedInt!)
// }
if let secondViewController = segue.destination as? LoLGoalViewController{
delegate = secondViewController
delegate?.passGoal(goal)
}
}
#IBOutlet var goalTableTitleText : UILabel!
#IBOutlet weak var goalProgressText: UILabel!
#IBOutlet weak var nameOfRewardText: UITextField!
#IBOutlet weak var pointsNeededText: UITextField!
#IBOutlet weak var repeatSwitch: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Screen cap of AddGoalsTableViewController with Outlets:
Here I conform to the protocol and call the function passGoal:
import UIKit
class LoLGoalViewController: UIViewController, GoalDelegate {
#IBOutlet weak var currentGoalTextField: UILabel!
func passGoal(_ goal: Goal?) {
currentGoalTextField.text = goal?.goalText
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension LoLGoalViewController {
#IBAction func cancelToLoLGoalViewController(_ segue: UIStoryboardSegue) {
}
}
Screen cap of LoLGoalViewController with Outlets:
Your LoLGoalViewController view controller might not have fully loaded with all of its outlets. Adding on to my answer to your previous question, you can declare another variable in LolGoalViewController:
#IBOutlet weak var currentGoalTextField: UILabel!
var goalText: String = ""
In your passGoal method, set your string to the goalText variable instead of the label's text:
func passGoal(_ goal: Goal?) {
goalText = goal?.goalText
}
Lastly, in your viewDidLoad of LolGoalViewController, set the label text to be goalText:
override func viewDidLoad() {
super.viewDidLoad()
currentGoalTextField.text = goalText
}
Related
I want to try Combine framework, very simple usage, press a UIButton, and update UILabel.
My idea is:
Add a publisher
#Published var cacheText: String?
Subscribe
$cacheText.assign(to: \.text, on: cacheLabel)
assign a value when button pressed.
cacheText = "testString"
Then the label's text should be updated.
The problem is when the button pressed, the #Published value is updated, but the UILabel value doesn't change.
e.g the cacheLabel1 was assigned 123 initially but not 789 when button pressed.
Here's the full code:
ViewModel.swift
import Foundation
import Combine
class ViewModel {
#Published var cacheText: String?
func setup(_ text: String) {
cacheText = text
}
init() {
setup("123")
}
}
ViewController.swift
class ViewController: UIViewController {
#IBOutlet weak var cacheLabel: UILabel!
var viewModel = ViewModel()
#IBAction func buttonPressed(_ sender: Any) {
viewModel.setup("789")
}
override func viewDidLoad() {
super.viewDidLoad()
viewModel.$cacheText.assign(to: \.text, on: cacheLabel)
}
}
Not sure if I missed something, thanks for the help.
The pipeline is dying before you have a chance to tap the button. You have to preserve it, like this:
var storage = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
viewModel.$cacheText.assign(to: \.text, on: cacheLabel).store(in: &storage)
}
I am beginner in iOS development and I have implemented following screen using UICollectionView :
CollectionViewCell File Code is:
import UIKit
class EventCell: UICollectionViewCell{
var classEvent: Event?
#IBOutlet weak var eventTitle: UILabel!
#IBOutlet weak var eventTeams: UILabel!
#IBOutlet weak var eventTime: UILabel!
#IBOutlet weak var eventTeamOneImage: UIImageView!
#IBOutlet weak var eventTeamTwoImage: UIImageView!
#IBOutlet weak var leaderboardButton: UIButton!
var datasourceItem: Any?{
didSet{
guard let event = datasourceItem as? Event else { return }
classEvent = event
eventTitle.text = "Match \(event.matchNo) (\(event.matchStage))"
eventTeams.text = "\(event.teamOne.nameAttr) vs \(event.teamTwo.nameAttr)"
eventTime.text = "\(event.getEventLockTimeAsString())"
eventTeamOneImage.loadImageUsingCache(withUrl: event.teamOne.flagPhoto)
eventTeamTwoImage.loadImageUsingCache(withUrl: event.teamTwo.flagPhoto)
leaderboardButton.addTarget(self, action: #selector(handleLeaderBoardClick), for: .touchUpInside)
}
}
#IBAction func leagueButton(_ sender: Any) {
}
weak var delegate: HomeControllerDelegate?
func handleLeaderBoardClick() {
if let matchId = classEvent?.id {
print(matchId)
delegate?.clickOnLeaderBoard(matchId: matchId)
}
}
}
Now on click on Leaderboard button(icon with 1,2,3) I would like to open new LeaderBoard Controller and pass matchId which is classEvent.id
How can I pass values to the new controller? And what is the best way to do that.
You can pass the match Id via segue:
In LeaderBoard Controller set a property:
var matchId:Int?
Set a segue between the controller and add an identifier:
On Click leaderboard button:
self.performSegueWithIdentifier("yourSegueIdentifier", sender: self)
Add the segue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue,identifier == "yourSegueIdentifier" {
let destinationVC = segue.destinationViewController as LeaderbardController
destinationVC.matchId = classEvent.id
}
}
}
Three easy steps to get what u want:
Make a BaseViewController class a subclass of UiViewController. This class would be the alternate of UiViewcontroller in your project,it means while creating any viewcontroller BaseViewController will be the parent class.
Declare a variable in BaseViewController.e.g- var data: Any?
Then while moving from a viewcontroller to another , simply assign any type of data to that variable declared in BaseViewController.
And in any lifecycle method of your new viewcontroller you will get that data using self.data.
I have a problem I can't seem to solve myself, I have two view controllers, the first one contains three variables that stores integers. On my second view controller I have 3 sliders which manipulates a label under each slider with a number.
I want the numbers from these 3 sliders to replace the numbers that were set in the three variables on my first view controller when I click a button on the second view controller but when I when I type in the variable name it doesn't show up in the second view controller?
Can somebody explain what I may be doing wrong as I thought the variables were public and globally accessible throughout my app but I'm struggling to figure out what I'm doing wrong.
Here is some of my code:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var timer = Timer()
var softTime = 180
var mediumTime = 300
var hardTime = 600
var chosenTime = 0
I want softTime, mediumTime & hardTime to be changed from the button in the next view controller:
import UIKit
class SettingsViewController: UIViewController {
#IBOutlet weak var softLabel: UILabel!
#IBOutlet weak var softSliderValue: UISlider!
#IBAction func softSlider(_ sender: Any) {
let currentValue = Int(softSliderValue.value)
softLabel.text = "\(currentValue)"
}
#IBOutlet weak var mediumLabel: UILabel!
#IBOutlet weak var mediumSliderValue: UISlider!
#IBAction func mediumSlider(_ sender: Any) {
let currentValue = Int(mediumSliderValue.value)
mediumLabel.text = "\(currentValue)"
}
#IBOutlet weak var hardLabel: UILabel!
#IBOutlet weak var hardSliderValue: UISlider!
#IBAction func hardSlider(_ sender: Any) {
let currentValue = Int(hardSliderValue.value)
hardLabel.text = "\(currentValue)"
}
#IBAction func setTimesButton(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
//in Second VC
protocol PassDataDelegte: class {
func your method(first: String, second: String, third: String)
}
weak var delegate: PassDataDelegte?
func youction button() {
delegate?.yourmethod(first, timeString: second, third: date)
}
// in First VC
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DeadlineSegue" {
let dvc = segue.destinationViewController as! YourSecondViewController
dvc.delegate = self
}
}
extension YourFirstViewController: PassDataDelegte {
func sendDateTime((first: String, second: String, third: String) {
print(first)
print(second)
print(third)
}
i try to create my first application on Xcode ,first I tried only to overwrite the text of a label at same moment when it is write in a TextField.
Now I try just for fun , to set hidden a second label (Label2) from Utility area and with the button ok to keep these unhide but the I'll give error (Thread 1 :breakpoint 1.1).
After I try solve the problem, I think to save the text in a var String and when I press the "ok" button , it set the Label2.text=String.
Anyway ,When I build and run this code it give the same ERROR .
Anyone can help me ?
thanks
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var labelTitle: UILabel!;
#IBOutlet weak var labelRes: UILabel!;
#IBOutlet weak var textReceveirer: UITextField!;
var myString : String = " "
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func button(_ sender: UIButton) {
myString=textReceveirer.text!
labelRes.text = "hello \(myString)"
}
}
Try with the following code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var labelOne: UILabel!;
#IBOutlet weak var textReciver: UITextField!;
override func viewDidLoad() {
super.viewDidLoad()
labelOne.text = " "
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func button(_ sender: UIButton) {
labelOne.text = textReciver.text
}
}
I think the error is at line
var String=""
String is data type ,
if you want to create variable type of string you may use follow this
var myVariable : String = ""
write in your code var String=""that replace with
var Variable : String = ""
or check that connection inspector..
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.