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.
Related
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
}
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've a tableView with a cell for each pokemon in the "pokedex". When I press a button in the Cell, I want to show a view with details about this creature.
What I do is that I have a global variable "currentPokemon", that I set to the requested pokemon when the button is pressed. Here's my code for the Cell :
class PokemonTableViewCell: UITableViewCell {
var pokemon: Pokemon!
#IBOutlet weak var pokemonImage: UIImageView!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var releaseDateLabel: UILabel!
#IBAction func setPokemon(sender: UIButton) {
currentPokemon = self.pokemon
}
}
When I try to access the currentPokemon var in the details view, I get a fatal error because currentPokemon is nil. How could I get this code to be executed before the segue ?
You need to add store for selected Pokemon with singleton instance like:
struct Pokemon {
let name: String
}
class PokemonStore {
static let instance = PokemonStore()
var currectPokemon: Pokemon?
}
Later you can get saved pokemon in any place of your code with PokemonStore.instance.currectPokemon
If you are using segue, you should pass data to detail controller in this UIViewController method:
func performSegue(withIdentifier identifier: String, sender: Any?)
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 have a UITextField on one ViewController and I want to be able to have a Label on the second ViewController = whatever the user enters.
However, I get an error when trying to do this. I know Swift doesn't use import so I'm not sure what to do.
// First View Controller
#IBOutlet weak var textOne: UITextField!
// Second View Controller
#IBOutlet weak var theResult: UILabel!
theResult.text = textOne.text
Error: Unresolved Identifier
It looks like that you in reality want to just access the text from the UITextField and not the field itself. So you should send the text to the second ViewController from your first one by using prepareForSegue.
But before, you have to set the name of your segue so that Swift knows which data to send:
As you see, we name the segue segueTest.
So now we can implement the prepareForSegue-method in the FirstViewController and set the data which should be sent to the second.
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "segueTest") {
var svc = segue!.destinationViewController as secondViewController;
svc.theText = yourTextField.text
}
}
That you can do that, you have to set a variable in your SecondViewController of course:
var theText:String!
You need to pass a reference to your FirstViewController instance to the SecondViewController instance at prepearForSegue...
Then do something like this
//FirstViewController
#IBOutlet weak var textOne: UITextField!
func getTextOne () -> String? {
return textOne.text
}
//SecondViewController
#IBOutlet weak var theResult: UILabel!
var firstViewControllerInstance: FirstViewController?
func showResult () {
theResult.text = firstViewControllerInstance?.getTextOne()
}
And you are done