This question already has answers here:
How to initialize properties that depend on each other
(4 answers)
Closed 5 years ago.
I'm getting this error: "Cannot use instance member 'server' within property initializer; property initializers run before 'self's available" in this line of my code
EDIT
import UIKit
import ChinoOSXLibrary
class LoginCL: UIViewController {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passField: UITextField!
var loggedUser: LoggedUser!
var customerId = "xxx"
var customerKey = "xxx"
var server = "https://api.test.chino.io/v1"
var chino = ChinoAPI.init(hostUrl: server, customerId: customerId, customerKey: customerKey)
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.
}
how i can solve it? The error is at this line
var chino = ChinoAPI.init(hostUrl: server, customerId: customerId, customerKey: customerKey)
You cannot use an instance of your view controller and properties until the initialization, so you just need to move your ChinoAPI initialization toviewDidLoad:
var chino: ChinoAPI!
override func viewDidLoad() {
super.viewDidLoad()
chino = ChinoAPI(hostUrl: server, customerId: customerId, customerKey: customerKey)
}
Another option is to move all hardcoded values from your view controller to ChinoAPI, but I'm not sure if it will fit your logic well.
Also, you can just move the values to init like:
ChinoAPI.init(hostUrl: "https://api.test.chino.io/v1", customerId: "xxx", customerKey: "xxx")
You need to use self after view controller init method. You can init your var chino in viewDidLoad or need to use hardcodet string if you need to init it before init view controller init method
Related
I am new to Swift and I have trouble using classes and structures.
I have a Structure called Workspace:
struct Workspace: Decodable {
var guid: String
var name: String
func getUserWorkspace(base: String, completed: #escaping () -> ()){
//some code
}
}
Here is my class User:
public class User {
var Wor = [Workspace]()
var WorData:Workspace? = nil
//+some other var & functions
}
So what I'm doing in my view controller is this:
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var listView: UITableView!
var co = User()
override func viewDidLoad() {
super.viewDidLoad()
co.WorData?.getUserWorkspace(base: co.Base) {
print("success")
self.listView.reloadData()
self.updateVertically()
}
listView.delegate = self
listView.dataSource = self
}
The problem is that the code never goes inside the function co.WorData?.getUserWorkspace(base: co.Base)
Before I put it in the structure it was directly in the class but since I changed it it doesn't work anymore so I think I might be calling it the wrong way ?
WorData is nil.
Conditional unwrapping (co.WorData?.getUserWorkspace(base: co.Base) will check WorData has a value before trying to call the method. If it was nil and Swift didn't do this, it would crash.
You either need to set it as new all the time
var worData = Workspace()
Set it after class init
var user = User()
user.worData = Workspace() // or pass a specific one in
or require your User object to be initialised with a Workspace
class User: NSObject {
var wor = [Workspace]()
var workspace: Workspace // use lower camel case for var names
required init(workspace: Workspace) {
self.workspace = workspace
}
}
Image of my view controller:
This is my code
class AddViewController: UIViewController {
#IBOutlet weak var questionField: UITextField!
#IBOutlet weak var correctAnswer: UITextField!
#IBOutlet weak var optionA: UITextField!
#IBOutlet weak var optionB: UITextField!
var ref: FIRDatabaseReference?
override func viewDidLoad() {
super.viewDidLoad()
self.hideKeyboard()
}
#IBAction func createQuestion(_ sender: Any) {
ref = FIRDatabase.database().reference(fromURL: "https://******.firebaseio.com/")
if questionField.text != "" && correctAnswer.text != "" && optionA.text != "" && optionB.text != ""
{
self.ref?.child("Questions").setValue(["Question": questionField.text, "CorrectAnswer": correctAnswer.text, "OptionA": optionA.text, "OptionB": optionB.text])
questionField.text = ""
correctAnswer.text = ""
optionA.text = ""
optionB.text = ""
}
else
{
print("Missing fields")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This is my goal in Firebase JSON:
My code is working but it replaces(ofc). Is my approach correct in saving questions so that in retrieving it will be easy? Could you give me idea how to save my questions?
First of all you must be using a pretty old version of Firebase if you are creating a database reference like that. For a while now (almost 6 months?) the correct way to create a reference to your database is
var ref: FIRDatabaseReference!
override func viewDidLoad(){
super.viewDidLoad()
ref = FIRDatabase.database().reference()
}
And in order for this to work you must download the GoogleService-info.plist file for your firebase project and add it to your Xcode project.
As far as your database structure goes...
What you have in your code is not going to produce what you are aiming for in the picture above. What you have in your code will produce this...
In order to produce data structured in the way you have pictured above you need to do this...
ref.child("Questions").child("Question1").setValue(["Question":questionField.text, "CorrectAnswer": correctAnswer.text, "optionA": optionA.text, "optionB": optionB.text])
then for question 2...
ref.child("Questions").child("Question2").setValue(["Question":questionField.text, "CorrectAnswer": correctAnswer.text, "optionA": optionA.text, "optionB": optionB.text])
and then your JSON will look like this ...
Note that I had to add the "Question" key as a child value under the "Question1" node in order to set the text for that question as its value.
Furthermore, if you are not able to increment Question1 followed by Question2... and so on, then you can use Firebase's method .childByAutoId like this for every question and Firebase will automatically generate a unique child id for that node...
ref.child("Questions").childByAutoId().setValue(["Question":questionField.text, "CorrectAnswer": correctAnswer.text, "optionA": optionA.text, "optionB": optionB.text])
the result will look similar to this...
Hope this helps, let me know if you have further questions
Since setValue() will override the whole content of Questions node.
U should create a child before upload the question to firebase.
ref.child("Questions").childByAutoId().setValue(...)
When dialing with CocoaTouch, it often happens that UIView(Controller) subclass properties can't be initialized in init method (ex. we need view already loaded), but logically they are non-optional and even non-var. In such cases the property must be optional to compile without errors, what looks pretty ugly - the code is fulfilled with !.
Is there any way to solve this problem? I would imagine some deferred initialization. Perfectly if such property can compile without initial value and crash at runtime if it's accessed prior to be initialized.
Some code sample to describe the issue:
class MyVC: UIViewController {
#IBOutlet var someLabel: UILabel!
let viewBasedParam: CustomClass // how to keep it non-optional if it can be initialized after view has been loaded?
override func viewDidLoad() {
super.viewDidLoad()
self.viewBasedParam = CustomClass(self.someLabel.text)
}
}
P.S. CustomClass can't have default initializer, because it requires data from view.
In your MyVC you can have a convenience init method where you can initialize the let variables. Try this and let me know if it works for you:
class MyVC: UIViewController {
let viewBasedParam: CustomClass
convenience init() {
self.init(nibName:nil, bundle:nil)
self.viewBasedParam = CustomClass(self.someLabel.text)//else just initialize with empty string here and then assign actual value in viewDidLoad
}
}
As far as I've discovered the workaround solution may be following:
class MyVC: UIViewController {
#IBOutlet var someLabel: UILabel!
private var _viewBasedParam: CustomClass? = nil
var viewBasedParam: CustomClass {
get { return self._viewBasedParam! } // always unwrap private optional
set { self._viewBasedParam = newValue }
}
override func viewDidLoad() {
super.viewDidLoad()
self.viewBasedParam = CustomClass(self.someLabel.text)
}
}
Overview
I need to save several TextFields into CoreData, but only the first one (Seen as pickerView below) saves and prints correctly. The others do not save correctly, for instance, when I try to save the integer ones, I get an error saying that they cannot take a String, which makes sense. I just cannot find a way to fix the integer-string issue. The other error occurs when I attempted to cast everything as a string ( mainly because I won't need to do any arithmetic on it, so it doesn't matter ), and it just gives me a breaking point in the saveButton function.
What I would like to know
What I ultimately need is the ability to save all of these TextFields into CoreData so that I can later retrieve them. I appreciate the help in advance. Thank you!
NOTE
I am including the entire ( or most of ) the ViewController.swift file so that you can see how I am declaring things and then how they are being called. The code in question is located in the saveButton action at the bottom of the code block.
CODE
#IBOutlet weak var locationOfMachine: UITextField!
#IBOutlet weak var engineHours: UITextField!
#IBOutlet weak var YOM: UITextField!
#IBOutlet weak var serialNo: UITextField!
#IBOutlet weak var modelName: UITextField!
#IBOutlet weak var pickerTextField: UITextField!
var pickOption = ["Wirtgen","Kleeman","Hamm","Vögele"]
override func viewDidLoad() {
super.viewDidLoad()
var pickerView = UIPickerView()
pickerView.delegate = self
pickerTextField.inputView = pickerView
// 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 numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
#IBAction func saveButton(sender: AnyObject)
{
var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext
var entity1 = NSEntityDescription.insertNewObjectForEntityForName("UsedInfo", inManagedObjectContext:context) as NSManagedObject
entity1.setValue(pickerTextField.text, forKey: "product")
entity1.setValue(modelName.text, forKey:"modelName")
entity1.setValue(serialNo.text, forKey:"serialNo")
entity1.setValue(Int(YOM.text!), forKey:"yom")
entity1.setValue(engineHours.text, forKey:"engineHours")
entity1.setValue(locationOfMachine.text, forKey:"location")
print(entity1.valueForKey("product"))
print(entity1.valueForKey("modelName"))
print(entity1.valueForKey("serialNo"))
print(entity1.valueForKey("yom"))
print(entity1.valueForKey("engineHours"))
do {
try context.save()
}
catch {
print("error")
}
}
EDIT
Upon trying to save everything as just a string, since i only need to retrieve it, I run into this issue:
entity1.setValue(pickerTextField.text, forKey: "product")
entity1.setValue(modelName.text, forKey:"modelName")
entity1.setValue(serialNo.text, forKey:"serialNo") <-Thread1:Breakpoint1.1
entity1.setValue(YOM.text, forKey:"yom")
entity1.setValue(engineHours.text, forKey:"engineHours")
entity1.setValue(locationOfMachine.text, forKey:"location")
print(entity1.valueForKey("product"))
print(entity1.valueForKey("modelName"))
print(entity1.valueForKey("serialNo"))
print(entity1.valueForKey("yom"))
print(entity1.valueForKey("engineHours"))
I also get "(lldb)" in the debugger window.
I'll just show you how to get int from string. Use it accordingly:
var aString = "0000" // var aString = textField.text!
var numFromString = Int(aString)
You can assign the text field to aString and convert it to Int like i showed you.
For things that don't need arithmetic, define them as strings in Core Data. For other numbers, it should work to do as you have with Int(YOM.text!).
However, I suggest that you create a managed object subclass for "UsedInfo" so that you can work directly with its properties instead of using setValue:forKey:. The benefit of a subclass is that it will show you data types explicitly.
Validate all textfields before trying to store,set the appropriate keyboard for each textfield and provide the valid character set for each textfield.
For Example:
YOM text field : Use Keyboard with only integers.
Valid character set are 0 to 9
And validation for min and max if applicable.
If any of the validation criteria fails ,throw an alert to input valid data.
I guess this solves your issue.
I am very new to swift, but i can work with javascript and php so thought this would make sense to me. I have read so many posts on this topic but non really explain mine. I have the following code which is pretty straight forward. I have several text fields with login information to pass on to php. But when i try to use the var from a function it is not possible. So i figured that out but when i try to redefine the vars outside of the function with different var i am still keep getting the error. This is the code so far
import UIKit
class RegisterPage: UIViewController, UITextFieldDelegate{
#IBOutlet weak var userEmailTextField: UITextField!
#IBOutlet weak var userPasswordTextField: UITextField!
#IBOutlet weak var userPasswordConfirmTextField: UITextField!
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.
}
#IBAction func registerTapped(sender: AnyObject) {
let userEmail = userEmailTextField.text
let userPassword = userPasswordTextField.text
let userConfirmPassword = userPasswordConfirmTextField.text
// check for empty fields
if(userEmail.isEmpty || userPassword.isEmpty || userConfirmPassword.isEmpty)
{
// Display alert message
displayMyAlertMessage("Alle velden gelieve invullen");
return;
}
//Check if passwords match
if(userPassword != userConfirmPassword){
// Display alert message
displayMyAlertMessage("Wachtwoorden komen niet overeen");
return;
}
}// end of registerTapped button
// send data to server side
static var urlConn: NSURL = NSURL(string: "http://xxxxxxxxx")!
var request: NSMutableURLRequest = NSMutableURLRequest(URL:urlConn);
var credLogin = "email=\(userEmail)&password=\(userPassword)"
the following line is giving the unresolved identifier error
var credLogin = "email=\(userEmail)&password=\(userPassword)"
i have tried so many different things, but i can't move the var in the function outside of it, and i have had also in other code blocks errors like this, i really would like to know how this works in swift.
Thanks
The variables userEmail and userPassword are declared within the scope of the registerTapped method. They are not visible outside this method.
Either put the line
var credLogin = "email=\(userEmail)&password=\(userPassword)"
in the method or declare the variables as instance variables right after IBOutlet declarations.
The code to send data to server side must be also executed within a method.