I am building an iOS app as a new interface to our club website.
Since I'm fairly new to this I watched several videos and looked on various websites for help. However, populating username, and password still does not happen:
Clicking the Sign In button works.
This is the login website: https://leamingtonst.aspsystems.co.uk/bookitasp/bookitasp.dll/cookielog
This is my code so far:
import UIKit
import WebKit
class ViewController: UIViewController {
#IBOutlet weak var usernameTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
let webView = WKWebView()
var counter = 0
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://leamingtons.aspsystems.co.uk/bookitasp/bookitasp.dll/cookielog")!
let request = URLRequest(url: url)
webView.frame = CGRect(x: 0, y: 350, width: 300, height: 400)
webView.load(request)
view.addSubview(webView)
}
#IBAction func submitTapped(_ sender: UIButton) {
print("Value: \(usernameTextField.text!)")
print("Value: \(passwordTextField.text!)")
switch counter {
case 0:
// Populate username and password
webView.evaluateJavaScript("document.getElementsByClass('username').value = '\(usernameTextField.text!)';", completionHandler: { (res, error) -> Void in
if res != nil {
print(res!)
} })
webView.evaluateJavaScript("document.getElementsByClass('password').value = '\(passwordTextField.text!)';", completionHandler: { (res, error) -> Void in
if res != nil {
print(res!)
} })
webView.evaluateJavaScript("document.getElementById('pabutton').click();", completionHandler: nil)
case 1: break
case 2: break
case 3: break
case 4: break
case 5: break
default: break
}
counter += 1
}
}
I am grateful for any suggestions or ideas.
Related
i hope im not breaking any rules, I've got a problem when im trying to pass data from struct to A and from A to B, now the problem happens when im trying to pass the data from B to C. it all works fine when i use delegates from A to B.
before i post my code, i would mention few things:
I parse JSON and use delegate to pass the data from A(is my struct) to B
I would like to send data from VCAA to VCB.
Here's my code:
my struct:
import Foundation
import UIKit
// MARK: - Struct Protocol
protocol QuizBrainDelegate {
func didUpdateQuestionsArray(questionsArr: [Questions])
func didUpdateMessage(message: String)
}
// MARK: -
struct QuizBrain {
let urlString = "https://5fa952f1c9b4e90016e6a5be.mockapi.io/data"
var delegate: QuizBrainDelegate?
// MARK: API Request.
func performRequest() {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, respone, error) in
if error != nil {
print("There's an error \(error!)")
}
if let safeData = data {
self.parseJSON(with: safeData)
}
}
task.resume()
}
}
/// parsing JSON method to parse the JSON
/// - Parameter data: The data returned by the server
func parseJSON(with data: Data) {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(Root.self, from: data)
let questionsArr = decodedData.data.questions // an array of questions
let thankUMessage = decodedData.data.thank_you_message
//passing the quiz arr to our Quiz's VC:
self.delegate?.didUpdateQuestionsArray(questionsArr: questionsArr)
self.delegate?.didUpdateMessage(message: thankUMessage)
} catch {
print("There was a problem with parsing JSON \(error)")
}
}
// MARK: - Struct Methods:
/// This func gets the next question everytime we answer the question
/// - Parameters:
/// - questionNum: a counter of the current question number.
/// - numOfQuestions: a counter of total amount of questions.
/// - Returns: returns the new value of questionNum which is the counter of our question number.
func nextQuestion(questionNum: Int, numOfQuestions: Int) -> Int {
return questionNum + 1
}
/// Func sets the score of the player
/// - Parameter scoreNum: the total score number.
/// - Returns: returns the score with 5 points once the user answers right
func getNumOfCurretQuestion(scoreNum: Int) ->Int {
return scoreNum+1
}
}
my VCA:
import UIKit
import Foundation
protocol QuizVCDelegate {
func changeTitle(_ message: String?)
func updateUserOptions(_ optionsArr: [String])
}
class QuizViewController: UIViewController, QuizBrainDelegate {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var answerOption1: UIButton!
#IBOutlet weak var answerOption2: UIButton!
#IBOutlet weak var answerOption3: UIButton!
#IBOutlet weak var answerOption4: UIButton!
#IBOutlet weak var currQuestionLabel: UILabel!
var currentQuestionCounter = 0 // user's current number.
var numOfQuestion = 0 // counter of total questions.
var numOfOptions = 0 // counter of total options for each question
var quizBrain = QuizBrain() // an instance of struct QuizBrain for following MVC.
var messageToDisplay = ""
var quizArr = [Questions]() // array of Q and A
var storedAnswers = [String]() // an array of stored answers of the user
var delegate: QuizVCDelegate?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
quizBrain.performRequest() // Calling the URLRequest.
}
override func viewDidLoad() {
super.viewDidLoad()
quizBrain.delegate = self
}
#IBAction func answerButtonPressed(_ sender: UIButton) {
guard let userAnswer = sender.currentTitle else { return }
storedAnswers.append(userAnswer) // Storing the User's answers.
delegate?.updateUserOptions(storedAnswers)
delegate?.changeTitle(self.messageToDisplay)
sender.pulsate() // lets the user knows that he answered the question.
numOfQuestion = quizBrain.nextQuestion(questionNum: numOfQuestion, numOfQuestions: quizArr.count)
if numOfQuestion == quizArr.count { // checking if its equal to the total of questions in the array.
switchScreen()
}
//to make smooth transitaions im using a timer to update the UI:
if numOfQuestion < quizArr.count {
Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(updateUI), userInfo: nil, repeats: false)
}
}
// a func that updates all the UI
#objc func updateUI() {
questionLabel.fadeTransition(0.4) // fade animation to our questionLabel
self.questionLabel.text = quizArr[numOfQuestion].question
while numOfOptions < quizArr[numOfQuestion].options.count {
switch numOfOptions { // 2-4 Options.
case 0: // none
self.answerOption1.setTitle(self.quizArr[numOfQuestion].options[numOfOptions].value, for: .normal) // Updates option1
case 1: // Joe
self.answerOption2.setTitle(self.quizArr[numOfQuestion].options[numOfOptions].value, for: .normal) // Updates option2
case 2: // Trump
self.answerOption3.setTitle(self.quizArr[numOfQuestion].options[numOfOptions].value, for: .normal) // Updates option3
case 3:
print("There's a case 4")
default:
print("There's a problem with Options Switch Statement")
}
numOfOptions+=1
}
numOfOptions = 0
currQuestionLabel.fadeTransition(0.4) // fade animation to our currentQuestion
currQuestionLabel.text = "Total: \(currentQuestionCounter)/\(numOfQuestion)" // updates the score.
}
/// func to update the arr with the JSON decoded questions and answers.
/// - Parameter questionsArr: an array of question objects.
func didUpdateQuestionsArray(questionsArr: [Questions]) {
DispatchQueue.main.async {
self.quizArr = questionsArr
self.updateUI()
}
}
func didUpdateMessage(message: String) {
DispatchQueue.main.async {
self.messageToDisplay = message
print(self.messageToDisplay)
}
}
// a func which presents our Thank you VC.
func switchScreen() {
let mainStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
if let viewController = mainStoryboard.instantiateViewController(withIdentifier: "sbThanks") as? UIViewController {
viewController.modalPresentationStyle = .fullScreen
viewController.modalTransitionStyle = .crossDissolve
self.present(viewController, animated: true, completion: nil)
}
}
}
my VCB:
import Foundation
import UIKit
class ThanksViewController: UIViewController, QuizVCDelegate {
func updateUserOptions(_ optionsArr: [String]) {
DispatchQueue.main.async {
self.choosenAnswers = optionsArr
}
}
func changeTitle(_ message: String?) {
DispatchQueue.main.async {
self.titleLabel.text = message
}
}
var titleLabel = UILabel()
let bodyLabel = UILabel()
var choosenAnswers = [String]()
var quizVC = QuizViewController()
fileprivate func setupLabels() {
titleLabel.lineBreakMode = .byClipping // avoiding the 3 dots.
titleLabel.font = UIFont(name: "Futura", size: 20)
titleLabel.textColor = UIColor.black
titleLabel.textAlignment = .center
bodyLabel.text = "Your Answers:\n\(choosenAnswers)"
bodyLabel.numberOfLines = 0
bodyLabel.textColor = UIColor.black
bodyLabel.textAlignment = .center
}
fileprivate func setupStackView() {
let stackView = UIStackView(arrangedSubviews: [titleLabel, bodyLabel])
stackView.axis = .vertical
stackView.spacing = 8
view.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
stackView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: -100).isActive = true
}
override func viewDidLoad() {
super.viewDidLoad()
quizVC.delegate = self
setupLabels()
setupStackView()
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTapAnimations)))
}
#objc fileprivate func handleTapAnimations() {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut) {
self.titleLabel.transform = CGAffineTransform(translationX: -30, y: 0)
} completion: { (_) in
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.titleLabel.alpha = 0
self.titleLabel.transform = self.titleLabel.transform.translatedBy(x: 0, y: -100)
})
}
UIView.animate(withDuration: 0.5, delay: 0.5, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseOut) {
self.bodyLabel.transform = CGAffineTransform(translationX: -30, y: 0)
} completion: { (_) in
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.bodyLabel.alpha = 0
self.bodyLabel.transform = self.bodyLabel.transform.translatedBy(x: 0, y: -100)
})
}
}
}
I'm doing a dictionary application. Some terms have animation, some don't. If ;
let url = URL(string: "http://bsstech.site/-Sozlukler/Fizik/(f.animasyonAdi ?? "").html")!
webview.load(URLRequest(url: url))
or let url = URL(string: "http://bsstech.site/-Sozlukler/Fizik/logo.html")!
webview.load(URLRequest(url: url)) I want to run.
Did I write the code as below, but I did not get the result I wanted.
if let f = fizik {
if (f.animasyonAdi != nil) {
let url = URL(string: "http://bsstech.site/-Sozlukler/Fizik/\(f.animasyonAdi ?? "").html")!
webview.load(URLRequest(url: url))
}else {
let url = URL(string: "http://bsstech.site/-Sozlukler/Fizik/logo.html")!
webview.load(URLRequest(url: url))
}
navigationItem.title = f.baslik
aciklama.text = f.aciklama
}
}
I would be very glad if you help.
Step 1: Create a WebViewViewController
Step 2: Added WebKitView, top title label, a cross button and activity IndicatorView in the WebViewVC.xib file, then insert outlets in the WebViewVC.swift
Step 3: Implement logic in the WebViewVC.swift like the following:
import UIKit
import WebKit
class WebViewVC: UIViewController {
// MARK: - Outlets
#IBOutlet private weak var webView: WKWebView!
#IBOutlet private weak var activityIndicatorView: UIActivityIndicatorView!
#IBOutlet private weak var titleLabel: UILabel!
// MARK: - Variables
private let userAgentValue = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16"
var navTitle: String?
var urlString: String?
// MARK: - View Cycle
override func viewDidLoad() {
super.viewDidLoad()
initView()
setupWebView()
loadData()
}
// MARK: - Event
#IBAction private func actionTapToCloseButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}
// MARK: - Setting up View Controller
extension WebViewVC {
private func initView() {
titleLabel.text = navTitle
}
private func setupWebView() {
webView.navigationDelegate = self
webView.customUserAgent = userAgentValue
webView.isMultipleTouchEnabled = true
webView.isUserInteractionEnabled = true
}
private func loadData() {
if let `urlString` = urlString, !urlString.isEmpty, let query = urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed), let url = URL(string: query) {
let request = URLRequest(url: url)
webView.load(request)
}
}
}
// MARK: - WKNavigationDelegate
extension WebViewVC: WKNavigationDelegate {
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
activityIndicatorView.startAnimating()
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
activityIndicatorView.stopAnimating()
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
ShowPopUps.showDefaultAlert(title: "", message: "\(error.localizedDescription)", negativeActionText: "Ok")
activityIndicatorView.stopAnimating()
}
}
Step 4: Just Call
if let f = fizik {
var urlString: String? = nil
if (f.animasyonAdi != nil) {
urlString = http://bsstech.site/-Sozlukler/Fizik/\(f.animasyonAdi ?? "").html"
} else {
urlString = "http://bsstech.site/-Sozlukler/Fizik/logo.html"
}
let vc = WebViewVC()
vc.urlString = urlString
vc.navTitle = f.baslik
present(vc, animated: true, completion: nil)
}
I am using a tabbarcontroller to show 3 xib's. I would like to decode JSON data in the UITabBarController subclass, and then share the data with the view controllers (as I understand that is the preferred way to do this). I had already successfully accomplished this individually in each view controller, where the same JSON data was getting decoded separately 3 times, but I am now trying to make the process more efficient by only dealing with JSON once.
I am currently getting the following error
"Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffee7ab7d98)".
Below is the code I am currently using. I'm mostly only including the code for the first view controller, but it is the same for the others
Here is one of the view controllers. Any help would be appreciated, thank you!
class FirstCollectionViewController: UIViewController {
var tbvc = CustomTabBar()
var statisticsData = [Model]()
let firstCellIdentifier = "FirstCellIdentifier"
#IBOutlet weak var FirstCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
FirstCollectionView.delegate = self
FirstCollectionView.dataSource = self
FirstCollectionView.register(UINib(nibName: "FirstCollectionViewCell", bundle: nil),forCellWithReuseIdentifier: firstCellIdentifier)
}
}
Here is the subclasses UITabBarController
import UIKit
class CustomTabBar: UITabBarController {
let website = "https:......."
var statisticsData = [Model]()
override func viewDidLoad() {
super.viewDidLoad()
let firstTab = FirstCollectionViewController(nibName: "FirstCollectionViewController", bundle: nil)
let secondTab = SecondCollectionViewController(nibName: "SecondCollectionViewController", bundle: nil)
let thirdTab = ThirdCollectionViewController(nibName: "ThirdCollectionViewController", bundle: nil)
viewControllers = [firstTab, secondTab, thirdTab]
downloadJSON(website: website) {
firstTab.statisticsData = self.statisticsData
secondTab.statisticsData = self.statisticsData
thirdTab.statisticsData = self.statisticsData
firstTab.FirstCollectionView.reloadData()
secondTab.SecondCollectionView.reloadData()
thirdTab.ThirdCollectionView.reloadData()
}
}
func downloadJSON(website:String, completed:#escaping ()->()){
guard let qurl = URL(string: website) else { return }
URLSession.shared.dataTask(with: qurl) { (data, response, error) in
if error == nil {
do{
self.statisticsData = try JSONDecoder().decode([Model].self, from: data!)
DispatchQueue.main.async{
completed()
}
} catch {
print("JSON Error")
}}
}.resume()
}
}
Once the data is loaded, you should assign the data to the viewControllers that are added in the tabBarController's Child list as below,
downloadJSON(website: website) {
firstTab.statisticsData = self.statisticsData
secondTab.statisticsData = self.statisticsData
thirdTab.statisticsData = self.statisticsData
firstTab.FirstCollectionView.reloadData()
secondTab.SecondCollectionView.reloadData()
thirdTab.ThirdCollectionView.reloadData()
}
You can also remove the below lines from viewDidLoad of FirstCollectionViewController, SecondCollectionViewController and ThirdCollectionViewController
tbvc = tabBarController as! CustomTabBar
statisticsData = tbvc.statisticsData
I'm trying to implement a website's login database to a swift app but I can't seem to find how to do so, all of the things I find online don't really help. The website stores the login data in a mySQL database and I want to implement that into my app.
Here is my code:
import UIKit
class SignInViewController: UIViewController,UITextFieldDelegate {
#IBOutlet var UsernameTextField: UITextField!
#IBOutlet var PasswordTextField: UITextField!
#IBOutlet var LogInButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.isTranslucent = true
navigationController?.view.backgroundColor = UIColor.clear
// Remove Autocorrection Type
UsernameTextField.autocorrectionType = .no
PasswordTextField.autocorrectionType = .no
PasswordTextField.textContentType = UITextContentType("")
//Next button takes user to the next textfield
UsernameTextField.delegate = self
PasswordTextField.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func LogInButtonTapped(_ sender: Any) {
// `READ VALUES FROM TEXTFIELDS
let username = UsernameTextField.text
let password = PasswordTextField.text
// CHECK IF BOTH FIELDS ARE EMPTY
if (username?.isEmpty)! && (password?.isEmpty)! {
// DISPLAY ALERT MESSAGE HERE
print("User name \(String(describing: username)) or password \(String(describing: password)) is empty")
displayMessage(userMessage: "Both fields are required to fill in")
return
} else if (password?.isEmpty)! {
displayMessage(userMessage: "You did not enter a passwords")
return
} else if (username?.isEmpty)! {
displayMessage(userMessage: "You did not enter a username")
return
}
// CREATE ACTIVITY INDICATOR
let myActivityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.gray)
// POSITION ACTIVITY INDICATOR IN CENTER OF THE VIEW
myActivityIndicator.center = view.center
// START ACTIVITY INDICATOR
myActivityIndicator.startAnimating()
view.addSubview(myActivityIndicator)
}
func displayMessage(userMessage:String) -> Void {
DispatchQueue.main.async
{
let alertController = UIAlertController(title: "Alert", message: userMessage, preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default) { (action:UIAlertAction!) in
// Code in this block will trigger when OK button tapped.
DispatchQueue.main.async
{
self.dismiss(animated: true, completion: nil)
}
}
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion:nil)
}
}
//Remove keyboard on tap of screen and Go to next textfield everytime user taps on next
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == UsernameTextField{
PasswordTextField.becomeFirstResponder()
} else if textField == PasswordTextField {
self.view.endEditing(true)
}
return true
}
func removeActivityIndicator(activityIndicator: UIActivityIndicatorView)
{
DispatchQueue.main.async
{
activityIndicator.stopAnimating()
activityIndicator.removeFromSuperview()
}
}
}
How do I add the login information from the mysql database into the application? My objective here is to create an app for the website where I can use the same username and password as the one of the website.
You would have to create an API service for the app to send the username and password and your backend validate if the login is valid.
Look into REST/JSON services.
I am having trouble posting the outputs to a label. I have to covert it to a String? The error it seems to give me is "Cannot subscript a value of type JiNode? with an index of type 'Int'" Please help!
var meter = ""
#IBAction func calculate(sender: AnyObject) {
print("start scraping...")
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let url = NSURL(string: "http://uberestimate.com/costs.php")
let jiDoc = Ji(htmlURL: url!)
if jiDoc != nil {
print("html retrived.\n")
self.scrapeHTML(jiDoc!)
}
}
}
#IBOutlet weak var resultLabel: UILabel!
#IBOutlet weak var endingPoint: UITextField!
#IBOutlet weak var startingpoint: UITextField!
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.
}
private func scrapeHTML(jiDoc: Ji) {
println("parsing...\n")
let bodyNode = jiDoc.xPath("//body")!.first!
var contentDivNode = bodyNode.xPath("//span[#style='font-size:1.3em']").first
if contentDivNode == nil {
print("unexpected format!")
}else{
var cdnArray = contentDivNode[1]
var cdn = cdnArray[0]! as String
self.resultLabel.text = cdn
// println(contentDivNode)
}
return
}
}
You can do something like:
#IBAction func calculate(sender: AnyObject) {
print("start scraping...")
let url = NSURL(string: "http://uberestimate.com/costs.php")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { data, response, error in
if data == nil || error != nil { // in Swift 2, I'd use `guard`, but I tried to keep this backward compatible
print(error)
return
}
dispatch_async(dispatch_get_main_queue()) {
self.scrapeHTML(data!)
}
}
task.resume()
}
private func scrapeHTML(data: NSData) {
print("parsing...\n")
let jiDoc = Ji(data: data, isXML: false)
if let contentDivNode = jiDoc?.xPath("//span[#style='font-size:1.3em']")?.first {
self.resultLabel.text = contentDivNode.content
}
}
I'm using the Swift 2.1 (and I infer from the presence of println that you must be using an earlier version), but I think this is largely the same regardless of Swift version.
BTW, notice that I am dispatching the update of the label back to the main queue (as you called scrapeHTML from a global queue, but UI updates must happen on the main thread). I'm also using NSURLSession rather than dispatching a synchronous network request to a global queue.