Here is the line of code causing the error
class ViewController: UIViewController, UITextFieldDelegate {
I'm following a tutorial so I can't imagine why this went wrong.
It was working just fine until I added this function into my code:
//Check if user is already logged in when opening app if so display dashboard page
override func viewDidAppear(animated: Bool){
if PFUser.currentUser() != nil{
if self.theUser.user_db_obj.email == "mike#chicagodrumlessons.com"{
self.performSegueWithIdentifier("adminLogin", sender: self) //dislay admin page
}
else{
self.performSegueWithIdentifier("userLogin", sender: self) //display user page
}
}
}
Here is the only lines of code where the delegate is referenced I believe
override func viewDidLoad() {
super.viewDidLoad()
self.email_tf.delegate = self
self.pass_tf.delegate = self
}
Any idea what caused this error and how to fix it?
My guess is you declare non-optional properties and they aren't initialized when the object is. The compiler is telling you you need an init or two to provide the non-optional properties values before the object can be initialized (or make the properties optionals).
Related
I've tried, without success, respond to events such as windowWillClose() and windowShouldClose() inside NSWindowController (yes conforming to NSWindowDelegate).
Later, to my surprise, I was able to receive those events if I make my contentViewController (NSViewController) conform to NSWindowDelegate.
Unfortunately, later on, found out that view.window?.windowController is nil inside windowWillClose() or windowShouldClose(), code:
override func viewDidAppear() {
super.viewDidAppear()
self.view.window?.delegate = self
self.view.window?.windowController // not nil!
}
func windowWillClose(_ notification: Notification) {
self.view.window?.windowController // nil!!
}
func windowShouldClose(_ sender: NSWindow) -> Bool {
self.view.window?.windowController // nil!!
return true
}
After realizing that view.window?.windowController is not nil inside viewDidAppear() the next thing I thought was that Swift garbage collected the controller, so I changed viewDidAppear() in a way that creates another reference of windowController thus preventing garbage collection on said object, code:
var windowController: NSWindowController?
override func viewDidAppear() {
super.viewDidAppear()
self.view.window?.delegate = self
windowController = view.window?.windowController
}
func windowWillClose(_ notification: Notification) {
self.view.window?.windowController // NOT nil
}
func windowShouldClose(_ sender: NSWindow) -> Bool {
self.view.window?.windowController // NOT nil
return true
}
My hypothesis turned out to be correct (I think).
Is this the same issue that is preventing me from receiving those events inside NSWindowController?
Is there another way I can achieve the same thing without creating more object references?
In order to post code, I use the Answer option even though it is more of a comment.
I added in NSViewController:
override func viewDidAppear() {
super.viewDidAppear()
parentWindowController = self.view.window!.windowController
self.view.window!.delegate = self.view.window!.windowController as! S1W2WC. // The NSWC class, which conforms to NSWindowDelegate
print(#function, "windowController", self.view.window!, self.view.window!.windowController)
}
I get print log:
viewDidAppear() windowController Optional()
and notification is passed.
But if I change to
override func viewDidAppear() {
super.viewDidAppear()
// parentWindowController = self.view.window!.windowController
self.view.window!.delegate = self.view.window!.windowController as! S1W2WC
print(#function, "windowController", self.view.window!, self.view.window!.windowController)
}
by commenting out parentWindowController, notification don't go anymore to the WindowController…
Edited: I declared in ViewController:
var parentWindowController: NSWindowController? // Helps keep a reference to the controller
The proposed solutions are, in my opinion, hacks that can cause serious problems with memory management by creating circular references. You definitely can make instances of NSWindowController work as the window’s delegate. The proper way is to wire it up correctly in either code or in Interface Builder in Xcode. An example of how to do it properly is offered here.
If the delegate methods are not called is because the wiring up is not done correctly.
Another thing that must be done in Swift is when you add the name of the NSWindowController subclass in Interface Builder in Xcode is to check the checkbox of Inherits from Module. If you fail to do this, none of your subclass methods will be called.
I'm trying to save a bool value to UserDefaults from a UISwitch, and retrieve it in another view. However, I've tried following multiple tutorials and stack answers and none seem to work.
This is how I'm saving it:
class SettingsViewController: UITableViewController {
#IBOutlet weak var soundSwitchOutlet: UISwitch!
#IBAction func soundSwitch(_ sender: UISwitch) {
UserDefaults.standard.set(soundSwitchOutlet.isOn, forKey: "sound")
}
and this is how I'm trying to retrieve it in another view:
if let savedValue = UserDefaults.standard.bool(forKey: "sound") {
boolValue = savedValue
}
//this is inside viewDidLoad and "boolValue" was declared outside viewDidLoad//
For a reason this code is giving me errors and none of the things I've tried have worked. How can I save a bool to UserDefaults and retrieve it in another view?
Edit: I think I fixed the first part. However, the way I'm retrieving the boolean seems to be totally wrong. Also: No other stackExchange answer responds to what I'm asking, at least not in swift.
As Leo mentioned in the comments bool(forKey returns a non-optional Bool. If the key does not exist false is returned.
So it's simply
boolValue = UserDefaults.standard.bool(forKey: "sound")
Calling synchronize() as suggested in other answers is not needed. The framework updates the user defaults database periodically.
Do it like this.
In your first view controller.
create an IBoutlet connection to your UISwitch
And then the action for your UISwitch. so in the end, your first view controller should look like this.
import UIKit
class FirstViewController: UIViewController {
#IBOutlet weak var myswitch: UISwitch! // Outlet connection to your UISwitch (just control+ drag it to your controller)
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func myswitchAction(_ sender: Any) { // Action for your UISwitch
var myswitctBool : Bool = false // create a local variable that holds your bool value. assume that in the beginning your switch is offed and the boolean value is `false`
if myswitch.isOn == true { // when user turn it on then set the value to `true`
myswitctBool = true
}
else { // else set the value to false
myswitctBool = false
}
// finally set the value to user default like this
UserDefaults.standard.set(myswitctBool, forKey: "mySwitch")
//UserDefaults.standard.synchronize() - this is not necessary with iOS 8 and later.
}
}
End of the first view controller
Now in your second view controller
you can get the value of userdefault, which you set in first view controller. I put it in the viewdidload method to show you how it works.
import UIKit
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let myswitchBoolValuefromFirstVc : Bool = UserDefaults.standard.bool(forKey: "mySwitch")// this is how you retrieve the bool value
// to see the value, just print those with conditions. you can use those for your things.
if myswitchBoolValuefromFirstVc == true {
print("true")
}
else {
print("false")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Hope this will help to you. good luck
Use this line of code:
#IBAction func soundSwitch(_ sender: UISwitch) {
UserDefaults.standard.set(soundSwitchOutlet.isOn, forKey: "sound")
}
insteadof :
#IBAction func soundSwitch(_ sender: UISwitch) {
UserDefaults.standard.set(soundSwitchOutlet, forKey: "sound")
}
Try this:
#IBAction func soundSwitchs(_ sender: Any)
{
UserDefaults.standard.set(soundSwitchOutlet.isOn, forKey: "sound")
UserDefaults.standard.synchronize()
}
//this is inside viewDidLoad and "boolValue" was declared outside viewDidLoad//
boolValue = UserDefaults.standard.bool(forKey: "sound")
I'm trying to trigger a save of my CoreData on a window close as its only a single window application.
I've got the following code in my viewDidLoad and viewDidAppear
override func viewDidLoad() {
super.viewDidLoad()
if windowShouldClose(self) {
saveValues()
}
}
override func viewDidAppear() {
super.viewDidAppear()
self.view.window?.delegate = self
}
however im still getting the following error
Use of unresolved identifier 'windowShouldClose'
Any advice as to why i'm still getting this error after declaring the window delegate as self?
Set the delegate in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.view.window?.delegate = self
}
and implement the delegate method
func windowWillClose(notification: NSNotification) {
saveValues()
}
windowShouldClose is different. It asks for permission to close the window and expects a boolean return value.
Recently I have been making a app where you can create and quiz yourself on definitions or anything for that matter. I pass data to the next view after it the user hits the create button to make the title of the new notecard. The code I am using right now for that is:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let DestViewController: Card1 = segue.destinationViewController as! Card1
DestViewController.Content = Notetitle.text!
self.saved = self.Notetitle.text!
}
All of that works but, it will only work if I have a segue between viewcontrollers. I need to be able to pass that data with out a segue because I want the user to be able to create as many notecards as they want and the way I am trying to do that now is by using this code to make a copy of the UIView and then put in the new data (a master view). The new view can only be create using an IBAction. The prepare for segue I cannot use in the IBAction because it is it's own override function.
This is the code I am using to make a the new view:
let newCard =
self.storyboard!.instantiateViewControllerWithIdentifier("Main")
self.presentViewController(newCard, animated: true, completion:nil)
My hope is that I will be able to make a new view and then pass in the data pass in the data that the user just made to go on the notecard. (Hope this makes any sense at all)
MAIN TOPICS: -Create a new view and pass in new data Problem: Can pass data without a segue dont have one :/ -Be able to pass data between view controllers without a segue :)
I am new to all of this about 5 months. All of my code is in swift. Take it easy on me please. Feel free to ask me with any questions or comments. I have already posted a question on this but I didnt get an answer so have at it.
Thanks, Lucas Mazza
Don't use global variables unless you really need to. Making global static singleton's does not follow best practices. For more information read: What is so bad about singletons?
A better solution
You can use the protocol delegate pattern. I've actually written an article on this topic here:
https://www.codebeaulieu.com/36/Passing-data-with-the-protocol-delegate-pattern
You'll need a protocol that defines a function that will accept data. Then your other view controller will need to implement the delegate. If you need step-by-step details see the link provided above, alternatively you can simply download the project below and examine the code.
Download Working Example Project
Here's the code to make your protocol-delegate pattern work:
View Controller 1:
class ViewController: UIViewController, PresentedViewControllerDelegate {
#IBOutlet weak var textOutlet: UILabel!
#IBAction func doPresent(sender: AnyObject) {
let pvc = storyboard?.instantiateViewControllerWithIdentifier("PresentedViewController") as! PresentedViewController
pvc.data = "important data sent via delegate!"
pvc.delegate = self
self.presentViewController(pvc, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func acceptData(data: AnyObject!) {
self.textOutlet.text = "\(data!)"
}
}
View Controller 2:
import UIKit
// place the protocol in the view controller that is being presented
protocol PresentedViewControllerDelegate {
func acceptData(data: AnyObject!)
}
class PresentedViewController: UIViewController {
// create a variable that will recieve / send messages
// between the view controllers.
var delegate : PresentedViewControllerDelegate?
// another data outlet
var data : AnyObject?
#IBOutlet weak var textFieldOutlet: UITextField!
#IBAction func doDismiss(sender: AnyObject) {
if textFieldOutlet.text != "" {
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
print("\(data!)")
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if self.isBeingDismissed() {
self.delegate?.acceptData(textFieldOutlet.text)
}
}
}
On my app there are several views where you input certain values (settings) and so these settings get sent back to the master view using delegates. I already had this setup with 2 other views, and just copied and pasted the required code and changed the variables, however this brought up the error; "Type 'MasterViewController' does not conform to protocol 'CropPerformanceControllerDelegate'"The Code is below:
// MasterViewController
class MasterViewController: UIViewController, SettingsControllerDelegate, RainfallDataControllerDelegate, CropPerformanceControllerDelegate {
// Other variables/functions...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "MasterToSettings" {
let vc = segue.destinationViewController as! Settings
vc.delegate = self
}
if segue.identifier == "MasterToRainfallData" {
let vc = segue.destinationViewController as! RainfallData
vc.delegate = self
}
if segue.identifier == "MasterToCropPerformance" {
let vc = segue.destinationViewController as! CropPerformance
vc.delegate = self
}
}
func cropPerformanceSettingsSaved(controller: CropPerformance, irrigationResponseFactor: Double, wdImpactFactor: Double, potentialYield: Double) {
controller.navigationController?.popViewControllerAnimated(true)
irrigationResponseFactorM = irrigationResponseFactor
wdImpactFactorM = wdImpactFactor
potentialYieldM = potentialYield
}
}
// New View
// CropPerformanceView
protocol CropPerformanceControllerDelegate {
func cropPerformanceSettingsSaved(controller: CropPerformance, irrigationResponseFactor: Double, wdImpactFactor: Double, potentialYield: Double)
}
class CropPerformance: UIViewController {
var delegate: CropPerformanceControllerDelegate? = nil
// Other functions and Variables
#IBAction func updateCropSettings(sender: AnyObject) {
// Other stuff
if (delegate != nil) {
delegate!.cropPerformanceSettingsSaved(self, irrigationResponseFactor: irrigationResponseFactor!, wdImpactFactor: wdImpactFactor!, potentialYield: potentialYield!)
}
}
}
So this exact same code is used for the settings and rainfallData views and there are no issues, however now on the master view the 'CropPerformanceControllerDelegate' does not seem to be recognised and any uses of the class "CropPerformance" cause the error; "Use of undeclared type 'CropPerformance'". I hope this is enough information, all code to do with the delegate is posted, all other unnecessary variable declarations and functions I left out.
I had looked for other answers and they all said that you need to implement all required methods if you want to conform to the protocols. What exactly does that mean? All of my functions are inside my class and the code works perfectly when I remove the parts regarding the delegate.
Thanks in advance.
I was not able to solve the problem as there was no mistake in the code, I simply started from scratch, made a new document, copy and pasted the same code, changed the name to CropPerformance2 and it worked. (It works with any other name except for CropPerformance). This is very strange and must have something to do with that the initial class "CropPerformace" that I had deleted as not completely wiped from the systems memory, at least that is my assumption. In conclusion there is no answer, I simply recreated everything and it worked.