Swift call same api in different controller - json

so i dont know if the title is right but i want to call an api that inside controller a in controller b. its because i hit the same api and and i figure i just do this
class resetPinVc: UIViewController{
#IBOutlet weak var phoneNumberTextField: SkyFloatingLabelTextField!
#IBAction func doResetPIn(_ sender: UIButton) {
loadingProcess(loading: true) // crash here
phoneNumberTextField.resignFirstResponder()
resetPinviewModel.doResetPin(mobileNumber: phoneNumberTextField.text ?? "") { [weak self] (resetCode) in //crash here
if resetCode.code == 200 {
self?.performSegue(withIdentifier: "timerSegue", sender: self)
self?.loadingProcess(loading: false)
}
else if resetCode.code == 400 {
let message = resetCode.message
self?.showError(message: message)
self?.loadingProcess(loading: false)
}
else if resetCode.code == 403 {
let messages = resetCode.message
self?.showError(message: messages)
self?.loadingProcess(loading: false)
self?.phoneNumberTextField.lineColor = UIColor.init(named: COLOR_RED)!
}
else if resetCode.code == -99 {
let alert = UIAlertController(title: "time out", message: "\(resetCode.code)", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "ok", style: .default, handler: nil))
self?.present(alert, animated: true, completion: nil)
}
}
}
}
so i want to call that func that hit api in another controller....which is like this
class ResetTimerVc: UIViewController {
let resetPinVC = resetPinVc()
#IBAction func resend(_ sender: UIButton) {
let timeFormated = resetPinViewModel.timeFormatted(totalSeconds: totalTime)
timer?.invalidate()
totalTime = 60
timerLabel.text = timeFormated
timerIsOn = false
if timerIsOn == false {
resendButton.isEnabled = false
resendButton.setTitleColor(UIColor.red, for: .normal)
startTimer()
}
resetPinVC.doResetPIn(resendButton)
}
}
but turns out i have a crash (in the line i mention) because apparently i dont have the that loadingProcess func on my ResetTimerVc, and i dont have phoneNumberTextField on my ResetTimerVc as well.
any idea how do i get over this? sorry for the bad english
the reason i need to hit the same api its because i need to hit that api with the same data that i fill in ResetPinVc on ResetTimerVc
thanks.

Related

How to load new data in CollectionView when refresh?

I am making app with swift and getting data from my Wordpress Website and using Rest Api to display data in CollectionView, all works fine but the problem is when i add new posts in website it doesn’t automatically shows in app , and when i refresh data then also can’t see the newest post . this is my code on refresh
#objc
private func didPullToRefresh(_ sender: Any) {
sortBy = "&orderby=date"
page = 1
self.fetchPostData { (posts) in
self.newsData = posts }
SVProgressHUD.show()
self.collectionView.setContentOffset(CGPoint(x:0,y:0), animated: true)
refreshControl.endRefreshing()
}
and this is the code to fetch data
func fetchPostData(completionHandler: #escaping ([Post]) -> Void ) {
DispatchQueue.main.asyncAfter(deadline: .now()) {
SVProgressHUD.show()
}
let url = URL(string: "https://www.pbkalam.com/wp-json/wp/v2/posts/?page=\(page)\(sortBy)" )!
print(url)
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else {return}
do {
let postsData = try JSONDecoder().decode([Post].self, from: data)
completionHandler(postsData)
DispatchQueue.main.async {
self.collectionView.isUserInteractionEnabled = true
self.collectionView.reloadData()
SVProgressHUD.dismiss()
}
}
catch {
let error = error
print(String(describing: error))
SVProgressHUD.dismiss()
}
}
task.resume()
}
Here is my cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "postcell", for: indexPath) as! ViewCell
cell.setup(with: newsData[indexPath.row-(indexPath.row/4)])
when i use
sortBy = "&orderby=rand"
then it loads the random posts but not the newest.. please help
i have tried this code
#objc
private func didPullToRefresh(_ sender: Any) {
sortBy = "&orderby=date&order=desc"
page = 1
self.fetchPostData { (posts) in
self.newsData = posts }
self.collectionView.reloadData()
SVProgressHUD.show()
self.collectionView.setContentOffset(CGPoint(x:0,y:0), animated: true)
refreshControl.endRefreshing()
}

How to modify the video format after the download in swift

I have a problem in modifying the video format after downloading from videoplayback to mp4 and save to camera.
This is my download code, but I downloaded some video with a different format example : "videoplayback". I can't save to camera because I want to change format video to mp4.
func SessionDownload(URLSession : String) {
MBProgressHUD.hideAllHUDs(for: view, animated: true)
let hud = MBProgressHUD.showAdded(to: self.view, animated: true)
// Set the bar determinate mode to show task progress.
progress = 0.0
hud?.mode = MBProgressHUDMode.determinateHorizontalBar
hud?.isUserInteractionEnabled = true;
hud?.labelText = NSLocalizedString("Downloading...", comment: "HUD loading title")
DispatchQueue.global(qos: .default).async(execute: {() -> Void in
// Do something useful in the background and update the HUD periodically.
self.doSomeWorkWithProgress()
DispatchQueue.main.async(execute: {() -> Void in
//hud?.hide(true)
hud?.labelText = NSLocalizedString("Just Wait...", comment: "HUD loading title")
})
})
let videoPath = URLSession
print(videoPath)
let s = videoPath
let url = NSURL(string:s)!
let req = NSMutableURLRequest(url:url as URL)
let config = URLSessionConfiguration.default
let task = self.session.downloadTask(with: req as URLRequest)
self.task = task
task.resume()
}
//MARK:- share video
func doSomeWorkWithProgress() {
// This just increases the progress indicator in a loop.
while progress < 1.0 {
DispatchQueue.main.async(execute: {() -> Void in
print(self.progress)
MBProgressHUD(for: self.view).progress = self.progress
})
usleep(50000)
}
}
//MARK:- URL Session delegat
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
print("downloaded \(100*totalBytesWritten/totalBytesExpectedToWrite)")
taskTotalBytesWritten = Int(totalBytesWritten)
taskTotalBytesExpectedToWrite = Int(totalBytesExpectedToWrite)
percentageWritten = Float(taskTotalBytesWritten) / Float(taskTotalBytesExpectedToWrite)
print(percentageWritten)
let x = String(format:"%.2f", percentageWritten)
print(x)
self.progress = Float(x)!
print(progress)
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
// unused in this example
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
print("completed: error: \(error)")
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("Finished downloading!")
let fileManager = FileManager()
// this can be a class variable
let directoryURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
print(directoryURL)
let docDirectoryURL = NSURL(fileURLWithPath: "\(directoryURL)")
print(docDirectoryURL)
//Save To Photos
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL:directoryURL)
}) { saved, error in
if saved {
let alertController = UIAlertController(title: "Your video was successfully saved", message: nil, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
let destinationFilename = downloadTask.originalRequest?.url?.lastPathComponent
print(destinationFilename!)
// append that to your base directory
let destinationURL = docDirectoryURL.appendingPathComponent("\(destinationFilename!)")
print(destinationURL!)
/* check if the file exists, if so remove it. */
if let path = destinationURL?.path {
if fileManager.fileExists(atPath: path) {
do {
try fileManager.removeItem(at: destinationURL!)
} catch let error as NSError {
print(error.debugDescription)
}
}
}
do
{
try fileManager.copyItem(at: location, to: destinationURL!)
}
catch {
print("Error while copy file")
}
DispatchQueue.main.async(execute: {() -> Void in
MBProgressHUD.hide(for: self.view, animated: true)
})
// let videoLink = NSURL(fileURLWithPath: filePath)
let objectsToShare = [destinationURL!] //comment!, imageData!, myWebsite!]
let activityVC = UIActivityViewController(activityItems: objectsToShare , applicationActivities: nil)
activityVC.setValue("Video", forKey: "subject")
//New Excluded Activities Code
if #available(iOS 9.0, *) {
activityVC.excludedActivityTypes = [UIActivity.ActivityType.airDrop, UIActivity.ActivityType.addToReadingList, UIActivity.ActivityType.assignToContact, UIActivity.ActivityType.copyToPasteboard, UIActivity.ActivityType.mail, UIActivity.ActivityType.message, UIActivity.ActivityType.openInIBooks, UIActivity.ActivityType.postToTencentWeibo, UIActivity.ActivityType.postToVimeo, UIActivity.ActivityType.postToWeibo, UIActivity.ActivityType.print]
} else {
// Fallback on earlier versions
activityVC.excludedActivityTypes = [UIActivity.ActivityType.airDrop, UIActivity.ActivityType.addToReadingList, UIActivity.ActivityType.assignToContact, UIActivity.ActivityType.copyToPasteboard, UIActivity.ActivityType.mail, UIActivity.ActivityType.message, UIActivity.ActivityType.postToTencentWeibo, UIActivity.ActivityType.postToVimeo, UIActivity.ActivityType.postToWeibo, UIActivity.ActivityType.print ]
}
if let popoverController = activityVC.popoverPresentationController {
popoverController.sourceView = self.BtnDownloadVideo
popoverController.sourceRect = self.BtnDownloadVideo.bounds
}
self.present(activityVC, animated: true, completion: nil)
}
I'm assuming when you download a file from the internet, you are sure you are downloading a video in this circumstance? And what you are really wanting is just to change the format, i.e. PathExtension such as .mp4, .png, jpeg, etc.
Iff (if and only if) this is the case, then you can add a file extension on to the path component.
let destinationURL = docDirectoryURL.appendingPathComponent("\(destinationFilename!)").appendingPathExtension("mp4")
Now, when you check your saved files, it will include the ".mp4"
Again, I'm assuming you are 110% confident you are downloading a ".mp4" from the interwebs.

Add Login page from mysql database to swift

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.

Checking if Firebase snapshot is equal to nil in Swift

I am trying to query Firebase to check if any user that has waiting: "1" and then when the snapshot is returned I want to see whether it is equal to nil. I have attempted to do this but the method I have used does not work and I only have some sort of out put if the snapshot is not equal to nil. I have added the code I currently have and the JSON text from Firebase.
import UIKit
import Firebase
import Spring
class GamesViewController: UIViewController {
let ref = Firebase(url: "https://123test123.firebaseio.com")
var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()
#IBAction func StartGamePressed(sender: AnyObject) {
print("test1")
var peopleWaiting: [String] = []
let userRef = Firebase(url:"https://123test123.firebaseio.com/users")
userRef.queryOrderedByChild("waiting").queryEqualToValue("1")
.observeEventType(.ChildAdded, withBlock: { snapshot in
print(snapshot.key)
if snapshot.key == nil {
print("test2")
let userData = ["waiting": "1"]
let usersRef = self.ref.childByAppendingPath("users")
let hopperRef = usersRef.childByAppendingPath("\(self.ref.authData.uid)")
hopperRef.updateChildValues(userData, withCompletionBlock: {
(error:NSError?, ref:Firebase!) in
if (error != nil) {
print("Data could not be saved.")
self.displayAlert("Oops!", message: "We have been unable to get you into a game, check you have an internet conection. If this problem carries on contect support")
} else {
print("Data saved successfully!")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let Home : UIViewController = storyboard.instantiateViewControllerWithIdentifier("continueToGame")
self.presentViewController(Home, animated: true, completion: nil)
}
})
} else {
var randomUID: String
peopleWaiting.append(snapshot.key)
let randomIndex = Int(arc4random_uniform(UInt32(peopleWaiting.count)))
randomUID = peopleWaiting[randomIndex]
print(randomUID)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let Home : UIViewController = storyboard.instantiateViewControllerWithIdentifier("continueToGame")
self.presentViewController(Home, animated: true, completion: nil)
}
})
}
func displayAlert(title: String, message: String){
let formEmpty = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
formEmpty.addAction((UIAlertAction(title: "Ok", style: .Default, handler: { (action) -> Void in
})))
self.presentViewController(formEmpty, animated: true, completion: nil)
}
func activityIndicatorFunction(){
activityIndicator = UIActivityIndicatorView(frame: CGRectMake(0, 0, 100, 100))
activityIndicator.backgroundColor = UIColor(red:0.16, green:0.17, blue:0.21, alpha:1)
activityIndicator.layer.cornerRadius = 6
activityIndicator.center = self.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.sharedApplication().beginIgnoringInteractionEvents()
}
}
JSON Data:
{
"68e42b7f-aea5-4c3f-b655-51a99cb05bb0" : {
"email" : "test1#test1.com",
"username" : "test1",
"waiting" : "0"
},
"8503d5a8-fc4a-492b-9883-ec3664898b4f" : {
"email" : "test2#test2.com",
"username" : "test2",
"waiting" : "0"
}
}
There are a few things going on here, but the most important one is that you cannot test for the existence of children with .ChildAdded. That makes sense if you think about it: the .ChildAdded event is raised when a child is added to the location. If no child is added, the event won't be raised.
So if you want to test if a child exists at a location, you need to use .Value. Once you do that, there are various way to detect existence. Here's one:
ref.queryOrderedByChild("waiting").queryEqualToValue("1")
.observeEventType(.Value, withBlock: { snapshot in
print(snapshot.value)
if !snapshot.exists() {
print("test2")
}
});
Check for NSNull. This is the code for observing a node. Queries work much the same way.
Here's a complete and tested app. To use, change the string 'existing' to some path you know exists, like your users path and the 'notexisting' to some path that does not exist
let myRootRef = Firebase(url:"https://your-app.firebaseio.com")
let existingRef = myRootRef.childByAppendingPath("existing")
let notExistingRef = myRootRef.childByAppendingPath("notexisting")
existingRef.observeEventType(.Value, withBlock: { snapshot in
if snapshot.value is NSNull {
print("This path was null!")
} else {
print("This path exists")
}
})
notExistingRef.observeEventType(.Value, withBlock: { snapshot in
if snapshot.value is NSNull {
print("This path was null!")
} else {
print("This path exists")
}
})
Please note that by using .Value, there will be a guaranteed a return result and the block will always fire. If your code used .ChildAdded then the block will only fire when a child exists.
Also, check to make sure of how your data appears in firebase.
users
user_0
waiting: 1
if different than
users
user_0
waiting: "1"
Note that "1" is not the same as 1.

Validating Information Before Moving to Next View in Swift

I have an application where I need to validate some information(zip code) from a database before I allow my iOS application to proceed to the next view. I used the zip code project to import a DB Table will all valid US Zip codes, and I want to have the zip code the inputed by the user validated before I allow them to proceed. If the zip code isn't valid, I hold them up at the current view and display an alert. I have a class to validate the zip code, but the zip code isn't being validated until after the next view is loaded. I've been leaning towards using a completion handler, but I'm not exactly sure if that's my best/only option. Thanks in advance.
EDIT:
The following is the whole class for retrieve the data
protocol ZipCodeLocationProtocol: class {
func zipCodeLocationDownloaded(zipLocation: Location)
}
class RetrieveZipCodeLocation: NSObject, NSURLSessionDataDelegate {
// MARK: Properties
weak var delegate: ZipCodeLocationProtocol!
var data: NSMutableData = NSMutableData()
let urlPath: String = "xxxx"
func downloadZipCodeLocation(zipcode: Int) {
let path = self.urlPath + "?zipcode=\(zipcode)"
let url: NSURL = NSURL(string: path)!
var session: NSURLSession!
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let task = session.dataTaskWithURL(url)
task.resume()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
self.data.appendData(data)
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON()
}
}
func parseJSON() {
var jsonResult: NSMutableArray = NSMutableArray()
var location = Location(title: "TITLE", coordinate: CLLocationCoordinate2D(latitude: 0, longitude: 0))
do {
jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:[]) as! NSMutableArray
} catch let error as NSError {
print(error)
}
var jsonElement: NSDictionary = NSDictionary()
for(var i = 0; i < jsonResult.count; i++) {
jsonElement = jsonResult[i] as! NSDictionary
let point = CLLocationCoordinate2D(latitude: (jsonElement["LATITUDE"] as! NSString).doubleValue, longitude: (jsonElement["LONGITUDE"] as! NSString).doubleValue)
// Get Information
location = Location(title: "TITLE", coordinate: point)
self.delegate.zipCodeLocationDownloaded(location)
}
}
I'm going to assume that a button triggers the segue to the next view. I'm also going to assume that the button is hooked up to a function for target-action. I'm also going to assume that you have the code to get the zip codes, otherwise you'll have to ask a separate question for that.
Assumptions aside, you need to present a UIAlertController instead of going to the next view controller when tapping the button. In order to do that:
func buttonAction() {
if verifyZipCode() {
let alert = UIAlertController(title: "Hold Up", message: "That zip code is invalid.", preferredStyle: .Alert)
let fixIt = UIAlertAction(title: "Fix It!", style: .Default, handler: nil) // handler could also contain code to make text field red or something interesting
alert.addAction(fixIt)
presentViewController(alert, animated: true, completion: nil)
} else {
// existing segue code
}
}
func verifyZipCode() -> Bool {
// Take text field text and verify zip code
}