How can I go about controlling 1 view controller from another? - ios

So I have the following layout for my iOS app.
What I'm intending to do is put a table view in the purpleVC to control the Green viewcontroller...the top peachVC will have text in it which will need to change. I'm just not sure how to control one view controller from another. This includes having the purple slide in and out when a button on the GreenVC is clicked. I know there are classes out there to do this however I want to learn as well.
TESTING DELEGATES:
MAINVIEW CONTROLER
import UIKit
protocol Purpleprotocol {
func buttonpressed()
}
protocol Greenprotocol {
}
extension UIViewController {
func alert(message: String, title: String = "") {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion: nil)
}
}
class MainViewController: UIViewController,Purpleprotocol,Greenprotocol {
weak var infoNav : UINavigationController?
weak var greenVC: GreenVC?
weak var purpleVC: PurpleVC?
weak var peachVC: PeachVC?
func buttonpressed() {
alert(message: "This is message")
print("buttonpressed")
let date = Date()
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
greenVC?.greenlabel.text = String(hour) + ":" + String(minutes)
}
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.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "contentSegue" {
let infoNav = segue.destination as! UINavigationController
}
}
}
PURPLEVIEW CONTROLER
class PurpleVC: UIViewController {
var delegate: Purpleprotocol?
#IBAction func butclick(_ sender: UIButton) {
alert(message: "infunction")
delegate?.buttonpressed()
}
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.
}
Thanks
R

It does depend on the case but to see a few examples:
A) You can connect it through the delegates. Your main view controller has 3 child view controllers to which it should report changes. It should also assign itself as a delegate to all 3 child controllers where it will get all notifications for events. This would look like
func purpleViewController(sender: PVC, selectedItem: Item) {
self.greenViewController.showItem(item: selectedItem)
self.peachVC.showItem(item: selectedItem)
}
func purpleViewController(sender: PVC, shouldSetMenuClosed closed: Bool) {
self.menuConstraint.constant = closed ? targetWidth : 0.0
}
B) You may have a data model which controls the whole screen and has a delegate for each of the children. The model will report any changes to its delegates so they may react accordingly. Main view controller would create an instance of this model when it loads and pass it to all of the children view controllers. The children would then directly manipulate the model:
In green controller:
func onTap() {
mode.menuShown = !mode.menuShown
}
In model:
var menuShown: Bool = true {
didSet {
self.menuDelegate.model(self, changedMenuShownStateTo: menuShown)
}
}
In main view controller:
func model(_ sender: Model, changedMenuShownStateTo shown:Bool) {
self.menuConstraint.constant = shown ? 0.0 : targetWidth
}
C) You can use notifications where any of the controllers may post to notification center a custom notification and other controllers may observe the notifications and act accordingly.
There are many other ways in doing so but these probably most popular. See if any of them fits you...

Delegation.
Your MainViewController will become a delegate to each of the embedded VC's that want to pass back information. From your description you'll need two delegate relationships:
protocol PurpleProtocol {
func selected(row: Int, text: String)
}
protocol GreenProtocol {
func slideButtonPressed()
}
Have MainViewController implement these protocols. Give identifiers to the embed segues. You can find them in the Document Outline view. In prepareForSegue, retain pointers to the embedded VC's and pass your self as the delegate:
class MainViewController: UIViewController, PurpleProtocol, GreenProtocol {
weak var greenVC: GreenViewController?
weak var purpleVC: PurpleViewController?
weak var peachVC: PeachViewController?
func selectedRow(row: Int, text: String) {
// do something useful
}
func slideButtonPressed() {
// slide purple view in or out depending on current state
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EmbedPurple" {
let dvc = segue.destination as! PurpleViewController
purpleVC = dvc
dvc.delegate = self
}
else if segue.identifier = "EmbedGreen" {
let nav = segue.destination as! UINavigationController
let dvc = nav.topViewController as! GreenViewController
greenVC = dvc
dvc.delegate = self
} else if segue.identifier = "EmbedPeach" {
peachVC = segue.destination as! PeachViewController
}
}
}
In your embedded VC's, add a delegate pointer and call the delegate with the protocol method when it is time:
class GreenViewController: UIViewController {
weak var delegate: GreenProtocol?
#IBAction slideButtonPressed(sender: UIButton) {
delegate?.slideButtonPressed()
}
}
class PurpleViewController: UITableViewController {
weak var delegate: PurpleProtocol?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.selected(row: indexPath.row, text: modelArray[indexPath.row])
}
}

Related

Delegate function not called

I have two view controllers (ViewController and ActionViewController) and one manager (Brain), the second view controller is shown when a user tapped on a button by a show segue created in storyboard and to get back to the first I use a self.dismiss in the second view controller.
The user enter a number on ActionViewController that need to be retrieved in ViewController. So I created Brain to use the delegate pattern.
The problem is that the delegate function inside ViewController is never run, I read other SO answers but nothing work. I used print statement to know where the code is not running anymore and the only block not running is the didUpdatePrice inside ViewController
Here is the code
ViewController
class ViewController: UIViewController, BrainDelegate {
var brain = Brain()
#IBOutlet var scoreLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
brain.delegate = self
scoreLabel.layer.cornerRadius = 25
scoreLabel.layer.masksToBounds = true
}
func didUpdateScore(newScore: String) {
print("the new label is \(newScore)")
scoreLabel.text = newScore
}
}
ActionViewController
class ActionViewController: UIViewController {
var brain = Brain()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func addButtonTapped(_ sender: Any) {
brain.newAction(actualScore: 0, newActionValue: 5, isPositive: true)
self.dismiss(animated: true)
}
}
Brain
protocol BrainDelegate {
func didUpdateScore(newScore: String)
}
struct Brain {
var delegate: BrainDelegate?
func newAction(actualScore: Int, newActionValue: Int, isPositive: Bool) {
let newScore: Int
if isPositive {
newScore = actualScore + newActionValue
} else {
newScore = actualScore - newActionValue
}
print("the new score is \(newScore)")
delegate?.didUpdateScore(newScore: String(newScore))
}
}
You dont need an additional Brain class/struct at all, You can achieve it with simple protocol and default extension of protocol.
Step 1: Select your show segue and provide an identifier to that in storyboard as shown below
Step 2: In your ViewController add prepare(for segue method
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "testIdentifier" {
guard let destinationViewController = segue.destination as? ActionViewController else { return }
destinationViewController.delegate = self
}
}
Step 3: In your ActionViewController declare a weak property named delegate
class ActionViewController: UIViewController {
weak var delegate: BrainDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func addButtonTapped(_ sender: Any) {
delegate?.newAction(actualScore: 0, newActionValue: 5, isPositive: true)
self.dismiss(animated: true)
}
}
Step 4: Add class clause to your BrainDelegate (Class bound protocol) so that you can hold a weak reference to delegate
protocol BrainDelegate: class {
func didUpdateScore(newScore: String)
func newAction(actualScore: Int, newActionValue: Int, isPositive: Bool)
}
Step 5:
Add a default extension to BrainDelegate and provide default implementation of newAction(actualScore:
extension BrainDelegate {
func newAction(actualScore: Int, newActionValue: Int, isPositive: Bool) {
let newScore: Int
if isPositive {
newScore = actualScore + newActionValue
} else {
newScore = actualScore - newActionValue
}
print("the new score is \(newScore)")
self.didUpdateScore(newScore: String(newScore))
}
}
Step 6: In your ActionViewController simply trigger delegate methods as
#IBAction func addButtonTapped(_ sender: Any) {
delegate?.newAction(actualScore: 0, newActionValue: 5, isPositive: true)
self.dismiss(animated: true)
}
This should do the job
First, on Brain you should use class, not struct. That is because when you use struct, passing the variable to another will make a copy, it will not use the same reference. And class will only copy the reference.
That means that your Brain struct will lose the delegate assigned on .delegate = self
second, you need to use the same instance on the second viewController and the first. like this:
on the first viewController
var brain = Brain()
// this one is the one that you will put your "brain.delegate = self"
on the second viewController, you will need to inject this variable from the first viewController into the second. That is to keep the same instance on both. And this will make the delegate callable.
to do this with storyboard you will do on the first ViewController:
// this function should be called when the next viewController should open.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.destination) {
case let vc as MyViewController:
vc.brain = self.brain
default:
break
}
}
super.prepare(for: segue, sender: sender)
}
inside the second viewController, use:
var brain: Brain?

Receive changing data into another controller Swift

I have a ViewController with a variable which value is changing every second ( from a sensor ).
I made another ViewController let's call it SensorViewController with a Label on the screen in which I want to display the value from the main ViewController.
If I use override func prepare(for segue: UIStoryboardSegue, sender: Any?) the value is send but only one time ( it doesn't refresh/update every second ).
What can I do to change the value from SensorViewController every time the value from ViewController is changing?
Example:
// ViewController example code:
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
distanta1 = String(byteArray[0]) // variable which is changing every second
#IBAction func distantaSenzori(_ sender: UIButton) { //button which send me to SensorViewController
self.performSegue(withIdentifier: "goToSenzori", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // this one is sending value only when I press the button from above ( I have to exit from SensorViewController and enter again to see updated value )
if segue.identifier == "goToSenzori"{
let destinatieVC = segue.destination as! SensorViewViewController
destinatieVC.distance1 = distanta1 } }
}
// SensorViewController code:
class SensorViewViewController: UIViewController {
#IBOutlet weak var distanta1: UILabel!
var distance1: String?
override func viewDidLoad() {
super.viewDidLoad()
distanta1.text = distance2 }
}
Thank you very much, guys! You are awesome!
For Frankenstein:
In class SensorViewViewController my code looks like that:
var distance1: String?
override func viewDidLoad() {
super.viewDidLoad()
distanta1.text = distance1
print("Distance 1 is \(distance1)")
// Do any additional setup after loading the view.
}
It's called only once and the value is nil. What should I modify at the code here so the value to be refreshed?
I think a cleaner solution is to create a shared manager for handling the sensor. After that, you can notify your objects about the changing value. Of course in your case your "sensor" is something bluetooth but what I wrote is only a template basically, you can fill in your necessary methods and objects, delegates, so on.
class SensorManager {
static let shared: SensorManager = SensorManager()
private var sensor: Sensor
private init() {
sensor = Sensor()
}
//MARK: - Public methods
func startTheSensor() {
//This is what you call to start your sensor
}
func getSensorData() -> YourData {
//This is from where your objects can read the sensor data
}
//MARK: - Private methods -
private func didSensorUpdatedValue() {
//This is called whenever your sensor updates
.
.
.
let newSensorValue = "yourValue"
NotificationCenter.default.post(name: .init("SensorDataChanged"), object: nil)
}
}
In your viewcontroller:
deinit() {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
weak var this = self
NotificationCenter.default.addObserver(this, selector: #selector(didSensorValueChanged), name: .init("SensorDataChanged"), object: nil)
}
#objc func didSensorValueChanged() {
SensorManager.shared.getSensorData()
}
You need to add an observer and keep reference to the destination view controller to keep passing in the new value that has been changed to the destination view controller. Here's how:
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var distanta1 = String(byteArray[0]) {
didSet {
destinatieVC?.distance1 = distanta1
}
}
//...
var destinatieVC: SensorViewViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToSenzori" {
destinatieVC = segue.destination as? SensorViewViewController
}
}
}
In SensorViewViewController:
var distance1: String? {
didSet {
print(distance1 ?? "")
}
}
Better approach: Set the destinatieVC?.distanta1.text = distanta1 directly if you're not doing anything else in the didSet block avoid the distance1 property entirely.

Swift Delegate is never called

I know the question is already here in the forum but I don't know why my delegate doesn't work. I work with them for the first time, by the way.
Here is the code
ViewController:
class ViewController: UIViewController, ContainerViewControllerDelegate{
override func viewDidLoad() {
super.viewDidLoad()
let controller = ContainerViewController()
controller.containerDelegate = self
}
func didScrollChangeAppearanceBarButtonItem(change: Bool) {
if(change == true){
print("true")
}else{
print("false")
}
}
}
ContainerView:
protocol ContainerViewControllerDelegate {
func didScrollChangeAppearanceBarButtonItem(change: Bool)
}
class ContainerViewController: UIViewController, UIScrollViewDelegate{
var containerDelegate: ContainerViewControllerDelegate?
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
if(velocity.y>0) {
containerDelegate?.didScrollChangeAppearanceBarButtonItem(change: false)
print("1")
} else {
containerDelegate?.didScrollChangeAppearanceBarButtonItem(change: true)
print("2")
}
}
}
What I am trying to do: When I scroll I want to send a bool to my ViewController. When the bool == true I want to something and when the bool == false I want to do something else.
I hope somebody can help me :)
instead of this:
let controller = ContainerViewController()
controller.containerDelegate = self
create the variable outside viewDidLoad():
var controller:ContainerViewController!
override func viewDidLoad() {
super.viewDidLoad()
controller = ContainerViewController()
controller.containerDelegate = self
}
The reason is that the controller being initialized inside the viewDidLoad gets deallocated once the viewDidLoad function reaches its end
Edit
I will elaborate, if you are trying to access your other view controller by segue, this is a wrong way. Instead do this:
self.performSegueWithIdentifier("your identifier", sender: self)
then add a function:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "Your identifier") {
guard let controller = segue.destination as? ContainerViewController else { return }
controller.delegate = self
}
}
You are allocating a ContainerViewController, which is deallocated about a microsecond later when the code leaves viewDidLoad, because there are no references to it.

How to detect focused UITextField in Container view from Parent View Controller

I have a container view with multiple text boxes on it. I also have a button in Parent View controller(custom keypad). What I'm trying to do is select text box first & when I tap on the button I wanted some value to be populated to that last selected/focused textbox.
How can I do that? any alternative ways are welcome too. (I am having multiple container-views in the original code and try to use one keypad for all the views)
class MainViewController: UIViewController {
var weightVC : WeightViewController!
var focusedElement : UITextField
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "weight") {
weightVC = segue.destination as? WeightViewController
}
}
#IBAction func button1Clicked(_ sender: Any) {
if weightVC != nil {
weightVC.sampleTextBox1.text = "1"
//I want this sampleTextBox1 to be dynamic like weightVC.focusedInput = "1"
}
}
}
extension MainViewController:ChildToParentProtocol {
func setFocusedElement(with value: UITextField){
focusedElement = value
}
}
Container View Controller
protocol ChildToParentProtocol: class {
func setFocusedElement(with value:UITextField)
}
class WeightViewController: UIViewController {
weak var delegate: ChildToParentProtocol? = nil
#IBOutlet weak var sampleTextBox1: UITextField!
#IBOutlet weak var sampleTextBox2: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
// sampleTextBox1 Editing Did Begin event
#IBAction func editBeginSampleText1(_ sender: Any) {
print("edit begin")
delegate?.setFocusedElement(with: sampleTextBox1)
}
}
In other words, I simply want to keep a reference to last focused UITextFild when a button is tapped. Hope my requirement is clear enough. Please guide me if there is a way to achieve this.
Thanks
If I understood your question correctly you can keep track on which UITextField is tapped by using it's tag. And you can use UITextFieldDelegate to get the selected UITextField tag.
Consider the below code for WeightViewController
protocol ChildToParentProtocol: class {
//Changed value to Int for passing the tag.
func setFocusedElement(with value: Int)
}
import UIKit
class WeightViewController: UIViewController {
#IBOutlet weak var tf1: UITextField!
#IBOutlet weak var tf2: UITextField!
var selectedTFTag = 0
weak var delegate: ChildToParentProtocol? = nil
override func viewDidLoad() {
super.viewDidLoad()
//Assign delegate and tags to your TF
tf1.delegate = self
tf2.delegate = self
tf1.tag = 1
tf2.tag = 2
}
}
extension WeightViewController: UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
//Get the selected TF tag
selectedTFTag = textField.tag
//Pass tag to parent view
delegate?.setFocusedElement(with: selectedTFTag)
}
}
Now in your parent view ViewController you need to make some modification. I have added comments where I made changes to achieve your requirement.
import UIKit
//You need to confirm your ChildToParentProtocol with your UIViewController
class ViewController: UIViewController, ChildToParentProtocol {
var selectedTFTag = 0
var weightVC : WeightViewController!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "weight" {
weightVC = segue.destination as? WeightViewController
//You need to pass delegate to containerview to make it working.
weightVC.delegate = self
}
}
#IBAction func btn1Tapped(_ sender: Any) {
//According to selected Tag perform your action
if selectedTFTag > 0 {
switch selectedTFTag {
case 1:
//set up first UITextField
weightVC.tf1.text = "First textfield was selected"
print("1")
case 2:
//set up second UITextField
weightVC.tf2.text = "Second textfield was selected"
default:
break
}
}
}
#IBAction func btn2Tapped(_ sender: Any) {
//According to selected Tag perform your action
if selectedTFTag > 0 {
switch selectedTFTag {
case 1:
//set up first UITextField
weightVC.tf1.text = "First textfield was selected"
print("1")
case 2:
//set up second UITextField
weightVC.tf2.text = "Second textfield was selected"
default:
break
}
}
}
func setFocusedElement(with value: Int) {
//Get selected TF tag with delegate
selectedTFTag = value
}
}
You can check THIS demo project for more info.

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