Failure when connecting iOS app to Database using Alamofire - ios

I am trying to complete my user registration from my app.
Using Alamofire I am trying to connect my iOS app to my database via my php files/server - yet I am receiving this error message:
FAILURE: responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))
this is my code -
import Alamofire
import UIKit
class SignUpComplete: UIViewController {
let URL_USER_REGISTER = "https:/mooverdata345.co.uk/registerIPHONE.php";
#IBOutlet var Email: UITextField!
#IBOutlet var Password: UITextField!
#IBOutlet var Username: UITextField!
#IBOutlet var Firstname: UITextField!
#IBOutlet var Surname: UITextField!
#IBOutlet var HouseNo: UITextField!
#IBOutlet var Postcode: UITextField!
#IBOutlet var labelMessage: UILabel!
#IBAction func submit(_ sender: UIButton) {
let parameters: Parameters=[
"Email":Email.text!,
"Password":Password.text!,
"Firstname":Firstname.text!,
"Surname":Surname.text!,
"HouseNo":HouseNo.text!,
"Postcode":Postcode.text!
]
Alamofire.request(URL_USER_REGISTER, method: .post, parameters: parameters).responseJSON
{
response in
//printing response
print(response)
//getting the json value from the server
if let result = response.result.value {
//converting it as NSDictionary
let jsonData = result as! NSDictionary
//displaying the message in label
self.labelMessage.text = jsonData.value(forKey: "message") as! String?
}
}
}
}
I think it may be something to do with JSON. The SQL queries are working so the backend stuff is okay. And my mate's Android app is connecting okay.

Related

Query Data from Firebase and write in UITextfield

I'm trying to pull data from my firebase project and write the field value in a UITextfield. I can't seem to figure out how to query the data needed for the UITextfields from the firebase field values correctly.
Is there anyway to do this? I have only seen videos of people adding firebase documents to a tableview, not any for direct pull of a firebase value to a UITextfield.
I've tried:
Switching the constants to instance the UITextfield Outlets and optionally unwrap as text fields let username = data[USERNAME] as? UITextField ?? "anonymous"
Creating variables of the UITextfields and equal the collections array data. So something kind like... let self.username = Userdata[0] but I keep getting "expected pattern error"
I know these may not be appropriate syntax but this is the first time I've ever coded and attempted to make an app, but I can't find any tutorial to follow for this scenario. So any information greatly appreciated, Thanks.
Heres what I've got so far...
import UIKit
import FirebaseDatabase
import Firebase
class ProfileVC: UIViewController {
#IBOutlet weak var userImage: UIImageView!
#IBOutlet weak var username: UITextField!
#IBOutlet weak var firstname: UITextField!
#IBOutlet weak var userEmail: UITextField!
#IBOutlet weak var lastname: UITextField!
#IBOutlet private weak var bgView: UIView!
//variables
private var Userdatas = [Userdata]()
private var usersCollectionRef: CollectionReference!
override func viewDidLoad() {
super.viewDidLoad()
usersCollectionRef = Firestore.firestore().collection(USERS_REF)
}
override func viewWillAppear(_ animated: Bool){
usersCollectionRef.getDocuments { (snapshot, error) in
if let err = error {
debugPrint("Error fetching docs: \(err) ")
} else {
guard let snap = snapshot else{return}
for document in snap.documents {
let data = document.data()
let username = data[USERNAME] as? String ?? "anonymous"
let firstname = data[FIRST_NAME] as? String ?? "Anonymous"
let lastname = data[LAST_NAME] as? String ?? "Anonymous"
let email = data[EMAIL] as? String ?? "Anonymous"
let documentID = document.documentID
let newuserData = Userdata(username: username, email: email, firstname: firstname, lastname: lastname, documentID: documentID)
}
}
}
}

Persisting Firebase Realtime Database creates null value in snapshot

So my application was working fine; I persisted the database locally using:
Database.database().isPersistenceEnabled = true
I didn't change anything but then all of a sudden it started returning a null snapshot. When I comment out that line, everything is working fine again and the label in the interface is displayed correctly, and this value is synced correctly across multiple devices. Here is a code snippet from my viewDidLoad:
import UIKit
import Firebase
import FirebaseDatabase
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var returnedName: UILabel!
#IBOutlet weak var scannedURLTextField: UITextField!
#IBOutlet weak var reentries: UILabel!
#IBOutlet weak var visitors: UILabel!
#IBOutlet weak var ticketType: UILabel!
#IBOutlet weak var statusImage: UIImageView!
#IBOutlet weak var entryOrReentrySwitch: UISwitch!
var qrDecodedURL : String!
var ticketNumber : String!
var eventID : String!
var numberOfAttendees: String!
var urlDictionary = [String : Any]()
var attendeeRef: DatabaseReference!
var ticketRef : DatabaseReference!
var entries : DatabaseReference!
var entriesRef : DatabaseReference!
var reentriesRef : DatabaseReference!
var entriesInt : Int!
var reentriesInt : Int!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
Database.database().isPersistenceEnabled = true
attendeeRef = Database.database().reference(withPath: "attendees")
ticketRef = Database.database().reference(withPath: "tickets")
entriesRef = Database.database().reference(withPath: "entries")
reentriesRef = Database.database().reference(withPath: "reentries")
self.scannedURLTextField .becomeFirstResponder()
scannedURLTextField.inputView=UIView()//create dummy view to supress keyboard
// Incresase size of switch
entryOrReentrySwitch.transform = CGAffineTransform(scaleX: 1.5, y: 1.5);
//monitor for changes in entries
entriesRef.child("entries").observe(.value, with: { (snapshot) in
print(snapshot);
self.visitors.text = "Visitors: \(snapshot.value as! String)"
let tempValue = snapshot.value as! String
self.entriesInt = Int(tempValue)
})
//Monitor for changes in reentries
reentriesRef.child("reentries").observe(.value, with: { (snapshot) in
// print(snapshot);
self.reentries.text = "Reentries: \(snapshot.value as! String)"
})
statusImage.image = UIImage.init(named: "scanQR.png")
}
The error generated is:
Could not cast value of type 'NSNull' (0x1fb2f3270) to 'NSString' (0x1fb2fcab8).
2019-10-12 18:05:54.061687-0700 VIM Tickets[621:97014] Could not cast value of type 'NSNull' (0x1fb2f3270) to 'NSString' (0x1fb2fcab8).
It fails on the self.visitors.text = "Visitors: \(snapshot.value as! String)" in the monitor for changes in entries section. Again, everything is working fine and there is data in the snapshot when I comment out the database persistence line. I even moved it to the AppDelegate, but it has the same result.
I am at a bit of a loss as to why this is happening when persistence was working before. Any suggestions would be greatly appreciated!
When you have disk persistence enabled, the Firebase client immediately fires with the current value that it knows for the node. It sounds like in your case it thinks that value is null, so it fires with that. If you have a connection to the server, it will moments later fire with the correct value that it got from the server.
The normal approach to deal with this situation is to first check whether the snapshot exists, before processing its contents.

How to update the labels in app as soon as JSON is fetched from server? If should be real time update

I am making a cricket app. I want to update the labels in iOS from URL every time server sends me the JDON file. How should I write the URL code?
import UIKit
import Foundation
struct jsonScore : Decodable {
let comment : String
let venuDetails : String
let valueToDisplay : String
let bowlingTeam : String
let battingTeam : String
let overs : Double
let targetScore : Int
let wickets : Int
let score : Int
let striker : striker
let nonStriker : nonStriker
let strikerBowler : strikerBowler
}
struct striker : Decodable{
let name: String
let runs: String
let balls: String
let fours: String
let sixes: String
}
struct nonStriker : Decodable{
let name: String
let runs: String
let balls: String
let fours: String
let sixes: String
}
struct strikerBowler : Decodable{
let name : String
let overs : String
let maidens : String
var runs : String
let wickets : String
}
class ViewController: UIViewController {
#IBOutlet weak var Comment: UITextView!
#IBOutlet weak var VenuDetails: UILabel!
#IBOutlet weak var ValueToDisplay: UILabel!
#IBOutlet weak var battingTeam: UILabel!
#IBOutlet weak var bowlingTeam: UILabel!
#IBOutlet weak var wickets: UILabel!
#IBOutlet weak var overs: UILabel!
#IBOutlet weak var score: UILabel!
#IBOutlet weak var striker: UILabel!
#IBOutlet weak var strikerRun: UILabel!
#IBOutlet weak var nonStriker: UILabel!
#IBOutlet weak var nonStrikerRun: UILabel!
#IBOutlet weak var strikerBowlerName: UILabel!
#IBOutlet weak var strikerBowlerOver: UILabel!
var timer = Timer()
// start the timer
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(getUpdatedData), userInfo: nil, repeats: true)
}
#objc func getUpdatedData() {
let jsonUrlString = "url from server"
guard let url = URL(string : jsonUrlString ) else
{ return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
//get your updated data here and update it into the UI.
do {
let jsonscore = try JSONDecoder().decode(jsonScore.self, from: data)
self.VenuDetails.text = jsonscore.venuDetails
self.Comment.text = jsonscore.comment
self.bowlingTeam.text = jsonscore.bowlingTeam
self.battingTeam.text = jsonscore.battingTeam
self.ValueToDisplay.text = jsonscore.valueToDisplay
self.wickets.text = String(jsonscore.wickets)
self.overs.text = String(jsonscore.overs)
self.score.text = String(jsonscore.score)
self.striker.text = jsonscore.striker.name + "*"
self.strikerRun.text = jsonscore.striker.runs
self.nonStriker.text = jsonscore.nonStriker.name
self.nonStrikerRun.text = jsonscore.nonStriker.runs
self.strikerBowlerName.text = jsonscore.strikerBowler.name
self.strikerBowlerOver.text = jsonscore.strikerBowler.overs
print(jsonscore)
}catch let jsonErr{
print("Error serializing json:", jsonErr)
}
}.resume()
}
}
How to I write the code so that as soon as JSON is fetched from server it gets updated in the app? I used timer also but the labels in app are not updating after first update. I want to update the app label as soon as server sends the JSON file and the update should be repeatedly.
Please help me writing the code.
As #Rmaddy said your timer use is quiet a bad idea. You can see why in the apple's Energy Efficiency Guide for iOS Apps
Timers prevent the CPU from going to or staying in the idle state,
which increases energy usage and consumes battery power.
That kind of over use will end up draining the device battery.
You should use something more efficient like web sockets(As #the4kman suggested). By using web sockets you will need to change a little bit your approach. You should consider to change your server to notify the app instead of the app being constantly downloading data from the server.
Here are some web sockets libraries that you can use:
Starscream
Socket.io
SwiftWebSocket

How Do I Post an Alamofire JSON Request on button press?

I am attempting to build a simple iOS app that features a login but first I want to make it so that pressing the "Continue" button on sign up posts data to the REST api. I can't successfully bind it to a button press for some reason. The code below doesn't know what inputboxes is. I ctr+dragged the button then added it in.
import Alamofire
import SwiftyJSON
import UIKit
class SignUpViewController: UIViewController {
var onButtonTapped : (() -> Void)? = nil
#IBOutlet weak var usernametextfield: UITextField!
#IBOutlet weak var passwordtextfield: UITextField!
#IBOutlet weak var emailtextfield: UITextField!
#IBOutlet weak var loginMessage: UILabel!
#IBAction func continueButtonPressed(sender: AnyObject) {
// POST requests dont need a response!
Alamofire.request(.POST, endpoint, parameters: inputboxes)
}
lazy var json : JSON = JSON.null
let endpoint = "anyapi.com/api/users"
override func viewDidLoad() {
digestUser()
}
func digestUser() {
let passwordInput = self.passwordtextfield.text
let usernameInput = self.usernametextfield.text
let emailInput = self.emailtextfield.text
let inputboxes: [String:AnyObject] = [
"hashword": passwordInput!,
"username": usernameInput!,
"email": emailInput!
]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Edit: Alamofire wasn't working properly because I forgot to include: "https://" before the URL
Declare inputboxes as instance variable below your outlets: var inputboxes: [String:AnyObject] = [:] and it should work.
Alamofire.request(.POST, BASE_URL , parameters: parameters as? [String : AnyObject])
.responseJSON { response in
if let JSON = response.result.value {
print("Success with JSON: \(JSON)")
}
}
Try to declare inputboxes outside function so it is accessible in the whole class.

Setting text of label in cell after request in Swift

I'm working on an app in Swift that makes a request to a server pulls back JSON and parses it into a schedule. I have table view controller with 7 cells and a label in each. I am aiming to change the text of each label after the request.
#IBOutlet weak var firstPeriod: UILabel!
#IBOutlet weak var secondPeriod: UILabel!
#IBOutlet weak var thirdPeriod: UILabel!
#IBOutlet weak var fourthPeriod: UILabel!
#IBOutlet weak var fifthPeriod: UILabel!
#IBOutlet weak var sixthPeriod: UILabel!
#IBOutlet weak var seventhPeriod: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let dayUrl = NSURL(string: "http://localhost:3000/day")
func setSchedLayout() {
var firstPeriodClass = String(defaults.dictionaryForKey("todaySchedule")!["first"]!["name"]!)
self.firstPeriod.text = firstPeriodClass
print(firstPeriodClass)
}
let task = NSURLSession.sharedSession().dataTaskWithURL(dayUrl!) {(data, response, error) in
day = NSString(data: data!, encoding: NSUTF8StringEncoding)!.stringByReplacingOccurrencesOfString("\"", withString: "").stringByReplacingOccurrencesOfString(" ", withString: "").stringByReplacingOccurrencesOfString("D", withString: "d")
var todaySchedule = defaults.dictionaryForKey("FullWeekSchedule")![day]
defaults.setObject(todaySchedule, forKey: "todaySchedule")
setSchedLayout()
}
task.resume()
}
This all happens inside my viewDidLoad()
I already have some data in my UserDefaults.
When my setSchedLayout() function calls at the end of my request, it doesn't change the text value for about 2 minutes. Then it gives me an error that says I'm trying to
modify the autolayout engine from a background thread
And when it does change the text it gives it an optional string. What's going on?

Resources