I've built a likert quiz and I'm trying to create a results page that looks like the second view controller. So far all I've been able to return is the score and personality ranked (first view controller).
I'm not sure how I can show the quiz results in order. I basically would want to rank them and adjust the cells, while showing the point total but I have no clue what to do.
class SurveyResultsViewController: UITableViewController {
#IBOutlet var lblSortedScores : [UILabel]!
#IBOutlet var sortedTitle : [UILabel]!
#IBOutlet weak var cellFinishButton : UITableViewCell!
var survey: LikertSurvey?
var points = [0, 0, 0, 0]
var results: [(Int, Int)] = []
override func viewDidLoad() {
super.viewDidLoad()
UserDefaults.standard.setValue(points, forKey: "points")
self.setResults()
self.initUI()
}
private func setResults() {
for (index, point) in points.enumerated() {
results.append((index, point))
}
results.sort { (result1, result2) -> Bool in
return result1.1 > result2.1
}
}
private func initUI() {
for i in 0 ..< results.count {
let title = survey!.questionCategories[results[i].0]
lblSortedScores[i].text = "\(title) = \(results[i].1) points"
sortedTitle[i].text = "\(title)"
}
let finishButtonTap = UITapGestureRecognizer(target: self, action: #selector(self.finishButtonTapped(_:)))
cellFinishButton.addGestureRecognizer(finishButtonTap)
self.navigationItem.hidesBackButton = false
}
#objc func finishButtonTapped(_ sender: UITapGestureRecognizer) {
self.survey?.completed = true
let alertController = UIAlertController(title: "Congratulations! You earned 100 XP from completing this quest!", message: "", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok",
style: .default) { action in
self.performSegue(withIdentifier: "unwindToSectionTableView", sender: self)
})
self.present(alertController, animated: true, completion: nil)
}
}
Try restructuring your code like so
var results: [(index: Int, points: Int)] = []
...
private func setResults() {
for (index, point) in points.enumerated() {
results.append((index, point))
}
results.sort{ $0.points > $1.points }
self.initUI()
}
Related
import UIKit
let alert = UIAlertController(title: "Warning",
message: "Your number is too big.",
preferredStyle: .alert)
class ViewController: UIViewController {
// Verbindungen zu Storyboard
#IBAction func rechnerEntry(_ sender: Any) {
}
#IBOutlet weak var resultLabel: UILabel!
#IBOutlet weak var buttons: UIButton!
#IBAction func clear(_ sender: Any) {
calculatorLabel.text = ""
number = 0
}
override func viewDidLoad() {
super.viewDidLoad()
buttons.backgroundColor = UIColor.gray
}
// Aufführung happyFuncs
func happyFunc(number: Int) -> Int {
var myNum = number
var sum = 0
while myNum > 0 {
let x = myNum % 10
sum += (x * x)
myNum /= 10
}
return sum
}
// happyCheckerFunc
func happyChecker(_ x: Int) -> Bool {
var alreadychecked: Set<Int> = Set()
var result = happyFunc(number: x)
while !alreadychecked.contains(result) {
if result == 1 {
resultLabel.text = "your number is a happy number"
return true
}
alreadychecked.insert(result)
result = happyFunc(number: result)
}
resultLabel.text = "your number is a unhappy number"
return false
}
// Eingabe Werte
var number = 0
var x = 0
#IBOutlet weak var calculatorLabel: UILabel!
var isTypingNumber = false
// Nummer getippt
#IBAction func numberTapped(_ sender: UIButton) {
let number = sender.currentTitle ?? (sender.titleLabel?.text ?? "0")
if isTypingNumber {
calculatorLabel.text = calculatorLabel.text! + number
} else {
calculatorLabel.text = number
isTypingNumber = true
}
}
// Überprüfung happy?
#IBAction func happycheck(_ sender: UIButton) {
number = Int(calculatorLabel.text!)!
x = number
if x > 9999999999999999 {
alert.addAction(UIAlertAction(title: "OK",
style: .default,
handler: { _ in
print("OK tap")
}))
present(alert, animated: true, completion: nil)
}
func happyFunc(number: Int) -> Int {
var myNum = number
var sum = 0
while myNum > 0 {
let x = myNum % 10
sum += (x * x)
myNum /= 10
}
return sum
}
func happyChecker(_ x: Int) -> Bool {
var alreadychecked: Set<Int> = Set()
var result = happyFunc(number: x)
while !alreadychecked.contains(result) {
if result == 1 {
resultLabel.text = "your number is a happy number"
return true
}
alreadychecked.insert(result)
result = happyFunc(number: result)
}
resultLabel.text = "your number is a unhappy number"
return false
}
happyChecker(x)
}
}
storyboard
Hey I wanted to ask you how I can implement the Swipe back Gesture in Swift. So I want that the user start at the Home View Controller and then he can tap on the "happy number Rechner"-Button and then the calculator View Controller appears. Like the same way with the transitions in the Settings App of iOS. And if you swipe left the Home View should appear again. Thank you!
You will need NavigationController, and ViewController
You can find and add this such like when you add a button.
After that click your Button, hold on the option button your keyboard, and pull together the first-and secondviewcontroller, now add you a navigationcontroller( you will see 2 screen, just delete a tableview controller screen) and don't forget to put a new way your arrow.(nav.controller first)
This is my simulator-
It shows - Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value in both the below scenarios:
i) - when I click on "card", it shows error as shown in the screenshot below:-
ii)when I click on "checkout" first it shows the following on the simulator
when I click on "confirm, , it shows error as shown in the screenshot below:-
This is my "CheckoutVC" -
import UIKit
import Stripe
import Firebase
class CheckoutVC: UIViewController {
var product = Cart()
lazy var quantitylabel = product.totalQuantity
var Pro = Product(imagename:#imageLiteral(resourceName: "blue"), price: 5,unit: 5)
#IBOutlet weak var selectCardView: UIView!
#IBOutlet weak var cardIcon: UIImageView!
#IBOutlet weak var cardEndingIn: UILabel!
#IBOutlet weak var selectBankView: UIView!
#IBOutlet weak var bankIcon: UIImageView!
#IBOutlet weak var bankEndingIn: UILabel!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
var currentSelectedPaymentType: PaymentType?
var paymentContext: STPPaymentContext!
override func viewDidLoad() {
super.viewDidLoad()
setupStripe()
setupTapGestures()
setupUi()
setCheckoutLabelDetails()
}
func setCheckoutLabelDetails() {
let pricelabel = Pro.price.formatToCurrencyString()
let processingFee = FeesCalculator.calculateFeesForCard(subtotal: Pro.price)
let formatprocessingfees = "Processing Fees: \(processingFee.formatToCurrencyString())"
let total = processingFee + Pro.price
let totallabel = "Total: \(total.formatToCurrencyString())"
}
func setupUi() {
let producttitle = Pro
let productprice = Pro.price
let qunatity = "\(Pro.unit) night accomodations"
let price = Pro.price.formatToCurrencyString()
}
func setupTapGestures() {
let selectCardTouch = UITapGestureRecognizer(target: self, action: #selector(selectCardTapped))
selectCardView.addGestureRecognizer(selectCardTouch)
let selectBankTouch = UITapGestureRecognizer(target: self, action: #selector(selectBankTapped))
selectBankView.addGestureRecognizer(selectBankTouch)
}
#objc func selectBankTapped() {
setBankPaymentView()
}
func setBankPaymentView() {
if currentSelectedPaymentType == .bank { return }
currentSelectedPaymentType = .bank
selectBankView.layer.borderColor = UIColor(named: AppColor.BorderBlue)?.cgColor
selectBankView.layer.borderWidth = 2
selectCardView.layer.borderColor = UIColor.lightGray.cgColor
selectCardView.layer.borderWidth = 1
bankIcon.tintColor = UIColor(named: AppColor.BorderBlue)
cardIcon.tintColor = UIColor.lightGray
}
func setupStripe() {
guard (UserManager.instance.user?.stripeId) != nil else { return }
let config = STPPaymentConfiguration.shared
paymentContext = STPPaymentContext(customerContext: Wallet.instance.customerContext,
configuration: config(),
theme: .default())
paymentContext.hostViewController = self
paymentContext.delegate = self
}
// MARK: Select Card
#objc func selectCardTapped() {
setCardPaymentView()
}
func setCardPaymentView() {
if currentSelectedPaymentType == .card { return }
currentSelectedPaymentType = .card
selectCardView.layer.borderColor = UIColor(named: AppColor.BorderBlue)?.cgColor
selectCardView.layer.borderWidth = 2
selectBankView.layer.borderColor = UIColor.lightGray.cgColor
selectBankView.layer.borderWidth = 1
cardIcon.tintColor = UIColor(named: AppColor.BorderBlue)
bankIcon.tintColor = UIColor.lightGray
}
#IBAction func changeCardClicked(_ sender: Any) {
self.paymentContext.pushPaymentOptionsViewController()
}
#IBAction func changeBankClicked(_ sender: Any) {
}
#IBAction func payBtnClicked(_ sender: Any) {
let total = Pro.price + FeesCalculator.calculateFeesForCard(subtotal: Pro.price)
let confirmPayment = UIAlertController(title: "Confirm Payment", message: "Confirm payment for \(total.formatToDecimalCurrencyString())", preferredStyle: .alert)
let confirmAction = UIAlertAction(title: "Confirm", style: .default) { (action) in
self.paymentContext.requestPayment()
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel)
confirmPayment.addAction(confirmAction)
confirmPayment.addAction(cancel)
present(confirmPayment, animated: true)
}
}
extension CheckoutVC: STPPaymentContextDelegate {
func paymentContextDidChange(_ paymentContext: STPPaymentContext) {
// Triggers when the content of the payment context changes, like when the user selects a new payment method or enters shipping information.
if let card = paymentContext.selectedPaymentOption {
cardEndingIn.text = card.label
} else {
cardEndingIn.text = "No Card Selected"
}
}
func paymentContext(_ paymentContext: STPPaymentContext, didFailToLoadWithError error: Error) {
simpleAlert(msg: "Sorry, but we are not able to load you credit cards at this time.")
}
func paymentContext(_ paymentContext: STPPaymentContext, didCreatePaymentResult paymentResult: STPPaymentResult, completion: #escaping STPPaymentStatusBlock) {
// Request Stripe payment intent, and return client secret.
guard let stripeId = UserManager.instance.user?.stripeId else { return }
let idempotency = UUID().uuidString.replacingOccurrences(of: "-", with: "")
let fees = FeesCalculator.calculateFeesForCard(subtotal: Pro.price)
let total = Pro.price + fees
let data: [String: Any] = [
"total": total,
"idempotency": idempotency,
"customer_id": stripeId
]
Functions.functions().httpsCallable("createPaymentIntent").call(data) { (result, error) in
if let error = error {
debugPrint(error)
self.simpleAlert(msg: "Sorry, but we are not able to complete your payment.")
return
}
guard let clientSecret = result?.data as? String else {
self.simpleAlert(msg: "Sorry, but we are not able to complete your payment.")
return
}
// Once the client secret is obtained, create paymentIntentParams
let paymentIntentParams = STPPaymentIntentParams(clientSecret: clientSecret)
paymentIntentParams.paymentMethodId = paymentResult.paymentMethod.stripeId
// Confirm the PaymentIntent
STPPaymentHandler.shared().confirmPayment(withParams: paymentIntentParams, authenticationContext: paymentContext) { (status, paymentIntent, error) in
switch status {
case .succeeded:
completion(.success, nil)
case .failed:
completion(.error, nil)
case .canceled:
completion(.userCancellation, nil)
}
}
}
}
func paymentContext(_ paymentContext: STPPaymentContext, didFinishWith status: STPPaymentStatus, error: Error?) {
// Take action based on return status: error, success, userCancellation
switch status {
case .success:
let successAlert = UIAlertController(title: "Payment Success!", message: "\nYou will receive an email with all the travel details soon! \n\n Bon Voyage!", preferredStyle: .alert)
let ok = UIAlertAction(title: "Ok", style: .default) { (action) in
self.navigationController?.popToRootViewController(animated: true)
}
successAlert.addAction(ok)
present(successAlert, animated: true)
case .error:
simpleAlert(msg: "Sorry, something went wrong during checkout. You were not charged and can try again.")
case .userCancellation:
return
}
}
}
enum PaymentType {
case card
case bank
}
what am I doing wrong ?
When the back button is pressed in my application, a delegate is called. All functions properly, however there is a large delay between the transition of the view. This gives the user a feeling that the app is crashed or isn't functioning properly.
The delegate methods that are triggered and causing the delay are shown here.
func setValues(obj: overviewProps){
overview = obj
print("Values Set")
surveyToEdit.overview = obj
updateSurveyObj()
}
func setArray(obj: [areaProps]) {
areas = obj
print("Set Array Sucessfully")
print(areas.count)
surveyToEdit.areas = obj
updateSurveyObj()
}
func saveSurveys(x : addedSurveys){
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(x, toFile: addedSurveys.ArchiveURL.path)
if isSuccessfulSave {
os_log("Surveys Saved", log: OSLog.default, type: .debug)
} else {
os_log("Failed to Save", log: OSLog.default, type: .error)
}
}
func updateSurveyObj(){
//this must be the issue
surveyToEdit.name = surveyToEdit.overview?.name ?? surveyToEdit.name
surveyToEdit.areas! = areas
surveyToEdit.overview! = overview
surveyListSurveys.surveys[surveyIndex] = surveyToEdit
saveSurveys(x: surveyListSurveys)
delegate?.saveInfo(updatedArray: surveyListSurveys)
print("the name is : \(surveyToEdit.overview!.name)")
}
When connected to the debugger, the device is showing a high memory usage and high cpu usage during this delay.
Here is the entire view controller for the project overview:
import UIKit
import os.log
class projectOverview: UIViewController, overviewDelegate, AreaDelegate {
var surveyToEdit = survey(areas: nil, settings: nil, overview: nil, name: "New Survey")
let IMG = UIImage(named: "noImage.png")
var areas = [areaProps(x: "New Area", y: "", z: "", a: "", b: "", p1: nil, p2: nil, p3: nil), areaProps(x: "New Area", y: "", z: "", a: "", b: "", p1: nil, p2: nil, p3: nil)]
var settings = companySettings(manager: "")
var overview = overviewProps(x: "", y: "", a: "", b: "", c: "", d: "", e: "", f: "", st: "", ct: "", stt: "")
var projectTitle: String = ""
let areaView = areaDetails()
let surveyHomeScreen = surveyList()
var surveyIndex = 0
var surveyListSurveys = addedSurveys(survey: [survey]())
var delegate:projectDelegate?
// need this to eventually pass back the data in the the survey object
func saveSurveys(x : addedSurveys){
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(x, toFile: addedSurveys.ArchiveURL.path)
if isSuccessfulSave {
os_log("Surveys Saved", log: OSLog.default, type: .debug)
} else {
os_log("Failed to Save", log: OSLog.default, type: .error)
}
}
func setProjDetails(){
print("gay")
if surveyToEdit.areas != nil{
areas = surveyToEdit.areas!
print("There is area")
}
if surveyToEdit.overview != nil{
overview = surveyToEdit.overview!
print("there is overview")
}
}
func updateSurveyObj(){
//this must be the issue
surveyToEdit.name = surveyToEdit.overview?.name ?? surveyToEdit.name
surveyToEdit.areas! = areas
surveyToEdit.overview! = overview
surveyListSurveys.surveys[surveyIndex] = surveyToEdit
saveSurveys(x: surveyListSurveys)
delegate?.saveInfo(updatedArray: surveyListSurveys)
print("the name is : \(surveyToEdit.overview!.name)")
}
let overviewController = addOverview()
override func viewDidLoad() {
super.viewDidLoad()
//areas = surveyToEdit.areas!
//overview = surveyToEdit.overview!
// Do any additional setup after loading the view.
//overviewController.delegate = self
//areaView.delegate = self
}
// MARK : - Actions
#IBAction func showPDF(_ sender: Any) {
performSegue(withIdentifier: "goToShare", sender: self)
print(overview.name)
}
#IBAction func editAreas(_ sender: Any) {
performSegue(withIdentifier: "goToServiceArea", sender: self)
}
#IBAction func editOverView(_ sender: Any) {
performSegue(withIdentifier: "goToMainDetails", sender: self)
}
func setValues(obj: overviewProps){
overview = obj
print("Values Set")
surveyToEdit.overview = obj
updateSurveyObj()
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToMainDetails"{
let vc = segue.destination as! addOverview
vc.overview = overview
vc.delegate = self
} else if segue.identifier == "goToServiceArea"{ // this is the segue
let vc = segue.destination as! areaDetails
vc.areaArray = self.areas
vc.delegate = self
print(" \(areas.count) Areas in Array ") // the array contains only 1 object
} else {
let vc = segue.destination as! shareReport
vc.surveyToDisplay = surveyToEdit
}
}
override func willMove(toParent parent: UIViewController?) {
super.willMove(toParent:parent)
if parent == nil {
updateSurveyObj()
}
}
func setArray(obj: [areaProps]) {
areas = obj
print("Set Array Sucessfully")
print(areas.count)
surveyToEdit.areas = obj
updateSurveyObj()
}
#IBOutlet var floorPlanIMG: UIImageView!
and here is the view that the back button is being pressed on:
import UIKit
class addOverview: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
var overview = overviewProps(x: "", y: "", a: "", b: "", c: "", d: "", e: "", f: "", st: "", ct: "", stt: "")
// MARK: - Init all UIVariables
let buildingTypes = ["Industrial", "School", "Office", "Multi-Tenant", "Church", "Manufacturing", "Misc"]
let cleaningFreqs = ["1/Week", "2/Week", "3/Week", "4/Week", "5/Week", "6/Week", "7/Week", "1/EOW", "1/Month"]
#IBOutlet var datePicker: UIDatePicker!
#IBOutlet var buildingName: UITextField!
#IBOutlet var street: UITextField!
#IBOutlet var city: UITextField!
#IBOutlet var State: UITextField!
#IBOutlet var contactName: UITextField!
#IBOutlet var phoneNumber: UITextField!
#IBOutlet var email: UITextField!
#IBOutlet var buildingPicker: UIPickerView!
#IBOutlet var cleaningFreqPicker: UIPickerView!
#IBOutlet var sqFt: UITextField!
var delegate:overviewDelegate?
// MARK: - Conform to PickerView
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView.tag == 2
{
return buildingTypes.count
}
else{
return cleaningFreqs.count
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if (pickerView.tag == 2)
{
return buildingTypes[row]
}else{
return cleaningFreqs[row]
}
}
override func viewDidLoad() {
super.viewDidLoad()
updateView()
buildingPicker.delegate = self
cleaningFreqPicker.delegate = self
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
if overview.building != ""{
buildingPicker.selectRow(buildingTypes.index(of: overview.building)!, inComponent: 0, animated: false)
cleaningFreqPicker.selectRow(cleaningFreqs.index(of: overview.freq)!, inComponent: 0, animated: false)
}
}
// set all the values of the object
func updateView(){
buildingName.text = overview.name
city.text = overview.city
contactName.text = overview.contact
email.text = overview.email
phoneNumber.text = overview.phone
sqFt.text = overview.sft
State.text = overview.state
street.text = overview.street
}
func setValues(){
overview.name = buildingName.text!
overview.city = city.text!
overview.contact = contactName.text!
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM-dd-yyyy"
overview.date = dateFormatter.string(from: datePicker.date)
overview.email = email.text!
overview.building = buildingTypes[buildingPicker.selectedRow(inComponent: 0)]
overview.freq = cleaningFreqs[cleaningFreqPicker.selectedRow(inComponent: 0)]
overview.phone = phoneNumber.text!
overview.sft = sqFt.text!
overview.state = State.text!
overview.street = street.text!
}
// MARK: - Navigation
override func willMove(toParent parent: UIViewController?) {
super.willMove(toParent:parent)
if parent == nil {
setValues()
print("Back Button Pressed")
delegate?.setValues(obj: overview)
}
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
}
I'm doing a calculator for school I finished everything but in the end the priority of calculation is not respected for example when I do : 2 + 2 * 2 it should be 6 but in my app it tells me 8, anyone have an idea how can I do that ? you will find in my code my model and my controller :
class viewControllerUtilities: UIViewController {
var stringNumbers: [String] = [String()]
var operators: [String] = ["+"]
var formerResult: Double?
var index = 0
var isExpressionCorrect: Bool{
if let stringNumber = stringNumbers.last{
if stringNumber.isEmpty{
if stringNumbers.count == 1 {
return false
}
return false
}
}
return true
}
var canAddOperator: Bool {
if let stringNumber = stringNumbers.last{
if stringNumber.isEmpty && formerResult == nil{
return false
}
}
return true
}
var canAddDecimal: Bool{
if let strings = stringNumbers.last{
if strings.contains(".") || strings.isEmpty{
return false
}
}
return true
}
func addDecimal(){
if let stringNumber = stringNumbers.last{
var stringNumberDecimal = stringNumber
stringNumberDecimal += "."
stringNumbers[stringNumbers.count-1] = stringNumberDecimal
}
}
func calculateTotal() -> Double{
var total : Double = 0
for (i, stringNumber) in stringNumbers.enumerated(){
if let number = Double(stringNumber){
switch operators[i]{
case "+":
total += number
case "-":
total -= number
case "x":
total *= number
case "/":
total /= number
default:
break
}
}
}
formerResult = total
clear()
return total
}
func clear(){
stringNumbers = [String()]
operators = ["+"]
index = 0
}
func allClear(){
clear()
formerResult = nil
}
func sendOperand(operand: String, number: String) {
operators.append(operand)
stringNumbers.append(number)
}
func addNewNumber(_ newNumber: Int){
if let stringNumber = stringNumbers.last{
var stringNumberMutable = stringNumber
stringNumberMutable += "\(newNumber)"
stringNumbers[stringNumbers.count-1] = stringNumberMutable
}
}
func roundResult(_ result: Double?){
if roundEvaluation(result!){
let rounded = Int(result!)
stringNumbers = ["\(rounded)"]
formerResult = nil
}
}
func roundEvaluation(_ result: Double) -> Bool{
if result.truncatingRemainder(dividingBy: 1) == 0{
return true
}
return false
}
}
and my controller :
class ViewController: UIViewController {
// MARK: - Properties
var CountOnMeU = viewControllerUtilities()
// MARK: - Outlets
#IBOutlet weak var textView: UITextView!
#IBOutlet var numberButtons : [UIButton]!
#IBOutlet var operators: [UIButton]!
#IBOutlet weak var point: UIButton!
// MARK: - Action
#IBAction func tappedNumberButton(_ sender: UIButton) {
for (i, numberButton) in numberButtons.enumerated() where sender == numberButton{
CountOnMeU.addNewNumber(i)
updateDisplay()
}
}
#IBAction func tappedPointButton(_ sender: Any){
if CountOnMeU.canAddDecimal{
CountOnMeU.addDecimal()
updateDisplay()
} else {
showAlert(message: "Vous ne pouvez pas mettre 2 points")
}
}
#IBAction func equal() {
if !CountOnMeU.isExpressionCorrect{
showAlert(message: "opération invalide")
} else {
let total = CountOnMeU.calculateTotal()
textView.text! += "\n =\(total)"
}
}
#IBAction func operandButtonTapped(_ sender: UIButton){
performOperation(operand: (sender.titleLabel?.text!)!)
}
#IBAction func allClear(_ sender: UIButton) {
CountOnMeU.allClear()
textView.text = "0"
}
// MARK: - Methods
func addNewNumber(message: String){
let alertVC = UIAlertController(title: "Erreur", message: message, preferredStyle: .alert)
alertVC.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alertVC, animated: true, completion: nil)
}
func updateDisplay() {
var text = ""
let stack = CountOnMeU.stringNumbers.enumerated()
for (i, stringNumber) in stack {
// Add operator
if i > 0 {
text += CountOnMeU.operators[i]
}
// Add number
text += stringNumber
}
textView.text = text
}
func showAlert(message: String){
let AlertVC = UIAlertController(title: "Erreur", message: message, preferredStyle: .alert)
AlertVC.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(AlertVC,animated: true, completion: nil)
}
func performOperation(operand: String){
if CountOnMeU.canAddOperator{
let result = CountOnMeU.formerResult
if result != nil {
CountOnMeU.roundResult(result)
updateDisplayForResultReuse(operand: operand)
} else {
CountOnMeU.sendOperand(operand: operand, number: "")
updateDisplay()}
} else {
self.showAlert(message: "Expression incorrecte")
}
}
func updateDisplayForResultReuse(operand: String){
updateDisplay()
CountOnMeU.sendOperand(operand: operand, number: "")
updateDisplay()
}
}
I am making a budgeting app for the purposes of learning and I have a few questions about storing and fetching entities in CoreData.
I have two entities "Budget" and "Expense".
Every Budget has its own Expenses. As an example I can have an 'Entertainment' budget and it can have expenses such as 'Bowling' and 'Movies' etc.
I can create a Budget and save it. And then add expenses to it.
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let expense = Expense(context: context)
.
. // Filling out the expense here
.
budget?.addToExpense(expense)
(UIApplication.shared.delegate as! AppDelegate).saveContext()
I then retrieve the collection of Expenses and display the store name in a TableView
// Inside cellForRowAt
let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
let myArray = Array((budget?.expense)!)
cell.textLabel?.text = (myArray[indexPath.row] as! Expense).store
return cell
So far so good. My issue is that when I store an expense it is stored in a Set. Which means the order is random when I retrieve that set and typecast it into an Array.
What I want is to store the Expenses and retrieve them in such a way that I can display the expenses in a FIFO order in the TableView. In other words the first expense I add in the budget should be the first element in the table view and so on and so forth.
There could be several ways to achieve that. The most straightforward would be to use Ordered relation for expense.
To do that,
Open expense relationship properties in DataModel editor.
Check Ordered option
Then budget.expense will be not Set, but OrderedSet, and you won't need to convert it to Array, but access it directly by index.
VIEWCONTROLLER 1:
=====================>
import CoreData
class ViewController: UIViewController {
#IBOutlet weak var txt_user: UITextField!
#IBOutlet weak var txt_password: UITextField!
var result = NSArray()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
txt_password.isSecureTextEntry = true
}
#IBAction func login_action(_ sender: Any)
{
if(txt_user.text == "" || txt_password.text == "")
{
let alert = UIAlertController(title: "info", message: "fields are empty", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(ok)
self.present(alert, animated: true, completion: nil)
}
else
{
self.CheckForUserNameAndPasswordMatch(empName: txt_user.text! , empPwd: txt_password.text!)
}
}
func CheckForUserNameAndPasswordMatch(empName:String,empPwd:String)
{
let app = UIApplication.shared.delegate as! AppDelegate
let context = app.persistentContainer.viewContext
let fetchdata = NSFetchRequest<NSManagedObject>(entityName: "Employee")
let predicate = NSPredicate(format: "empName = %#",empName)
fetchdata.predicate = predicate
do
{
self.result = try context.fetch(fetchdata as! NSFetchRequest<NSFetchRequestResult>)as NSArray
if result.count>0
{
let objcetEntity = result.firstObject as! Employee
if objcetEntity.empName == empName && objcetEntity.empPwd == empPwd
{
print("Login Successfully")
// Entered Username & password matched
}
else
{
print("Wrong password/username")
//Wrong password/username
}
}
}
catch let error as NSError
{
print("error",error.localizedDescription)
}
}
#IBAction func unwindToVC1(sender:UIStoryboardSegue)
{
if sender.source is ViewController2
{
let secvc = sender.source as! ViewController2
txt_password.text = secvc.str1! as String
}
}
VIEWCONTROLLER 2:
=====================>
class ViewController2: UIViewController ,UITextFieldDelegate{
#IBOutlet weak var txt_name: UITextField!
#IBOutlet weak var txt_mail: UITextField!
#IBOutlet weak var txt_pwd: UITextField!
#IBOutlet weak var txt_cpwd: UITextField!
#IBOutlet weak var txt_phone: UITextField!
#IBOutlet weak var err: UILabel!
var str1:NSString!
var str2:NSString!
//var update:NSManagedObject!
override func viewDidLoad() {
super.viewDidLoad()
/*if(update != nil)
{
txt_name.text = update.value(forKey: "empName") as? String
txt_mail.text = update.value(forKey: "empMail") as? String
txt_pwd.text = update.value(forKey: "empPwd") as? String
txt_cpwd.text = update.value(forKey: "empCpwd") as? String
txt_phone.text = update.value(forKey: "empPhone") as? String
}*/
txt_pwd.isSecureTextEntry = true
txt_cpwd.isSecureTextEntry = true
}
override func viewWillAppear(_ animated: Bool)
{
txt_name.becomeFirstResponder()
}
#IBAction func regis_clicked(_ sender: Any)
{
if(txt_name.text == "" || txt_mail.text == "" || txt_pwd.text == "" || txt_cpwd.text == "" || txt_phone.text == "" )
{
let alert = UIAlertController(title: "information", message: "fields are empty", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler:
{
(actionsheet) in
if(self.txt_name.text == "")
{
self.txt_name.becomeFirstResponder()
}
if(self.txt_mail.text == "")
{
self.txt_mail.becomeFirstResponder()
}
if(self.txt_pwd.text == "")
{
self.txt_pwd.becomeFirstResponder()
}
if(self.txt_cpwd.text == "")
{
self.txt_cpwd.becomeFirstResponder()
}
if(self.txt_phone.text == "")
{
self.txt_phone.becomeFirstResponder()
}
})
let cancel = UIAlertAction(title: "cancel", style: .default, handler: nil)
alert.addAction(ok)
alert.addAction(cancel)
self.present(alert, animated: true, completion: nil)
}
else if(txt_pwd.text != txt_cpwd.text)
{
let alert1 = UIAlertController(title: "information", message: "password mismatched", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler:nil)
let cancel = UIAlertAction(title: "cancel", style: .default, handler: nil)
alert1.addAction(ok)
alert1.addAction(cancel)
self.present(alert1, animated: true, completion: nil)
}
else
{
let app = UIApplication.shared.delegate as! AppDelegate
let context = app.persistentContainer.viewContext
let newuser = NSEntityDescription.insertNewObject(forEntityName: "Employee", into: context)
newuser.setValue(txt_name.text, forKey: "empName")
newuser.setValue(txt_mail.text, forKey: "empMail")
newuser.setValue(txt_pwd.text, forKey: "empPwd")
newuser.setValue(txt_cpwd.text, forKey: "empCpwd")
newuser.setValue(txt_phone.text, forKey: "empPhone")
do
{
try context.save()
}
catch let error as NSError
{
print("error",error.localizedDescription)
}
}
// self.navigationController?.popViewController(animated: true)
performSegue(withIdentifier: "unwind", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if let newlabel = txt_pwd.text
{
str1 = newlabel as NSString
}
}