Segue is not being transferred in (swift 3) - ios

I am making a game that when a button is pressed twice, it will transfer to another view controller. Right now the users reaction time is timed in view controller a. I would like the time to be segued to view controller b and when in view controller b the time be subtracted by 1. Right now the time is not being segued. When the button is pressed twice the view controller changes but the text is not being transferred.
import UIKit
class ViewController: UIViewController {
#IBOutlet var labelx: UILabel!
#IBOutlet var startx: UIButton!
#IBOutlet var pressSoccerBall: UIButton!
var level = 0
var timer: Timer?
var isRunning: Bool {
get {
return timer != nil
}
}
var counter = 0.0
override func viewDidLoad() {
super.viewDidLoad()
labelx.text = String(format: "%.1f", counter)
startx.isEnabled = true
}
#IBAction func startTimer(_ sender: Any) {
if isRunning {
return
}
refreshTimer()
}
#IBAction func PressSoccerBall(_ sender: Any) {
level += 1
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let DestViewController : winViewController = segue.destination as! winViewController
DestViewController.LebelText = labelx.text!
}
func refreshTimer() {
if let timer: Timer = timer {
timer.invalidate()
}
timer = Timer.scheduledTimer(timeInterval: 0.1,target: self,selector: #selector(updateTimer),userInfo: nil, repeats: true)
startx.isEnabled = false
}
func updateTimer() {
counter += 0.1
labelx.text = String(format: "%.1f", counter)
if counter < 9.9 && level == 2 {
let nextc = self.storyboard?.instantiateViewController(withIdentifier: "winViewController") as? winViewController
self.present(nextc!, animated: true, completion: nil)
}
}
}
VIEW CONTROLLER B
import UIKit
class winViewController: UIViewController {
#IBOutlet var winningLabel: UILabel!
public var LebelText: String?
override func viewDidLoad() {
super.viewDidLoad()
steve()
}
func steve(){
guard let unwrapedText = self.LebelText else {
return
}
if let myInt = Double(unwrapedText){
let myInt = myInt - 1
self.winningLabel.text = String(myInt)
} else {
return
}
}
}

You're not using segues. You are creating the winViewController and then calling present to show it. So, prepareForSegue will never be called.
Simply set the LebelText property on nextc before presenting it:
func updateTimer() {
counter += 0.1
labelx.text = String(format: "%.1f", counter)
if counter < 9.9 && level == 2 {
if let nextc = self.storyboard?.instantiateViewController(withIdentifier: "winViewController") as? winViewController {
nextc.LebelText = labelx.text
self.present(nextc, animated: true, completion: nil)
}
}
}

Related

Swift NSTiimer not following specified Interval

I am trying to create a quiz app which has a timer for each question when the timer expires (i.e. 10 seconds and I want Timer to have an interval of 1 sec) it resets it self and next question is fetched and Timer again restart from 10... But my issue is the timer doesn't follow a fixed interval when first question is loaded it shows interval of 2 ... i.e. 10,8,6 .. and then for second question it makes jump for 3 secs interval and similarly the interval increases.
import UIKit
class ViewController: UIViewController {
let allQuestions = QuestionsBundle()
var pickedAnswer : Int = 0
var questionCounter = 0
var score : Int = 0
var timer: Timer!
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var countDownLabel: UILabel!
#IBOutlet weak var ansLbl1: UILabel!
#IBOutlet weak var ansLbl2: UILabel!
#IBOutlet weak var ansLbl3: UILabel!
#IBOutlet weak var ansLbl4: UILabel!
#IBOutlet weak var checkBox1: CheckBox!
#IBOutlet weak var checkBox2: CheckBox!
#IBOutlet weak var checkBox3: CheckBox!
#IBOutlet weak var checkBox4: CheckBox!
var checkBoxlist : [CheckBox] = []
#IBAction func correct_Answer_Checbox_Btn(_ sender: AnyObject) {
//print("\(sender.tag) <==> \(String(describing: question?.correctAnswer))")
updateCheckBoxes(sender: sender)
if sender.tag == question?.correctAnswer{
question?.isAnswerCorrect = true
question?.selectedAnswer = sender.tag
//score = score + 1
}
else {
question?.isAnswerCorrect = false
}
}
func updateCheckBoxes(sender: AnyObject){
for checkBoxItem in checkBoxlist{
if checkBoxItem.tag != sender.tag {
checkBoxItem.isChecked = false
}
}
}
#IBOutlet weak var nextButton: UIButton!
#IBAction func nextBtnClicked(_ sender: AnyObject) {
do{
try handleNextQuestion()
}
catch{
moveToResultView()
}
}
func handleNextQuestion() throws {
nextQuestion()
if questionCounter == allQuestions.list.count-1{
finishButton.isHidden = false
nextButton.isHidden = true
//scoreLbl.text = "\(score)"
}
}
var question : Question?
var countTime = 10.0
override func viewDidLoad() {
super.viewDidLoad()
finishButton?.isHidden = true
checkBoxlist = fetchCheckBoxList()
question = fetchQuestion()
setQuizView(question: question!)
// Do any additional setup after loading the view, typically from a nib.
}
// set all questions in a function
#objc func update() {
if(countTime > 0) {
countTime = countTime - 1
self.countDownLabel.text = String(countTime)
}else{
timer.invalidate()
countTime = 10.0
do{
try handleNextQuestion()
}
catch{
moveToResultView()
}
}
}
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(ViewController.update), userInfo: nil, repeats: true)
}
func setQuizView(question:Question) {
self.countDownLabel.text = "10"
startTimer()
questionLabel.text = question.questionText
ansLbl1.text = question.answer1
ansLbl2.text = question.answer2
ansLbl3.text = question.answer3
ansLbl4.text = question.answer4
if question.selectedAnswer == Constants.DEFAULT_ANSWER {
for checkBoxItem in checkBoxlist{
checkBoxItem.isChecked = false
}
}
}
#IBOutlet weak var finishButton: UIButton!
// prepare segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == resultScreenIdentifier{
let vc = segue.destination as! ResultViewController
vc.data = sender as! String
}
}
let resultScreenIdentifier = "resultScreenSegue"
func moveToResultView(){
performSegue(withIdentifier: resultScreenIdentifier, sender: score)
}
#IBAction func finishButtonClicked(_ sender: UIButton) {
//perform segue
let score = "\(calculateScore())"
moveToResultView()
}
// calculate the score of quiz using loop
func calculateScore()->Int{
var numOfCorrectAnswers = 0
for question in allQuestions.list{
if question.isAnswerCorrect {
numOfCorrectAnswers = numOfCorrectAnswers + 1
//print(numOfCorrectAnswers)
}
}
return numOfCorrectAnswers
}
func nextQuestion(){
showResultView(isCorrect: (question?.isAnswerCorrect)!)
questionCounter = questionCounter + 1
question = fetchQuestion()
setQuizView(question: question!)
}
func fetchQuestion() -> Question{
return allQuestions.list[questionCounter]
}
func fetchCheckBoxList() -> [CheckBox]{
let arr : [CheckBox] = [checkBox1,checkBox2,checkBox3,checkBox4]
return arr
}
}
Timers are not particularly accurate. They can suffer from significant jitter.
A better approach is to create a Date that represents the expiration time (ie Date(timeIntervalSinceNow:10) and then run a Timer with a much shorter interval (I would suggest around 0.1 second). You can then calculate the time remaining based on the target Date and check if the target date is in the past.

Is it possible to toss data to another view controller?

I just Make timer that can use in life. just like image that I push in here, if I go back to main ViewController then I wanna the number that I input in set view controller are tossed to viewController so when I go back to main ViewController and press restart then that number gonna be in text of CountTimeLabel.. but I really don't know how to toss data that I input in another view controller to root viewController... pleas help me.. if I write code like ViewController().variableName = 30 in setViewController, that dose not make things well..(I already know about prepare function but that is not what I am finding..because this is happen when I go back to ViewController(RootViewController)) I will put my code in below..
is it possible to toss data to another view controller from other view controller?
import UIKit
class ViewController: UIViewController{
#IBOutlet var AllTileLabel: UILabel!
#IBOutlet var SumTimeLabel: UILabel!
#IBOutlet var CountTimeLabel: UILabel!
#IBOutlet var StartButton: UIButton!
#IBOutlet var StopButton: UIButton!
#IBOutlet var ResetButton: UIButton!
var timeTrigger = true
var realTime = Timer()
var second : Int = 3000
var sum : Int = 14400
var allTime : Int = 14400
var IntSecond : Int = 0
var ifReset = false
override func viewDidLoad() {
StartButton.layer.cornerRadius = 10
StopButton.layer.cornerRadius = 10
ResetButton.layer.cornerRadius = 10
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func StartButtonAction(_ sender: UIButton) {
if timeTrigger { checkTimeTrigger() }
print("Start")
}
#IBAction func StopButtonAction(_ sender: UIButton) {
endGame()
}
#IBAction func ResetButtonAction(_ sender: UIButton) {
print(second)
getTimeData()
//second = 3000
//CountTimeLabel.text = "0:50:00"
CountTimeLabel.text = printTime(temp: second)
ifReset = true
}
#IBAction func Reset(_ sender: UIButton) {
endGame()
timeTrigger = true
realTime = Timer()
second = 3000
sum = 14400
allTime = 14400
IntSecond = 0
ifReset = false
AllTileLabel.text = "8:00:00"
SumTimeLabel.text = "0:0:0"
CountTimeLabel.text = "0:50:00"
}
#objc func updateCounter(){
// if String(format: "%.2f",second) == "0.00"{
if second < 1 {
endGame()
CountTimeLabel.text = "종료"
} else {
second = second - 1
sum = sum + 1
allTime = allTime - 1
AllTileLabel.text = printTime(temp: allTime)
SumTimeLabel.text = printTime(temp: sum)
CountTimeLabel.text = printTime(temp: second)
print("update")
}
}
func checkTimeTrigger() {
realTime = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)
timeTrigger = false
}
func endGame() {
realTime.invalidate()
timeTrigger = true
}
func printTime(temp : Int) -> String
{
let S = temp%60
let H = temp/3600
let M = temp/60 - H*60
let returnString = String(H) + ":" + String(M) + ":" + String(S)
return returnString
}
func getTimeData() {
second = 20
sum = SetViewController().real.sum
allTime = SetViewController().real.allTime
print(second)
}
}
import UIKit
class SetViewController: UIViewController {
#IBOutlet var View1: UIView!
#IBOutlet var View2: UIView!
#IBOutlet var InputView1: UIView!
#IBOutlet var InputView2: UIView!
#IBOutlet var SetButton: UIButton!
#IBOutlet var H1TextField: UITextField!
#IBOutlet var M1TextField: UITextField!
#IBOutlet var H2TextField: UITextField!
#IBOutlet var M2TextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
H1TextField.keyboardType = .numberPad
M1TextField.keyboardType = .numberPad
H2TextField.keyboardType = .numberPad
M2TextField.keyboardType = .numberPad
View1.layer.cornerRadius = 14
View2.layer.cornerRadius = 14
InputView1.layer.cornerRadius = 10
InputView2.layer.cornerRadius = 10
SetButton.layer.cornerRadius = 10
// Do any additional setup after loading the view.
}
#IBAction func SetButton(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
enter image description here
If you're a hobbyist programmer and you just want to "get it done", simply use a static.
Let's say Bottom: UIViewController is the "main", root, view controller at the absolute "base" of your app. no matter what happens "Bottom" is always there.
Say Timer: UIViewController is (any) other view controller you put on top for some reason.
In Bottom, do this
class Bottom: UIViewController, etc ... {
static weak var current: Bottom? = nil
override func viewDidLoad() {
super.viewDidLoad()
Bottom.current = self
}
func testing() {
print("it works, WTH")
}
Note that in ViewDidLoad, you simply set it.
Next, say you are in Timer, try this:
class Timer: UIViewController, etc ... {
func someFunction() {
Bottom.current.testing() // it's that easy
}
It's that easy.
Note there is a huge amount of confusion about using statics, singletons, and similar approaches in iPhone programming.
(Just for example, many engineers will say "avoid singletons!" This is remarkably confused because in iOS engineering, almost everything is a singleton (notably the app itself (!!!!!), the screen, the GPS, etc etc.)
In any event, as a beginner hobbyist, learn how to use statics (it's simple .. Bottom.current. ... as above), and eventually you can learn about the pros and cons of such things.

How to open a embedded segue controller from another controller?

I am making an app following the same design approach of this app https://github.com/Bailig/SurveyApp .
In the above GitHub project the controllers are designed in such a way like a common ViewController with ContainerView inside.And also this common ViewController is Embed Segue with the First Controller or very first page. The container view is getting replaced for all the next screens.
In the above project there is a thank you page in the last, in my app I placed a button on the thank you page. I want to open the very first page again on click of the button from thank you page. How can I do that from last page controller/FourthController?
ViewController
class ViewController: UIViewController {
var currentController: UIViewController?
var pageIndex = 1
var survey = Survey()
#IBOutlet weak var backButton: UIButton!
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var progressLabel: UILabel!
#IBAction func nextTapped(_ sender: Any) {
switch pageIndex {
case 1:
let nextController = storyboard?.instantiateViewController(withIdentifier: "SecondController")
if let fromController = currentController, let toController = nextController as? SecondController {
toController.survey = survey
moveAndSizeChildControllers(fromController: fromController, toController: toController)
pageIndex += 1
setButtonAndProgressLabel()
}
case 2:
let nextController = storyboard?.instantiateViewController(withIdentifier: "ThirdController")
if let fromController = currentController, let toController = nextController as? ThirdController {
toController.survey = survey
moveAndSizeChildControllers(fromController: fromController, toController: toController)
pageIndex += 1
setButtonAndProgressLabel()
}
case 3:
let nextController = storyboard?.instantiateViewController(withIdentifier: "FourthController")
if let fromController = currentController, let toController = nextController as? FourthController {
toController.survey = survey
moveAndSizeChildControllers(fromController: fromController, toController: toController)
pageIndex += 1
setButtonAndProgressLabel()
}
default:
break
}
}
#IBAction func backTapped(_ sender: Any) {
switch pageIndex {
case 2:
let nextController = storyboard?.instantiateViewController(withIdentifier: "FirstController")
if let fromController = currentController, let toController = nextController as? FirstController {
toController.survey = survey
moveAndSizeChildControllers(fromController: fromController, toController: toController)
pageIndex -= 1
setButtonAndProgressLabel()
}
case 3:
let nextController = storyboard?.instantiateViewController(withIdentifier: "SecondController")
if let fromController = currentController, let toController = nextController as? SecondController {
toController.survey = survey
moveAndSizeChildControllers(fromController: fromController, toController: toController)
pageIndex -= 1
setButtonAndProgressLabel()
}
default:
break
}
}
#IBOutlet weak var backTapped: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
currentController = segue.destination
if let firstController = currentController as? FirstController {
firstController.survey = survey
}
setButtonAndProgressLabel()
}
func moveAndSizeChildControllers(fromController: UIViewController, toController: UIViewController) {
fromController.willMove(toParentViewController: nil)
toController.view.frame = containerView.bounds
addChildViewController(toController)
containerView.addSubview(toController.view)
// animatin
toController.view.alpha = 0
UIView.animate(withDuration: 0.5, animations: {
toController.view.alpha = 1
fromController.view.alpha = 0
}) { (completed) in
fromController.view.removeFromSuperview()
fromController.removeFromParentViewController()
toController.didMove(toParentViewController: self)
self.currentController = toController
}
}
}
You can manage it by using Notification
Add in ViewController (main)
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(navigateToFirstPage), name:NSNotification.Name(rawValue:"NavigateToFirstPage") , object: nil)
}
#objc private func navigateToFirstPage() {
pageIndex = 2
self.backTapped(UIButton())
}
Add in you fourthViewController
// This is your button from where you need to perform action
#IBAction func thanksButtonAction(_ sender: Any) {
NotificationCenter.default.post(name: NSNotification.Name(rawValue:"NavigateToFirstPage"), object: nil)
}
I would better use delegation pattern. It's simple to manage and easily to understand.
On the top of FourthController after imports you need to add
protocol FourthControllerThankDelegate {
func didTapYourButton()
}
and then add the variable inside that class
class FourthController: UIViewController {
weak var delegate: FourthControllerThankDelegate?
...
}
then you need to call didTapYourButton() inside your button action handler
#IBAction func thanksButtonTapped(_ sender: Any) {
delegate?.didTapYourButton()
}
then inside your ViewController function nextTapped: you need to set this view controller as a delegate to FourthController
case 3:
... // I have skipped code above
toController.delegate = self
setButtonAndProgressLabel()
}
and finally you need to handle delegate action
extension ViewController: FourthControllerThankDelegate {
func didTapYoutButton {
pageIndex = 2
backTapped(self)
}
}
As you do that, backTapped handler will move you to first page. This is not the best way to move back. To improve that you can create a function "displayMeFirstPage" and move there part of the logic from backTapped() case: 2 and call it inside that case and inside delegate handler. There are a lot of ways to improve navigation. if you have any questions please let me know.

Code crashing in during runtime

I am learning swift3 programming but after executing my calculator app its crashing in between. Please check the below code.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var aLabel: UILabel!
#IBOutlet weak var commmon_button: UIButton!
var a: Int?
var b: Int?
var sum: Int?
var val = ""
#IBOutlet weak var text_feild: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func clik_button(_ sender: UIButton) {
val=String(sender.tag)
text_feild.text = text_feild.text! + val
}
#IBAction func fn_addition(_ sender: UIButton) {
a = Int(text_feild.text!)
}
#IBAction func fn_answer(_ sender: UIButton) {
b = Int(text_feild.text!)
sum = a! + b!
a = 0
b = 0
text_feild.text = nil
text_feild.text = String(sum!)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
During run time i am getting crash at fn_addition by saying Thread 1 breakpoint 2.1
Initiliaze your variables as below
var a = 0
var b = 0
var sum = 0
Replace your methods with below methods.
#IBAction func clik_button(_ sender: UIButton) {
guard let value = String(sender.tag), let text = text_feild.text
else {
return
}
text_feild.text = text + value
}
#IBAction func fn_addition(_ sender: UIButton) {
guard let aValue = Int(text_feild.text)
else{
return
}
a = aValue
}
#IBAction func fn_answer(_ sender: UIButton) {
guard let bValue = Int(text_feild.text)
else{return}
b = bValue
sum = a + b
a = 0
b = 0
text_feild.text = ""
text_feild.text = String(sum)
}
Suggestion: You are using same text field for taking a , b values and for showing sum result. It is better to use two different text fields for taking a and b values separately. Take a label to show sum value.

How can I do this with one segue?

I want to pass movies's data to another controller also pass another controller when progress is finished.Can I do this with one segue ?
class LoadingScreenViewController: UIViewController {
var movies = [Movie]()
#IBOutlet weak var progress: UIProgressView!
#IBOutlet weak var countLabel: UILabel!
override func viewDidLoad()
{
NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(LoadingScreenViewController.updateProgress), userInfo: nil, repeats: true)
progress.setProgress(0, animated: true)
}
func updateProgress () {
if progress.progress != 1 {
self.progress.progress += 2 / 10
} else {
UIView.animateWithDuration(0.4, animations: { () -> Void in
})
performSegueWithIdentifier("segue", sender:self)
progress.hidden = true
self.countLabel.hidden = true
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
let controller : SearchViewController = segue.destinationViewController as! SearchViewController
if segue.identifier == "segue"{
controller.model = movies
}
}
}
Do following:-
extension UIViewController {
func addSearchController() {
let searchController = UISearchController(searchResultsController: nil)
self.view.addSubview(searchController.searchBar)
}
}
Just call self.addSearchController() method in viewDidLoad method of required VC. No need to pass SearchController.

Resources