I am wondering what would be the best practice when I want to pass data from model to controller.
What I want to do
I would like to update a label when the time changes.
CurrentTime.swift (Model)
var timer: Timer?
var currentTime: String?
init() {
if timer == nil{
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateCurrentTime), userInfo: nil, repeats: true)
}
}
#objc private func updateCurrentTime(){
let df = DateFormatter()
df.dateFormat = "HH:mm"
df.timeZone = TimeZone.current
let timezoneDate = df.string(from: Date())
currentTime = timezoneDate
}
ViewController.swift
class ViewController: UIViewController {
#IBOutlet var timeLabel: UILabel!
var currentTime = CurrentTime()
override func viewDidLoad() {
}
#IBAction func closeBtnWasPressed(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}
Option 1
1- Add this var
weak var delegate: ViewController?
2- in viewDidLoad of the vc
currentTime.delegate = self
3-
let timezoneDate = df.string(from: Date())
currentTime = timezoneDate
delegate?.update(currentTime)
4- inside the vc
func update(_ data:String) {
lbl.text = data
}
off course you can do
delegate?.lbl.text = currentTime
but above is MVC
Option 2
var ob:NSKeyValueObservation!
and in viewDidLoad
ob = currentTime.observe(\CurrentTime.currentTime, options: .new) { cur, tex in
timeLabel.text = tex
}
You should define a Dynamic class like this:
class Dynamic<T> {
var bind: (T) -> Void = { _ in }
var value: T? {
didSet {
bind(value!)
}
}
init(_ v: T) {
value = v
}
}
In your model change definition of the currentTime property like this:
var currentTime: Dynamic<String>
In your controller in viewDidLoad method add these codes:
yourModel.currentTime.bind = { [weak self] time in
self?.timeLabel.text = time
}
Related
So I have this big file with more than 600 words. I add them in my array and now I need to randomly show them on the Label. Every time a button is pressed the new random word has to be shown until the timer is ended. I've searched multiple sources for this question but couldn't apply them, because I'm new to this
import UIKit
class ViewController: UIViewController {
var wordArray: [String] = []
var i: Int = 0
var timer = Timer()
var totalSecond = 5
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
}
#objc func updateTime() {
if totalSecond != 0 {
totalSecond -= 1
timerLabel.text = "\(totalSecond) seconds left"
} else {
endTimer()
}
}
func endTimer() {
timer.invalidate()
}
func timeFormatted(_ totalSeconds: Int) -> String {
let seconds: Int = totalSeconds % 60
return String(format: "0:%02d", seconds)
}
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var showWordLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let url = Bundle.main.url(forResource: "english_words", withExtension: "txt")!
do {
let string = try String(contentsOf: url, encoding: .utf8)
wordArray = string.components(separatedBy: CharacterSet.newlines)
} catch {
print(error)
}
startTimer()
}
#IBAction func nextBtn(_ sender: UIButton) {
}
}
If you use swift 4.2 and above you can use randomElement() It returns an optional to avoid the empty case.
let yourArray = ["one", "two", "three", "Four"]
if let randomName = yourArray.randomElement() {
print(randomName)
}
if you use Swift 4.1 or below, you do in this way:
let array = ["one", "two", "three", "Four"]
let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
print(array[randomIndex])
Although I'm not 100% sure I understand you problem here a modified version of your viewController.
See comments in code.
class ViewController: UIViewController {
var wordArray: [String] = []
var i: Int = 0
var timer = Timer()
var totalSecond = 5
func startTimer() {
// Stop old timer
timer.invalidate()
// Start new timer
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)
}
#objc func updateTime() {
if totalSecond != 0 {
totalSecond -= 1
timerLabel.text = "\(totalSecond) seconds left"
} else {
endTimer()
}
}
func endTimer() {
timer.invalidate()
}
func timeFormatted(_ totalSeconds: Int) -> String {
let seconds: Int = totalSeconds % 60
return String(format: "0:%02d", seconds)
}
#IBOutlet weak var timerLabel: UILabel!
#IBOutlet weak var showWordLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let url = Bundle.main.url(forResource: "english_words", withExtension: "txt")!
do {
let string = try String(contentsOf: url, encoding: .utf8)
wordArray = string.components(separatedBy: CharacterSet.newlines)
} catch {
print(error)
}
startTimer()
}
#IBAction func nextBtn(_ sender: UIButton) {
// Fetch random Word from array
let randomValue = Int.random(in: 0..<wordArray.count)
let randomWord = wordArray[randomValue]
// Assign to label
showWordLabel.text = randomWord
// Restart timer
startTimer()
}
}
I have a tabbed app that starts recording on one tab, and plots the mic levels on another tab.
In the first VC, I'm gathering mic levels and storing them in an array in the model. I'm using another method in the model to update the data, and I'm calling it in the second VC in order to update the view.
What I want to do is update the chart in the second view controller from the first view controller (where the logic for storing data in the model is)
Model:
Chart.swift
import Charts
class Chart {
static let sharedInstance = Chart()
var lineChartView: LineChartView!
func setChartValues() {
let entries = (0..<GraphData.sharedInstance.array.count).map { (i) -> ChartDataEntry in
let val = GraphData.sharedInstance.array[i]
print(ChartDataEntry(x: Double(i), y: val))
return ChartDataEntry(x: Double(i), y: val)
}
let set1 = LineChartDataSet(values: entries, label: "DataSet 1")
let data = LineChartData(dataSet: set1)
lineChartView.data = data
}
}
GraphData.swift
class GraphData {
static let sharedInstance = GraphData()
var array = [Double]()
}
View Controllers:
First VC: (complete code per comment)
import UIKit
import AVFoundation
class SoundController: UIViewController, AVAudioRecorderDelegate {
var recordingSession: AVAudioSession!
var audioRecorder: AVAudioRecorder!
var timer = Timer()
#IBOutlet weak var errorLbl: UILabel!
#IBOutlet weak var recordBtn: UIButton!
#IBAction func recordButton(_ sender: UIButton) {
if audioRecorder == nil {
startRecording()
} else {
finishRecording(success: true)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(false)
errorLbl.text = ""
}
override func viewDidLoad() {
super.viewDidLoad()
recordPermission()
}
func recordPermission() {
recordingSession = AVAudioSession.sharedInstance()
do {
try recordingSession.setCategory(.playAndRecord, mode: .default)
try recordingSession.setActive(true)
recordingSession.requestRecordPermission() { allowed in
DispatchQueue.main.async {
if allowed {
print("recording allowed")
} else {
self.errorLbl.text = "Recording Permission was Denied. Please open settings and allow Cry It Out to access the microphone."
}
}
}
} catch {
self.errorLbl.text = "Recording Permission was Denied. Please open settings and allow the app to access the microphone."
}
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
func startRecording() {
if recordBtn.titleLabel?.text == "Tap to Re-record" {
//reset values array
GraphData.sharedInstance.array = []
}
let audioFilename = getDocumentsDirectory().appendingPathComponent("baby.m4a")
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 12000,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
do {
audioRecorder = try AVAudioRecorder(url: audioFilename, settings: settings)
audioRecorder.delegate = self
audioRecorder.isMeteringEnabled = true
runTimer()
audioRecorder.record()
runTimer()
recordBtn.setTitle("Tap to Stop", for: .normal)
} catch {
finishRecording(success: false)
}
}
func levelTimerCallback() -> Float {
if audioRecorder != nil {
audioRecorder.updateMeters()
//If we are beyond a threshold value (-15)
if audioRecorder.averagePower(forChannel: 0) > -15 {
return audioRecorder.averagePower(forChannel: 0)
}
}
return 0
}
func finishRecording(success: Bool) {
//stop recording and reset recorder to nil for other checks
audioRecorder.stop()
audioRecorder = nil
if success {
recordBtn.setTitle("Tap to Re-record", for: .normal)
if timer.isValid {
timer.invalidate()
}
} else {
//Recording Failed
recordBtn.setTitle("Tap to Record", for: .normal)
//disable timer if running (might be running or might not)
if timer.isValid {
timer.invalidate()
}
}
}
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
if !flag {
finishRecording(success: false)
}
}
//MARK: Timers
#objc func updateTimer() {
if levelTimerCallback() != 0 {
let date = Date()
let calendar = Calendar.current
let month = calendar.component(.month, from: date)
let day = calendar.component(.day, from: date)
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
let seconds = calendar.component(.second, from: date)
let prettyDate = "\(month)/\(day) \(hour):\(minutes) and \(seconds) seconds"
print(prettyDate)
GraphData.sharedInstance.array.append(Double(levelTimerCallback()))
//does this run the method? It should
GraphController.sharedInstance.lineChartView?.data = Chart.sharedInstance.setChartValues()
}
}
func runTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(SoundController.updateTimer)), userInfo: nil, repeats: true)
}
func stopTimer() {
timer.invalidate()
}
}
Second VC:
import UIKit
import Charts
class GraphController: UIViewController {
static let sharedInstance = GraphController()
#IBOutlet weak var lineChartView: LineChartView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
self.lineChartView.data = Chart.sharedInstance.setChartValues()
}
}
Try this solution without lambda functions. You don't need use static values.
1. Prepare your GraphController to have a function to receive data
class GraphController: UIViewController {
...
func dataReceived ( gData : GraphData ) {
DispatchQueue.main.async {
// Update your chart with gData
}
}
}
2. Get the reference of GraphController and use the function of step 1 to make your updates.
Please, get the reference of your GraphController from tab and use this reference to call a function to make your chart updates. I don't know exactely your situation, but if you have problems to make it, please look this: https://stackoverflow.com/a/39499751/5140756
class SoundController: UIViewController, AVAudioRecorderDelegate {
var graphController : GraphController?
...
override func viewDidLoad() {
super.viewDidLoad()
...
// get graph controller reference from tabbar.
self.graphController = self.tabBarController.viewControllers![INDEX_OF_VIEW_CONTROLLER] as! GraphController
}
// finally on your function call the function's graph controller receive data
#objc func updateTimer() {
if levelTimerCallback() != 0 {
let date = Date()
let calendar = Calendar.current
let month = calendar.component(.month, from: date)
let day = calendar.component(.day, from: date)
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
let seconds = calendar.component(.second, from: date)
let prettyDate = "\(month)/\(day) \(hour):\(minutes) and \(seconds) seconds"
print(prettyDate)
GraphData.sharedInstance.array.append(Double(levelTimerCallback()))
//does this run the method? It should
//GraphController.sharedInstance.lineChartView?.data = Chart.sharedInstance.setChartValues()
if graphController != nil {
self.graphController!.dataReceived( gData: GraphData.sharedInstance )
}
}
}
}
Please, look the code, and make some changes that you need, I tried automate the max that I can.
My issue is this I have two viewControllers connected with a modal segue like normal A--->B, A has the controls like textFields, switches, buttons and a mapView where I get the userLocation. B hast only a button, and a mapView at the moment, but when I tap the exit button it does successfully dismisses viewController B and shows A only controls are frozen, can't tap anything anymore, I don't know why. Any help?
B code
import UIKit
import MapKit
import Parse
import CoreLocation
class MapaMososViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapMozosFollow: MKMapView!
var totlaAutomozo: String!
var fechaRegistro: String!
override func viewDidLoad() {
super.viewDidLoad()
mapMozosFollow.delegate = self
mapMozosFollow.showsUserLocation = true
mapMozosFollow.showsTraffic = false
mapMozosFollow.showsScale = false
print(mapMozosFollow.userLocation.location)
}
override func viewDidAppear(_ animated: Bool) {
self.displayError(error: "Exito", message: "Tu pago ha sido procesado, en unos momentos atenderemos tu orden. Total es de $\(totlaAutomozo!) la fecha registrada \(fechaRegistro!)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewWillDisappear(_ animated: Bool) {
}
#IBAction func salirTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: {
print("here dismissing")
})
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(locations.last!.coordinate)
centerMapOnLocation(locations.last!)
}
let regionRadius: CLLocationDistance = 2000
func centerMapOnLocation(_ location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
mapMozosFollow.setRegion(coordinateRegion, animated: true)
}
}
EDIT 1: A ViewController code.
import UIKit
import Parse
import MapKit
import BraintreeDropIn
import Braintree
class ViewController: UIViewController, PayPalPaymentDelegate, PayPalFuturePaymentDelegate, PayPalProfileSharingDelegate, CLLocationManagerDelegate, UITextFieldDelegate, MKMapViewDelegate, BTDropInViewControllerDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var mapaLugar: MKMapView!
#IBOutlet weak var numeroExteriorTextField: UITextField!
#IBOutlet weak var telefonoTextField: UITextField!
#IBOutlet weak var lavadoSwitch: UISwitch!
#IBOutlet weak var lavadoYAspiradSwitch: UISwitch!
#IBOutlet weak var numeroCarrosTextField: UITextField!
#IBOutlet weak var numeroMinivanTextField: UITextField!
#IBOutlet weak var numeroPickUpsTextField: UITextField!
#IBOutlet weak var numeroVansTextField: UITextField!
#IBOutlet weak var numeroAspiradoCarrosTextField: UITextField!
#IBOutlet weak var numeroAspiradoMinivanTextField: UITextField!
#IBOutlet weak var numeroAspiradoPickUpsTextField: UITextField!
#IBOutlet weak var numeroAspiradoVansTextField: UITextField!
#IBOutlet weak var botonRealizarPedido: UIButton!
#IBOutlet weak var botonInstrucciones: UIButton!
#IBOutlet weak var totalLabel: UILabel!
var showAlertFirstTime: Bool = true
var locationManager: CLLocationManager = CLLocationManager()
var ubicacion: CLLocationCoordinate2D!
var environment:String = PayPalEnvironmentSandbox {
willSet(newEnvironment) {
if (newEnvironment != environment) {
PayPalMobile.preconnect(withEnvironment: newEnvironment)
}
}
}
var braintreeClient: BTAPIClient?
let defaults = UserDefaults.standard
var resultText = "" // empty
var payPalConfig = PayPalConfiguration() // default
var total: NSDecimalNumber!
var vistaDeMozos: Bool = false
var fechaRegistro: String!
var totalToSend: String!
#IBOutlet weak var constrainSizeMap: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
botonInstrucciones.backgroundColor = UIColor(colorLiteralRed: (200.0/255.0), green: 0.0, blue: 0.0, alpha: 1.0)
botonInstrucciones.layer.cornerRadius = 3
botonInstrucciones.layer.borderWidth = 2
botonInstrucciones.layer.borderColor = UIColor.clear.cgColor
botonInstrucciones.layer.shadowColor = UIColor(colorLiteralRed: (100.0/255.0), green: 0.0, blue: 0.0, alpha: 1.0).cgColor
botonInstrucciones.layer.shadowOpacity = 1.0
botonInstrucciones.layer.shadowRadius = 1.0
botonInstrucciones.layer.shadowOffset = CGSize(width: 0, height: 3)
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
NotificationCenter.default.post(name: Notification.Name(rawValue: "keyPressed"), object: nil)
numeroCarrosTextField.delegate = self
numeroMinivanTextField.delegate = self
numeroPickUpsTextField.delegate = self
numeroVansTextField.delegate = self
numeroAspiradoCarrosTextField.delegate = self
numeroAspiradoMinivanTextField.delegate = self
numeroAspiradoPickUpsTextField.delegate = self
numeroAspiradoVansTextField.delegate = self
do {
if defaults.object(forKey: "clientId") == nil || clientId == "000" {
let idTest = try PFCloud.callFunction("newCutomer", withParameters: nil)
print(idTest)
clientId = idTest as! String
defaults.set(clientId, forKey: "clientId")
} else {
print(self.clientId)
}
} catch let error {
print(error)
}
if defaults.object(forKey: "clientId") == nil {
} else {
clientId = defaults.string(forKey: "clientId")!
print(clientId)
}
fetchClientToken()
NotificationCenter.default.addObserver(
self,
selector: #selector(ViewController.keyboardWillShow(notification:)),
name: NSNotification.Name.UIKeyboardWillShow,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(ViewController.keyboardWillHide(notification:)),
name: NSNotification.Name.UIKeyboardWillHide,
object: nil
)
scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.interactive
let touch = UITapGestureRecognizer(target: self, action: #selector(ViewController.singleTapGestureCaptured(gesture:)))
scrollView.addGestureRecognizer(touch)
}
func singleTapGestureCaptured(gesture: UITapGestureRecognizer){
self.view.endEditing(true)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if showAlertFirstTime {
showAlertFirstTime = false
} else {
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
PayPalMobile.preconnect(withEnvironment: environment)
print("stop test")
}
#IBAction func realizarPedidoTapped(_ sender: UIButton) {
let numeroExterior = numeroExteriorTextField.text!
let numeroMotosLavado = numeroCarrosTextField.text!
let numeroDeportivosLavado = numeroMinivanTextField.text!
let numeroCarroLavado = numeroPickUpsTextField.text!
let numeroCamionLavado = numeroVansTextField.text!
let numeroMotoLavadoAspirado = numeroAspiradoCarrosTextField.text!
let numeroDeportivoLavadoAspirado = numeroAspiradoMinivanTextField.text!
let numeroCarroLavadoAspirado = numeroAspiradoPickUpsTextField.text!
let numeroCamionLavadoAspirado = numeroAspiradoVansTextField.text!
let numeroTelefono = telefonoTextField.text!
if numeroExterior == "" || numeroTelefono == "" {
displayError("Error", message: "Te falto llenar tu numero exterior y/o telefono")
} else {
//Braintree init
self.braintreeClient = BTAPIClient(authorization: clientToken)
let items = [item1]
let subtotal = PayPalItem.totalPrice(forItems: items)
//var subtotal = PayPalItem.totalPrice(forItems: items)
let shipping = NSDecimalNumber(string: "0.00")
let tax = NSDecimalNumber(string: "0.00")
//details ???
let paymentDetails = PayPalPaymentDetails(subtotal: subtotal, withShipping: shipping, withTax: tax)
self.total = subtotal.adding(shipping).adding(tax)
let payment = PayPalPayment(amount: total, currencyCode: "MXN", shortDescription: "Automozo inc", intent: .sale)
payment.items = items
payment.paymentDetails = paymentDetails
print("\(payment.localizedAmountForDisplay)")
self.showDropIn(clientTokenOrTokenizationKey: clientToken)
if (payment.processable) {
let paymentViewController = PayPalPaymentViewController(payment: payment, configuration: payPalConfig, delegate: self)
}
else {
print("Payment not processalbe: \(payment.description)")
print("payment not processable \(payment)")
displayError("Error", message: "Hubo un error al procesar tu pago, por favor intenta de nuevo.")
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if segue.identifier == "MapaMozosSegue" {
let mapaMozosVC = segue.destination as! MapaMososViewController
mapaMozosVC.totlaAutomozo = totalToSend!
mapaMozosVC.fechaRegistro = fechaRegistro
locationManager.stopUpdatingLocation()
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
textField.resignFirstResponder()
print("test text field ended")
if textField.text == "" {
textField.text = "0"
}
var numeroCarrosLavadoVar = numeroCarrosTextField.text!
var numeroMinivansLavadoVar = numeroMinivanTextField.text!
var numeroPickUpsLavadoVar = numeroPickUpsTextField.text!
var numeroVansLavadoVar = numeroVansTextField.text!
var numeroCarrosLavadoAspiradoVar = numeroAspiradoCarrosTextField.text!
var numeroMinivansLavadoAspiradoVar = numeroAspiradoMinivanTextField.text!
var numeroPickUpsLavadoAspiradoVar = numeroAspiradoPickUpsTextField.text!
var numeroVansLavadoAspiradoVar = numeroAspiradoVansTextField.text!
if numeroCarrosLavadoVar == "" {
numeroCarrosLavadoVar = "0"
numeroCarrosTextField.text = "0"
}
if numeroMinivansLavadoVar == "" {
numeroMinivansLavadoVar = "0"
numeroMinivanTextField.text = "0"
}
if numeroPickUpsLavadoVar == "" {
numeroPickUpsLavadoVar = "0"
numeroPickUpsTextField.text = "0"
}
if numeroVansLavadoVar == "" {
numeroVansLavadoVar = "0"
numeroVansTextField.text = "0"
}
if numeroCarrosLavadoAspiradoVar == "" {
numeroCarrosLavadoAspiradoVar = "0"
numeroAspiradoCarrosTextField.text = "0"
}
if numeroMinivansLavadoAspiradoVar == "" {
numeroMinivansLavadoAspiradoVar = "0"
numeroMinivanTextField.text = "0"
}
if numeroPickUpsLavadoAspiradoVar == "" {
numeroPickUpsLavadoAspiradoVar = "0"
numeroAspiradoPickUpsTextField.text = "0"
}
if numeroVansLavadoAspiradoVar == "" {
numeroVansLavadoAspiradoVar = "0"
numeroVansTextField.text = "0"
}
let priceOfLavadoCarro = Int(numeroCarrosLavadoVar)! * pricesLavado["LavadoCarro"]!
let priceOfLavadoMinivan = Int(numeroMinivansLavadoVar)! * pricesLavado["LavadoMinivan"]!
let priceOfLavadoPickUp = Int(numeroPickUpsLavadoVar)! * pricesLavado["LavadoPickUp"]!
let priceOfLavadoVan = Int(numeroVansLavadoVar)! * pricesLavado["LavadoVan"]!
//Lavado y Aspirado
let priceOfLavadoYAspiradoCarro = Int(numeroCarrosLavadoAspiradoVar)! * pricesLavadoYAspirado["LavadoYAspiradoCarro"]!
let priceOfLavadoYAspiradoMinivan = Int(numeroMinivansLavadoAspiradoVar)! * pricesLavadoYAspirado["LavadoYAspiradoMinivan"]!
let priceOfLavadoYAspiradoPickUp = Int(numeroPickUpsLavadoAspiradoVar)! * pricesLavadoYAspirado["LavadoYAspiradoPickUp"]!
let priceOfLavadoYAspiradoVan = Int(numeroVansLavadoAspiradoVar)! * pricesLavadoYAspirado["LavadoYAspiradoVan"]!
let totalAutomozo = priceOfLavadoCarro + priceOfLavadoMinivan + priceOfLavadoPickUp + priceOfLavadoVan + priceOfLavadoYAspiradoCarro + priceOfLavadoYAspiradoMinivan + priceOfLavadoYAspiradoPickUp + priceOfLavadoYAspiradoVan
print(totalAutomozo)
totalLabel.text = "\(totalAutomozo).00"
textField.resignFirstResponder()
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
if (textField.text?.characters.count)! == 1 {
print("text quota meet")
textField.resignFirstResponder()
self.view.endEditing(true)
return true
} else {
textField.text = "0"
}
return true
}
let regionRadius: CLLocationDistance = 100
func centerMapOnLocation(_ location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
mapaLugar.setRegion(coordinateRegion, animated: true)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
centerMapOnLocation(locations.last!)
ubicacion = locations.last!.coordinate
}
// Mark - Braintree methods
func showDropIn(clientTokenOrTokenizationKey: String) {
var value: Bool = false
var totlaAutomozo = self.totalLabel.text
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM dd YYYY HH:mm"
dateFormatter.timeZone = NSTimeZone.local
fechaRegistro = dateFormatter.string(from: Date())
let request = BTDropInRequest()
request.amount = "\(total)"
request.currencyCode = "MXN"
print(request.description)
BTUIKAppearance.darkTheme()
BTUIKAppearance.sharedInstance().activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
// request.
let dropIn = BTDropInController(authorization: clientTokenOrTokenizationKey, request: request)
{ (controller, result, error) in
if (error != nil) {
print("ERROR")
} else if (result?.isCancelled == true) {
print("CANCELLED")
} else if let result = result {
// Use the BTDropInResult properties to update your UI
print(result.paymentOptionType)
print("payment method: \(result.paymentMethod?.nonce)")
print("ppayment desc \(result.paymentDescription)")
print(result.paymentIcon.description)
value = self.postNonceToServer(paymentMethodNonce: (result.paymentMethod?.nonce)!)
}
controller.dismiss(animated: true, completion: nil)
if value {
self.locationManager.stopUpdatingLocation()
self.performSegue(withIdentifier: "MapaMozosSegue", sender: self)
self.vistaDeMozos = true
} else {
self.displayError("Alerta", message: "El pedido ha sido cancelado exitosamente.")
//top row
self.numeroCarrosTextField.text = "0"
self.numeroMinivanTextField.text = "0"
self.numeroPickUpsTextField.text = "0"
self.numeroVansTextField.text = "0"
//bottom row
self.numeroAspiradoCarrosTextField.text = "0"
self.numeroAspiradoMinivanTextField.text = "0"
self.numeroAspiradoPickUpsTextField.text = "0"
self.numeroAspiradoVansTextField.text = "0"
//data
self.telefonoTextField.text = ""
self.telefonoTextField.text = ""
}
}
self.present(dropIn!, animated: true, completion: nil)
}
func userDidCancelPayment() {
self.dismiss(animated: true, completion: nil)
}
func postNonceToServer(paymentMethodNonce: String) -> Bool {
var val = true
do {
var response = try PFCloud.callFunction("checkout", withParameters: ["payment_method_nonce":paymentMethodNonce, "amount":"\(total!).00", "customerId": clientId])
print(response)
} catch let error {
print(error.localizedDescription)
}
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM. dd, YYYY HH:mm"
dateFormatter.timeZone = NSTimeZone.local
fechaRegistro = dateFormatter.string(from: Date())
let usuarioPagado: PFObject = PFObject(className: "Ordenes")
let location: PFGeoPoint = PFGeoPoint(latitude: ubicacion.latitude, longitude: ubicacion.longitude)
usuarioPagado["Ubicacion"] = location
usuarioPagado["NumeroExterior"] = numeroExteriorTextField.text!
usuarioPagado["NumeroDeTelefono"] = telefonoTextField.text!
usuarioPagado["LavadoCarro"] = numeroCarrosTextField.text!
usuarioPagado["LavadoMiniVan"] = numeroMinivanTextField.text!
usuarioPagado["LavadoPickUp"] = numeroPickUpsTextField.text!
usuarioPagado["LavadoDeVan"] = numeroVansTextField.text!
usuarioPagado["LavadoAspiradoCarro"] = numeroAspiradoCarrosTextField.text!
usuarioPagado["LavadoAspiradoMiniVan"] = numeroAspiradoMinivanTextField.text!
usuarioPagado["LavadoAspiradoPickUp"] = numeroAspiradoPickUpsTextField.text!
usuarioPagado["LavadoAspiradoDeVan"] = numeroAspiradoVansTextField.text!
usuarioPagado["Monto"] = totalLabel.text!
usuarioPagado["NumeroDeTelefono"] = telefonoTextField.text!
usuarioPagado["TipoDeCelular"] = "iPhone"
usuarioPagado["FechaDeOrden"] = fechaRegistro
self.totalToSend = self.totalLabel.text!
usuarioPagado.saveInBackground() {
(success: Bool, error: Error?) -> Void in
if error == nil {
//done
print("saved object")
val = false
} else {
//not done
print("not saved because \(error?.localizedDescription)")
}
}
numeroCarrosTextField.text = "0"
numeroMinivanTextField.text = "0"
numeroPickUpsTextField.text = "0"
numeroVansTextField.text = "0"
numeroAspiradoCarrosTextField.text = "0"
numeroAspiradoMinivanTextField.text = "0"
numeroAspiradoPickUpsTextField.text = "0"
numeroAspiradoVansTextField.text = "0"
totalLabel.text = "00.00"
self.lavadoSwitch.isOn = false
self.lavadoYAspiradSwitch.isOn = false
self.numeroExteriorTextField.text = ""
self.telefonoTextField.text = ""
self.numeroCarrosTextField.isHidden = true
self.numeroMinivanTextField.isHidden = true
self.numeroPickUpsTextField.isHidden = true
self.numeroVansTextField.isHidden = true
self.numeroAspiradoCarrosTextField.isHidden = true
self.numeroAspiradoMinivanTextField.isHidden = true
self.numeroAspiradoPickUpsTextField.isHidden = true
self.numeroAspiradoVansTextField.isHidden = true
return val
}
func drop(inViewControllerDidLoad viewController: BTDropInViewController) {
print("did load view drop")
}
func drop(inViewControllerDidCancel viewController: BTDropInViewController) {
print("did cancel drop payment")
}
func drop(inViewControllerWillComplete viewController: BTDropInViewController) {
print("drop will complete payment")
}
func drop(_ viewController: BTDropInViewController, didSucceedWithTokenization paymentMethodNonce: BTPaymentMethodNonce) {
var totlaAutomozo = totalLabel.text
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM dd YYYY HH:mm"
dateFormatter.timeZone = NSTimeZone.local
fechaRegistro = dateFormatter.string(from: Date())
print("did succeeded with tokenization")
print(" \(paymentMethodNonce.nonce)")
var value = postNonceToServer(paymentMethodNonce: paymentMethodNonce.nonce)
self.dismiss(animated: true, completion: nil)
if value {
displayError("Exito", message: "Tu pago ha sido procesado, en unos momentos atenderemos tu orden. Total es de $\(totlaAutomozo ?? "00.00") la fecha registrada \(fechaRegistro)")
} else {
self.displayError("Error", message: "Hubo un error al guardar tu informacion, ponte en contacto con nosotros.")
}
}
func fetchClientToken() {
do {
let response = try PFCloud.callFunction("generateToken", withParameters: ["clientId": clientId])
self.clientToken = response as! String
} catch let error {
print(error)
}
}
func keyboardWillShow(notification:NSNotification){
var userInfo = notification.userInfo!
var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
keyboardFrame = self.view.convert(keyboardFrame, from: nil)
var contentInset:UIEdgeInsets = self.scrollView.contentInset
contentInset.bottom = keyboardFrame.size.height
self.scrollView.contentInset = contentInset
}
func keyboardWillHide(notification:NSNotification){
let contentInset:UIEdgeInsets = UIEdgeInsets.zero
self.scrollView.contentInset = contentInset
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.view.endEditing(true)
}
func showFullMap() {
if vistaDeMozos {
self.telefonoTextField.isHidden = true
self.botonRealizarPedido.isHidden = true
self.lavadoSwitch.isHidden = true
self.lavadoYAspiradSwitch.isHidden = true
self.botonRealizarPedido.isHidden = true
self.numeroExteriorTextField.isHidden = true
self.numeroCarrosTextField.isHidden = true
self.numeroMinivanTextField.isHidden = true
self.numeroPickUpsTextField.isHidden = true
self.numeroVansTextField.isHidden = true
self.numeroAspiradoCarrosTextField.isHidden = true
self.numeroAspiradoMinivanTextField.isHidden = true
self.numeroAspiradoPickUpsTextField.isHidden = true
self.numeroAspiradoVansTextField.isHidden = true
self.view.layoutSubviews()
} else {
}
}
}
Did you try pausing the app with the debugger to inspect the stack frames? Sometimes that can help you spot deadlocks or infinite loops. You'll find the pause button in the bar between the code editor and the debugger (or at the bottom if the debugger is hidden):
Look at the stack frames in the Debug Navigator on the left-hand side of the Xcode window. Can you see anything suspicious? Here is a stack frame that indicates the app is idling on the main run loop:
That's usually perfectly normal as the app is waiting for user input. If you see something like the following you are likely dealing with a deadlock:
The semaphore stops the thread from continuing until some other thread opens the semaphore again. You are dealing with a deadlock if two or more threads are stopped waiting for each other. If the main thread is involved the app will be frozen.
The third possibility I can think of is an infinite loop on the main thread:
Of course this one is pretty easy to spot :)
The darker entries in stack frames are from your own code. You can click on those entries to find the exact locations and use the debugger to inspect variables. The other entries will show you assembly.
If you could not find anything suspicious by pausing the debugger I would start to remove those parts of code bit by bit, trying to reproduce the problem each time. There are two possible results:
You remove some harmless looking code and suddenly it works as expected. You can then take a closer look at the code you removed, making it easier to figure the issue out.
You end up with a minimal project exhibiting the issue. This is now much easier to debug and reason about because there is nothing else distracting you from the problem. You also have a much higher probability of getting help from coworkers or here on Stack Overflow when your code sample is as small as possible.
A third attack vector is checking the View Debugger:
Are there any transparent views above the frozen view controller blocking user events?
Is user interaction enabled on the controls and views involved? Select a view and check the Object Inspector on the right-hand side:
Try to remove DispatchQueue.main.async or the A viewController won't get notified. It's interaction has been disabled because the segue
//DispatchQueue.main.async {
self.dismiss(animated: true, completion: {
print("here dismissing")
})
//}
Make sure to check if any NSDelayedPerforming methods are blocking the main thread (Foundation > NSRunloop). i.e. performSelector afterDelay...
In my case (Objective-C) I had to use cancelPreviousPerformRequestsWithTarget in the viewDidDisappear instance method of the ViewController.
[NSObject cancelPreviousPerformRequestsWithTarget:self];
I think the same applies when using NSTimer.scheduledTimerWithTimeInterval (Swift) without invalidating the timer in the proper life cycle method.
enter code hereI'm trying to add a calendar feature to my app, but I'm having 2 errors on two different viewcontrollers, I can't find out what I am missing.
The error says:
Value of type AddEventViewController has no member "Calendar" on the line addEventVC.calendar = calendar
2nd viewcontroller
1st viewcontroller
Code:
import UIKit
import EventKit
class EventsViewController: UIViewController, UITableViewDataSource, EventAddedDelegate {
#IBOutlet weak var tableView: UITableView!
var calendar: EKCalendar!
var events: [EKEvent]?
#IBOutlet weak var eventsTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
loadEvents()
}
func loadEvents() {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let startDate = dateFormatter.date(from: "2016-01-01")
let endDate = dateFormatter.date(from: "2016-12-31")
if let startDate = startDate, let endDate = endDate {
let eventStore = EKEventStore()
let eventsPredicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: [calendar])
self.events = eventStore.events(matching: eventsPredicate).sorted {
(e1: EKEvent, e2: EKEvent) in
return e1.startDate.compare(e2.startDate) == ComparisonResult.orderedAscending
}
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let events = events {
return events.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "basicCell")!
cell.textLabel?.text = events?[(indexPath as NSIndexPath).row].title
cell.detailTextLabel?.text = formatDate(events?[(indexPath as NSIndexPath).row].startDate)
return cell
}
func formatDate(_ date: Date?) -> String {
if let date = date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy"
return dateFormatter.string(from: date)
}
return ""
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as! UINavigationController
let addEventVC = destinationVC.childViewControllers[0] as! AddEventViewController
addEventVC.calendar = calendar
addEventVC.delegate = self
}
// MARK: Event Added Delegate
func eventDidAdd() {
self.loadEvents()
self.eventsTableView.reloadData()
}
}
AddEventViewController :
class AddEventViewController: UIViewController {
#IBOutlet weak var eventNameTextField: UITextField!
#IBOutlet weak var eventStartDatePicker: UIDatePicker!
#IBOutlet weak var eventEndDatePicker: UIDatePicker!
var delegate: EventAddedDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.eventStartDatePicker.setDate(initialDatePickerValue(), animated: false)
self.eventEndDatePicker.setDate(initialDatePickerValue(), animated: false)
}
func initialDatePickerValue() -> Date {
let calendarUnitFlags: NSCalendar.Unit = [.year, .month, .day, .hour, .minute, .second]
var dateComponents = (Calendar.current as NSCalendar).components(calendarUnitFlags, from: Date())
dateComponents.hour = 0
dateComponents.minute = 0
dateComponents.second = 0
return Calendar.current.date(from: dateComponents)!
}
#IBAction func cancelButtonTapped(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
#IBAction func addEventButtonTapped(_ sender: UIButton) {
// Create an Event Store instance
let eventStore = EKEventStore();
// Use Event Store to create a new calendar instance
if let calendarForEvent = eventStore.calendar(withIdentifier: self.calendar.calendarIdentifier)
{
let newEvent = EKEvent(eventStore: eventStore)
newEvent.calendar = calendarForEvent
newEvent.title = self.eventNameTextField.text ?? "Some Event Name"
newEvent.startDate = self.eventStartDatePicker.date
newEvent.endDate = self.eventEndDatePicker.date
// Save the event using the Event Store instance
do {
try eventStore.save(newEvent, span: .thisEvent, commit: true)
delegate?.eventDidAdd()
self.dismiss(animated: true, completion: nil)
} catch {
let alert = UIAlertController(title: "Event could not save", message: (error as NSError).localizedDescription, preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(OKAction)
self.present(alert, animated: true, completion: nil)
}
}
}
}
You are calling addEventVC.calendar = calendar but your AddEventViewController doesn't have a variable called calendar which is why you get the error AddEventViewController has no member "Calendar".
I am trying to change the label that you see in my screenshot that has a green background and says We Are Open.
I would like the bottom label to turn RED and say "Sorry we are closed" whenever the listed opening times have passed and then go back to GREEN and say "We Are Open" at the correct opening times.
I've managed to import date and time successfully into the top label but I'm not sure how do the bottom label.
Here is the code:
import UIKit
import Firebase
import FirebaseInstanceID
import FirebaseMessaging
class FirstViewController: UIViewController {
var timer = Timer()
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var openStatusLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
FIRMessaging.messaging().subscribe(toTopic: "/topics/news")
self.timer = Timer.scheduledTimer(timeInterval: 1.0,
target: self,
selector: #selector(FirstViewController.tick),
userInfo: nil,
repeats: true)
}
#objc func tick() {
timeLabel.text = DateFormatter.localizedString(from: NSDate() as Date,
dateStyle: .medium,
timeStyle: .medium)
}
}
Below code i have try and it will work fine. Initially i created two UILabel with proper constraints. Then Create outlets for two label to view controller. Then try this code.
import UIKit
extension NSDate {
func dayOfWeek() -> Int? {
guard
let calender: NSCalendar = NSCalendar.currentCalendar(),
let component: NSDateComponents = calender.components(.Weekday, fromDate: self) else { return nil }
return component.weekday
}
}
class ViewController: UIViewController {
#IBOutlet var timeOfTheDay: UILabel! //Top Label for showing current time
#IBOutlet var Status: UILabel! //Status Label for showing open or close
override func viewDidLoad() {
super.viewDidLoad()
self.dateCheck()
}
func dateCheck()
{
let today = NSDate().dayOfWeek()
if today == 1
{
//print("Sunday")
self.closed()
}
else if today == 2
{
//print("Monday")
self.closed()
}
else if today == 3
{
//print("Tuesday")
self.uptoEvening()
}
else if today == 4
{
//print("Wednesday")
self.uptoNight()
}
else if today == 5
{
// print("Thursday")
self.uptoNight()
}
else if today == 6
{
//print("Friday")
self.uptoNight()
}
else
{
//print("Saturday")
self.uptoEvening()
}
}
func getTime() -> (hour:Int, minute:Int, second:Int) {
let currentDateTime = NSDate()
let calendar = NSCalendar.currentCalendar()
let component = calendar.components([.Hour,.Minute,.Second], fromDate: currentDateTime)
let hour = component.hour
let minute = component.minute
let second = component.second
return (hour,minute,second)
}
func closed()
{
timeOfTheDay.text = String(getTime().hour)+" : "+String(getTime().minute)+" : "+String(getTime().second)
timeOfTheDay.backgroundColor = UIColor.redColor()
timeOfTheDay.textColor = UIColor.whiteColor()
Status.text = "Sorry! Today, We are Closed!"
Status.backgroundColor = UIColor.redColor()
Status.textColor = UIColor.whiteColor()
}
func opened(endTime:String)
{
timeOfTheDay.text = String(getTime().hour)+" : "+String(getTime().minute)+" : "+String(getTime().second)
timeOfTheDay.backgroundColor = UIColor.greenColor()
timeOfTheDay.textColor = UIColor.whiteColor()
Status.text = "Hi! still we are opened upto "+endTime
Status.backgroundColor = UIColor.greenColor()
Status.textColor = UIColor.whiteColor()
}
func uptoEvening()
{
let time = getTime().hour
switch time
{
case 09...16: opened("17") //set time for 09:00 to 16:59
default:closed()
}
}
func uptoNight()
{
let time = getTime().hour
switch time
{
case 09...20: opened("21") //set time for 09:00 to 20:59
default:closed()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Extension for swift 3:
extension Date {
func dayOfWeek() -> Int? {
let calender: Calendar = Calendar.current
let component: DateComponents = (calender as NSCalendar).components(.weekday, from: self)
return component.weekday
}
}