Swift: Calling Functions from different View Controllers - ios

Im very new to swift, I have a tabbed page app with 5 different view controllers and 5 different view controller.swift files.Each view controller has similar Syntax but a few names and labels are different. Each controller has a function that will restart my data values and they all work per page. but what I am trying to do, is access the clear functions from each view controller by just pressing one button from one view controller. My formatting/logic may be completely off. Im teaching myself so any help is appreciated
import UIKit
class FirstViewController: UIViewController {
// North wing
var nTotal = 0
var total = 0
//Stepper Values
#IBOutlet weak var tStepper: UIStepper!
#IBOutlet weak var cStepper: UIStepper!
#IBOutlet weak var ssStepper: UIStepper!
#IBOutlet weak var sStepper: UIStepper!
//-Tables
#IBOutlet weak var Tables: UILabel!
#IBAction func TCounter(_ sender: UIStepper) {
Tables.text = String(Int(sender.value))
}
//-Carrels
#IBOutlet weak var Carrels: UILabel!
#IBAction func CCounter(_ sender: UIStepper) {
Carrels.text = String(Int(sender.value))
}
//-Soft Seating
#IBOutlet weak var SoftSeating: UILabel!
#IBAction func SSCounter(_ sender: UIStepper) {
SoftSeating.text = String(Int(sender.value))
}
//-Standing
#IBOutlet weak var Standing: UILabel!
#IBAction func SCounter(_ sender: UIStepper) {
Standing.text = String(Int(sender.value))
}
//-Clear Pop-up
#IBAction func Clear(_ sender: UIButton) {
let alert = UIAlertController(title: "Clear", message: "Clear all or current page?", preferredStyle: .alert)
let clearPage = UIAlertAction(title: "Clear Page", style: .default, handler: {ACTION in
self.nClear()
})
let clearAll = UIAlertAction(title: "Clear All", style: .destructive, handler: {ACTION in
self.MasterClear()
})
let Cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addAction(clearPage)
alert.addAction(clearAll)
alert.addAction(Cancel)
self.present(alert, animated: true, completion: nil)
}
This is the clear function on all of my view controllers
//Clear Function
func nClear() {
self.Tables.text = "0"
self.Carrels.text = "0"
self.SoftSeating.text = "0"
self.Standing.text = "0"
//Stepper Clear
self.tStepper.value = 0
self.cStepper.value = 0
self.ssStepper.value = 0
self.sStepper.value = 0
}
This is the function that I want to be able to access all the clear functions I have on every Controller
//Clear all Function
func MasterClear(){
self.nClear()
SecondViewController().iLClear()
}
my code breaks and app crashes when I run and access the master clear function

What you really want to do is make a model of the data you want to share between the different views one for each of your views. I will do a sample with one. create a swift file for your data model like this:
class TestModel {
var Tables: String = "0"
var Carrels: String = "0"
var SoftSeating: String = "0"
var Standing: String = "0"
//Stepper Clear
var tStepper: Int = 0
var cStepper: Int = 0
var ssStepper: Int = 0
func modelReset() {
Tables = "0"
Carrels = "0"
SoftSeating = "0"
Standing = "0"
tStepper = 0
cStepper = 0
ssStepper = 0
}
}
next in your first view controller add a variable that is an instance of the model
class FirstViewController: UIViewController {
var modelController: TestModel!
and in your viewDidLoad function initialize the variable
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
modelController = TestModel()
}
create your clear function. I called mine reset:
#IBAction func reset(_ sender: Any) {
//Do for each ViewConrtoller
modelController.modelReset()
}
now override the prepare function to send the data to the view controller we are going to
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondViewController = segue.destination as? SecondViewController {
secondViewController.modelController = modelController
}
}
now in your second view controller create a variable of the model but in this instance we will not initialize it in the viewDidLoad function.
class SecondViewController: UIViewController {
var modelController: TestModel!
we don't initialize it as we are passing it from the first view controller in our prepare function.
in the second view controllers viewWillApear function update the view with the data from the model
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.Tables.text = modelController.Tables
self.Carrels.text = modelController.Carrels
self.SoftSeating.text = modelController.SoftSeating
self.Standing.text = modelController.Standing
//Stepper Clear
self.tStepper.value = modelController.tStepper
self.cStepper.value = modelController.cStepper
self.ssStepper.value = modelConroller.ssStepper
}
one last step don't forget to implement the prepare function to pass the model back to the first view controller in case you have updated it
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondViewController = segue.destination as? SecondViewController {
secondViewController.modelController = modelController
}
}

Related

Why isn't the score showing up after segue on different view controller?

Iv created a quiz app, that tracks the user's score till the user gets to the end. There is an if statement - when it reaches the end of the quiz, a results View controller pops up. My Question is I want to get the same score value presented at the end on the resultsViewContoller. I have connected it via segue and the identifier has been placed. The app runs but when i get to the end the segue opens up the page but the score doesnt change?
How can i solve this problem?
The user finishes the app. I call the segue method and the screen comes up.
Results View Controller
import UIKit
class ResultsViewController: UIViewController {
var fruitness = Fruitness()
#IBOutlet weak var finalScoreLabel: UILabel!
var finalScore: String!
override func prepare(for: UIStoryboardSegue, sender: Any?) {
func viewWillAppear(_ animated: Bool) {
finalScoreLabel.text = finalScore
if finalScore != nil {
finalScoreLabel.text = "FINALSCORE:\(String(describing: Int(finalScore!)))"
}
}
}
}
Game View Controller
import UIKit
class GameViewController: UIViewController {
#IBOutlet weak var progressBar: UIProgressView!
#IBOutlet private weak var fruitLabel: UILabel!
#IBOutlet private weak var scoreLabel: UILabel!
#IBOutlet weak var replayGame: UIButton!
#IBOutlet weak var optionButton0: UIButton!
#IBOutlet weak var optionButton1: UIButton!
#IBOutlet weak var optionButton2: UIButton!
#IBOutlet weak var optionButton3: UIButton!
#IBOutlet weak var optionButton4: UIButton!
#IBOutlet weak var optionButton5: UIButton!
#IBOutlet weak var optionButton6: UIButton!
#IBOutlet weak var optionButton7: UIButton!
#IBOutlet weak var optionButton8: UIButton!
#IBOutlet private var fruitButtons: [UIButton]!
var score = 0
var fruitness = Fruitness()
override func viewDidLoad() {
super.viewDidLoad()
updateUI()
}
#IBAction func replayGame(_ sender: UIButton) {
fruitness.restartGame() //Calling restart
updateUI()
}
#IBAction func touchButton(_ sender: UIButton) {
let userAnswer = sender.currentTitle!
//The userGotItRight is = to the checkAnswer function which goes through the fruitOptions array to make sure the answer is corrct. T/F
let userGotItRight = checkAnswer(userAnswer: userAnswer)
if userGotItRight {
//Depending if the user got the answer correct the button turns green/red
sender.backgroundColor = UIColor.green
} else {
sender.backgroundColor = UIColor.red
}
nextFruit() //Calling the next Fruit untill all the fruit items have been displayed.
//This timer is responsible for the UIColors green, red and clear. Without this timer the color drags onto the next fruit.
Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(updateUI), userInfo:nil, repeats: false)
}
// This check answer method needs an input to work. The input is the answer the user-choose (String).
func checkAnswer(userAnswer: String) -> Bool {
// Checks if the user got the answer correct. T/F
if userAnswer == fruitness.fruitOptions[fruitness.fruitNumber].fruit {
fruitness.score += 1 //We increase the value of score when we get the answer right.
// fruitness.finalScorez = fruitness.score
return true
} else {
return false
}
}
//Checks to make sure the eveytime it hits 0 it will shuffle.
func nextFruit() {
if fruitness.fruitNumber == 0 {
fruitness.fruitOptions.shuffle()
}
// print(fruitness.fruitOptions[fruitness.fruitNumber]) //Only gets printed in the consol
if fruitness.fruitNumber + 1 < fruitness.fruitOptions.count {
fruitness.fruitNumber += 1
} else {
self.performSegue(withIdentifier: "goToResultsVC", sender: self) //To call Segue
}
}
//Connecting and controlling oF the Segue and from GameView COntroller -> Results view controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToResultsVC" {
let destinationVC = segue.destination as! ResultsViewController
destinationVC.finalScore = scoreLabel.text //Printing the final score at the end.
}
}
#objc func updateUI() {
//Controlls the background. Clearing ability between T/F answers.
optionButton0.backgroundColor = UIColor.clear
optionButton1.backgroundColor = UIColor.clear
optionButton2.backgroundColor = UIColor.clear
optionButton3.backgroundColor = UIColor.clear
optionButton4.backgroundColor = UIColor.clear
optionButton5.backgroundColor = UIColor.clear
optionButton6.backgroundColor = UIColor.clear
optionButton7.backgroundColor = UIColor.clear
optionButton8.backgroundColor = UIColor.clear
//The fruit name available that the user needs to match.
fruitLabel.text = fruitness.getFruitText()
//Displaying the progress of the user till they reach the end.
progressBar.progress = fruitness.getProgress()
//Displaying the score at all times
scoreLabel.text = "SCORE: \(fruitness.score)"
}
}
You have a number of problems with your code.
First off, the prepare(for:sender:) method gets called on the source view controller that triggers the segue, not the destination view controller.
Second, your ResultsViewController has a viewWillAppear(_:) method nested inside its prepare(for:sender:) method. Don't do that. The viewWillAppear(_:) method needs to be a top-level method of your view controller or it won't get called.
Also, viewWillAppear(_:) methods should call super.viewWillAppear(animated).
Your ResultsViewController's viewWillAppear method should look like this:
func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
finalScoreLabel.text = finalScore
}
The prepare(for:sender:) method in your GameViewController should set finalScore in your ResultsViewController so that when its viewWillAppear is called, finalScore has a value.
Edit:
(It looks like you got that last part correct. Your GameViewController's prepare(for:sender) does appear to set finalScore. Note, however, that you are using scoreLabel to hold your finalScoreValue. You should not save state in view objects. You should have a var in GameViewController that holds your score. You could make GameViewController set your score var, and have a didSet() method on the score var that installs the updated score value into the scoreLabel.)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToResultsVC" {
let destinationVC = segue.destination as! ResultsViewController
destinationVC.finalScore = scoreLabel.text //Printing the final score at the end.
}
}
Maybe you wish to refactor your repetitive code to this one:
let optionButtonArray = [optionButton0,optionButton1 ...]
optionButtonArray.forEach { $0.backgroundColor = UIColor.clear }

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.

Accessing variables in other ViewControllers Swift 3

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)
}

Memory usage increases with every segue to modal vc

I have two view controllers, one is the timeline the second one is for the creation. In that second view controller I have a sub view. This sub view is an SKView. Now every time I segue to it, it increases the memory usage by 2mb (on a real device), but the memory usage stays the same when I unwind it.
So it is like this: I start with a usage of 12mb, then it gets 14-15mb. After the unwind it stays around 14-15mb. After the second segue to it, it becomes 17mb... and so on.
This is the code used in the timeline controller:
#IBAction func createButtonAct(sender: AnyObject) {
self.performSegueWithIdentifier("create", sender: self)
}
#IBAction func unwindFromCreation(segue: UIStoryboardSegue) {
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "create"{
let vc = segue.destinationViewController as! CreateViewController
if vc.currCountry == nil || vc.currCountry != self.currCountry{
vc.currCountry = self.currCountry
}
}
}
And this is the code in the create View Controller:
class CreateViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var bubbleView: SKView!
#IBOutlet var arrow: UIButton!
var ref: Firebase!
let categories = CatsAndColors.categories
#IBOutlet var doneButton: UIButton!
#IBOutlet var titleField: UITextField!
#IBOutlet var descriptionView: KMPlaceholderTextView!
var choosedCat: String!
var selectedCats: NSMutableArray!
var currCountry:String!
var tap: UITapGestureRecognizer!
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
UIApplication.sharedApplication().statusBarStyle = .Default
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.arrow.transform = CGAffineTransformMakeRotation(3.14159)
})
titleField.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
titleField.addTarget(self, action: "textFieldDidBegin:", forControlEvents: UIControlEvents.EditingDidBegin)
titleField.addTarget(self, action: "textFieldDidEnd:", forControlEvents: UIControlEvents.EditingDidEnd)
// the targets get removed in viewWillDisappear
selectedCats = NSMutableArray()
}
override func viewDidLoad() {
super.viewDidLoad()
ref = Firebase(url: "https://blabber2.firebaseio.com")
self.doneButton.enabled = false
doneButton.setBackgroundImage(UIImage(named: "Done button inactive"), forState: .Disabled)
doneButton.setTitleColor(UIColor(netHex: 0xF6F6F6), forState: .Disabled)
doneButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
self.setupBubbles()
self.descriptionView.delegate = self
}
func setupBubbles(){
let floatingCollectionScene = ChooseBubblesScene(size: bubbleView.bounds.size)
// floatingCollectionScene.scaleMode = .AspectFit
/*let statusBarHeight = CGRectGetHeight(UIApplication.sharedApplication().statusBarFrame)
let titleLabelHeight = CGRectGetHeight(self.tibleLabel.frame)*/
bubbleView.presentScene(floatingCollectionScene)
for (category, color) in categories {
let node = ChooseBubbleNode.instantiate()
node!.vc = self
node!.fillColor = SKColor(netHex: color)
node!.strokeColor = SKColor(netHex: color)
node!.labelNode.text = category
floatingCollectionScene.addChild(node!)
}
}
...
And the catsAndColors struct looks like this:
struct CatsAndColors{
static var categories = ["Crime":0x5F5068, "Travel":0xFBCB43, "Religion":0xE55555, "Tech":0xAF3151, "Economy":0x955BA5, "Games":0xE76851, "Climate":0x6ED79A, "Books":0xE54242, "History":0x287572, "Clothes":0x515151, "Sports":0x4AB3A7, "Food":0xD87171, "Politics":0x5FA6D6, "Music":0xDD2E63, "Tv-shows":0x77A7FB]
}
Maybe you have created some sort of retain cycle between your view controllers.
If both view controllers hold a reference to each other, then try declaring one of the references as weak.
For more information on the topic read Resolving Strong Reference Cycles Between Class Instances.
I solved the problem, it was strong reference in the sknode file.
Thank you for your answers.

Error: Could not cast value of type 'FirstApp.ChoosePageViewController' to 'FirstApp.CreateAccountPageViewController'

I am using Xcode 6.3.2 creating a single view app.
I have it set up so that the first view controller is a home page (Figure 1.), and when it appears, it automatically goes to a login/register/guest page. (Figure 2.)
From there, if someone chooses register, it brings them to a quick screen (Figure 3.) which is sort of just a background view to check if the registration works. From that screen, it automatically brings up the registration page. (Figure 4.)
Then, if registration is completed or successful, the registration page is dismissed back to that checking screen which is then dismissed to go back to the login/register/guest page.
Can't add many links so I uploaded a zip folder of my project plus the 4 images.
My Project:
http://www.mediafire.com/download/dnv1vqlx3j741zv/FirstApp.zip
Everything works up to the point where registration is cancelled. If registration is cancelled it will go back to the checking screen, then is just stuck there. I looked around and just couldn't find anything that worked for me to solve the issue and I unfortunately could not figure out the solution from the error message. Thank you to anyone who helps!
My Error Message:
Could not cast value of type 'FirstApp.ChoosePageViewController' (0x101edd680) to 'FirstApp.CreateAccountPageViewController' (0x101edd380).
(lldb)
The Login/Register/Guest Page View Controller:
import UIKit
class ChoosePageViewController: UIViewController {
//Sets Button Outlets to Edit Displays
#IBOutlet weak var viewLoginButton: UIButton!
#IBOutlet weak var viewRegisterButton: UIButton!
#IBOutlet weak var viewGuestButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
viewLoginButton.layer.cornerRadius = 5.0
viewRegisterButton.layer.cornerRadius = 5.0
viewGuestButton.layer.cornerRadius = 5.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The Registration Check Page View Controller:
import UIKit
class RegistrationCheckPageViewController: UIViewController, DetailsDelegate {
#IBOutlet weak var viewRegistrationStatusLabel: UILabel!
#IBOutlet weak var viewRegistrationForceQuitLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Allow CreateAccountPage to Edit RegistrationCheckPage Labels
func labelDelegateMethodWithString(RegistrationStatus: String, RegistrationForceQuit: String) {
viewRegistrationStatusLabel.text! = RegistrationStatus
viewRegistrationForceQuitLabel.text! = RegistrationForceQuit
}
//Prepare RegistrationCheckPage Controller for CreateAccountPage Controller Takeover
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
let controller = segue.destinationViewController as! CreateAccountPageViewController
controller.delegate = self
}
//Immediately Present Create Account Page, Dismiss When Account is Created
//Display Error and Return to Create Account Page if Account Creation Fails Unexpectedly
override func viewDidAppear(animated: Bool) {
if(viewRegistrationStatusLabel.text == "Complete!") {
self.performSegueWithIdentifier("toChoosePageFromRegistrationCheckPage", sender: self)
} else if(viewRegistrationForceQuitLabel.text == "Active") {
displayErrorAlert("Account not created.")
self.performSegueWithIdentifier("toChoosePageFromRegistrationCheckPage", sender: self)
} else if(viewRegistrationStatusLabel.text == "Checking..." && viewRegistrationForceQuitLabel.text == "Inactive"){
} else {
displayErrorAlert("An unknown error occurred.")
}
self.performSegueWithIdentifier("toCreateAccountPage", sender: self)
}
func displayErrorAlert(displayMessage: String) {
var myAlert = UIAlertController(title: "Error", message: displayMessage, preferredStyle: UIAlertControllerStyle.Alert)
let dismissAction = UIAlertAction(title: "Retry", style: UIAlertActionStyle.Default, handler: nil)
myAlert.addAction(dismissAction)
self.presentViewController(myAlert, animated: true, completion: nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
The Create Account Page View Controller:
import UIKit
//Allows RegistrationCheckPage and CreateAccountPage to Communicate
protocol DetailsDelegate {
func labelDelegateMethodWithString(RegistrationStatus: String, RegistrationForceQuit: String)
}
class CreateAccountPageViewController: UIViewController {
//Sets Button Outlets to Edit Displays
#IBOutlet weak var viewCreateButton: UIButton!
#IBOutlet weak var viewCancelButton: UIButton!
var registrationStatus = "Checking..."
var registrationForceQuit = "Inactive"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
viewCreateButton.layer.cornerRadius = 5.0
viewCancelButton.layer.cornerRadius = 5.0
}
//CreateAccountPage Allows or Disallows RegistrationCheckPage to Continue
var delegate: DetailsDelegate!
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
delegate.labelDelegateMethodWithString(registrationStatus, RegistrationForceQuit: registrationForceQuit)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var userUsernameTextField: UITextField!
#IBOutlet weak var userEmailTextField: UITextField!
#IBOutlet weak var userPasswordTextField: UITextField!
#IBOutlet weak var userRepeatPasswordTextField: UITextField!
#IBAction func didPressCreateAccountButton(sender: AnyObject) {
let userUsername = userUsernameTextField.text;
let userEmail = userEmailTextField.text;
let userPassword = userPasswordTextField.text;
let userPasswordRepeat = userRepeatPasswordTextField.text;
func displayAlert(displayMessage:String) {
var myAlert = UIAlertController(title: "Wait!", message:displayMessage, preferredStyle: UIAlertControllerStyle.Alert)
let dismissAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil)
myAlert.addAction(dismissAction)
self.presentViewController(myAlert, animated: true, completion: nil)
}
//Check for Empty Fields
if(userUsername.isEmpty || userEmail.isEmpty || userPassword.isEmpty || userPasswordRepeat.isEmpty) {
displayAlert("All fields are required!")
return;
}
//Make Sure Username Is Not In Use
/*if(username is in use) {
displayAlert("Username is already in use.")
return;
}*/
//Make Sure Passwords Match
if(userPassword != userPasswordRepeat) {
displayAlert("The passwords did not match!")
return;
}
//Store Data
//Successful Registration
registrationStatus = "Complete!"
registrationForceQuit = "Inactive"
delegate.labelDelegateMethodWithString(registrationStatus, RegistrationForceQuit: registrationForceQuit)
self.dismissViewControllerAnimated(true, completion: nil)
}
//Cancel the Registration Without Finishing
#IBAction func didPressCancelRegistrationButton(sender: AnyObject) {
registrationStatus = "Failed"
registrationForceQuit = "Active"
delegate.labelDelegateMethodWithString(registrationStatus, RegistrationForceQuit: registrationForceQuit)
self.dismissViewControllerAnimated(true, completion: nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
In this line:
let controller = segue.destinationViewController as! CreateAccountPageViewController
Your segue.destinationViewController is not what you expected it to be, it is actually a ChoosePageViewController.
You have two segues, "toChoosePageFromRegistrationCheckPage" and "toCreateAccountPage".
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
let controller = segue.destinationViewController as! CreateAccountPageViewController
controller.delegate = self
}
Right here, you have to check if segue.identifier is equal to "toChoosePageFromRegistrationCheckPage" or "toCreateAccountPage" and based on the identifier, cast the destination to the appropriate view controller.

Resources