I have a tableview that displays a sourceArray with a Name and Category properties. I want to filter the Category property of the sourceArray based on the users input from a UIAlertController but getting the error "Instance method 'contains' requires that 'UITextField' conform to 'StringProtocol'". Any help is greatly appreciated.
var sourceArray = [(Name: String, Category: String, Picture1: UIImage, Picture2: UIImage, Picture3: UIImage, Description: String)]()
#IBAction func filterButton(_ sender: UIBarButtonItem) {
var textField = UITextField()
let alert = UIAlertController(title: "Category", message: nil, preferredStyle: .alert)
let action = UIAlertAction(title: "Filter", style: .default) { (action) in
print(textField)
let filtered = sourceArray.filter({$0.Category.contains(textField)})
self.filteredArray = filteredArray.isEmpty ? sourceArray : filtered
self.tableview.reloadData()
}
alert.addTextField { (alertTextField) in
alertTextField.placeholder = "Biceps, Chest, Shoulders, etc."
textField = alertTextField
}
alert.addAction(action)
present(alert, animated: true, completion: nil)
}
This issue I was having is that textField was not being recognized as a String. So I added a constant text as a String and assigned the textField.text to it like so.
#IBAction func filterButton(_ sender: UIBarButtonItem) {
var textField = UITextField()
let alert = UIAlertController(title: "Category", message: nil, preferredStyle: .alert)
let action = UIAlertAction(title: "Filter", style: .default) { (action) in
let text: String = textField.text!
let filtered = self.sourceArray.filter({$0.Category.contains(text)})
self.filteredArray = self.filteredArray.isEmpty ? self.sourceArray : filtered
self.tableview.reloadData()
}
alert.addTextField { (alertTextField) in
alertTextField.placeholder = "Biceps, Chest, Shoulders, etc."
textField = alertTextField
}
alert.addAction(action)
present(alert, animated: true, completion: nil)
}
Related
I have an app that takes user inputs in an alertController, and then this values will be stored in CoreData which is then displayed in a tableview. I concatenated all the strings to gather with a comma as separator to make it easier for me to export a csv. However, when I print out the CoreData entity, I get an array that is quite complicated. The array looks like this:
[ (entity: AlarmItems; id: 0xc2bccd37cb753acb ; data: {
alarmAttributes = "Example Name, 24/11/2019, 1500, True, NIL";
}), (entity: AlarmItems; id: 0xc2bccd37cb653acb ; data: {
alarmAttributes = "Example , 12/12/2019, 24/11/2019, True, NIL";
})]
I would like to pull out just that parts after alarmAttributes to be exported into a CSV for further use.
I looked at NSEntityMapping but that did not help me. I'm quite stuck right now. I do not know how to approach the problem. Is my approach even correct in the first place? Is it even possible to export a csv using a an array that I create? The idea is to have the csv be stored in the iOS Device which can then be emailed elsewhere.
My ViewController:
class ViewController: UITableViewController {
var alarmItems: [NSManagedObject] = []
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "AlarmItems")
do {
alarmItems = try managedContext.fetch(fetchRequest)
} catch let err as NSError {
print("Failed to fetch items", err)
}
}
#objc func addAlarmItem(_ sender: AnyObject) {
print("this works")
let alertController = UIAlertController(title: "Add New Item", message: "Please fill in the blanks", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) { [unowned self] action in
//combined string of attributes
let myStrings: [String] = alertController.textFields!.compactMap { $0.text }
let myText = myStrings.joined(separator: ", ")
self.save(myText)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive, handler: nil)
alertController.addTextField { (textField) in
textField.placeholder = "Enter Name of Engineer"
}
alertController.addTextField { (textField) in
textField.placeholder = "Enter Date of Alarm in DD/MM/YYYY"
}
alertController.addTextField { (textField) in
textField.placeholder = "Enter Time of Alarm in 24h (eg: 2300)"
}
alertController.addTextField { (textField) in
textField.placeholder = "Please indicate True/False (type True or False)"
}
alertController.addTextField { (textField) in
textField.placeholder = "Insert comments (if any), or NIL"
}
alertController.addAction(saveAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
func save(_ itemName: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "AlarmItems", in: managedContext)!
let item = NSManagedObject(entity: entity, insertInto: managedContext)
item.setValue(itemName, forKey: "alarmAttributes")
do {
try managedContext.save()
alarmItems.append(item)
} catch let err as NSError {
print("Failed to save an item", err)
}
}
#objc func exportCSV(_ sender: AnyObject) {
//will work on exporting csv in the future
return
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return alarmItems.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let alarmItem = alarmItems[indexPath.row]
cell.textLabel?.text = alarmItem.value(forKeyPath: "alarmAttributes") as? String
return cell
}
}
I want my app to show data from mysql database in collectionview so i write down the mysql connection code in viewDidload() and make it in array format everything work fine except for showing data in collectionview Here is my code
var subjectlist = ""
var imgurllist = ""
var subjectarray = [String]()
var imgurllistarray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
collectionview.dataSource = self
collectionview.delegate = self
let request = NSMutableURLRequest(url: NSURL(string: [Point to file on my server])! as URL)
let urlsession = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
DispatchQueue.main.async {
do {
if let dataunwarp = data {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
if let subjectnotfound = parseJSON["subjectnotfound"]{
let alert = UIAlertController(title: "เกิดข้อผิดพลาด", message: "ไม่พบ subject ในเซิฟเวอร์ กรุณาลองใหม่อีกครั้ง", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "ปิด", style: .default, handler: { (alert: UIAlertAction!) in
self.navigationController?.popViewController(animated: true)
}))
self.dismiss(animated: false, completion: { () in self.present(alert, animated: true, completion: nil) })
} else {
self.subjectlist = parseJSON["subjectlist"] as! String
self.imgurllist = parseJSON["imgurllist"] as! String
self.subjectarray = Array(self.subjectlist.components(separatedBy: ","))
print("subjectarray=\(self.subjectarray)")
print(self.subjectarray[0])
//self.imgurllistarray = Array(self.imgurllist.components(separatedBy: ","))
}
} else {
let alert = UIAlertController(title: "เกิดข้อผิดพลาด", message: "เกิดข้อผิดพลาดจากเซิฟเวอร์", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "ปิด", style: .default, handler: { (alert: UIAlertAction!) in
self.navigationController?.popViewController(animated: true)
}))
self.dismiss(animated: false, completion: { () in self.present(alert, animated: true, completion: nil) })
}
} else {
let alert = UIAlertController(title: "เกิดข้อผิดพลาด", message: "เกิดข้อผิดพลาดจากเซิฟเวอร์", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "ปิด", style: .default, handler: { (alert: UIAlertAction!) in
self.navigationController?.popViewController(animated: true)
}))
self.dismiss(animated: false, completion: { () in self.present(alert, animated: true, completion: nil) })
}
} catch {
let alert = UIAlertController(title: "เกิดข้อผิดพลาด", message: "ไม่สามารถติดต่อกับเซิฟเวอร์ได้ กรุณาตรวจสอบการเชื่อมต่ออินเตอร์เน็ตเเละลองใหม่อีกครั้ง", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "ปิด", style: .default, handler: { (alert: UIAlertAction!) in
self.navigationController?.popViewController(animated: true)
}))
self.dismiss(animated: false, completion: { () in self.present(alert, animated: true, completion: nil) })
}
}})
urlsession.resume()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return subject.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! collectionviewcell
let subjectimgurl = NSMutableURLRequest(url: NSURL(string: "https://psmapps.com/psmatstamp/images/atstamp.png")! as URL)
let imgsession = URLSession.shared.dataTask(with: subjectimgurl as URLRequest, completionHandler: {data, response, error -> Void in
if let e = error {
print("Error downloading picture: \(e)")
} else {
// No errors found.
// It would be weird if we didn't have a response, so check for that too.
if let res = response as? HTTPURLResponse {
if let imageData = data {
// Finally convert that Data into an image and do what you wish with it.
let subjectimg = UIImage(data: imageData)
DispatchQueue.main.async {
cell.subjectimage.image = subjectimg
}
} else {
print("Couldn't get image: Image is nil")
}
} else {
print("Couldn't get response code for some reason")
}
}
})
imgsession.resume()
cell.subjectlabel.text = subjectarray[indexPath.item]
print(self.subjectarray[indexPath.item])
cell.layer.borderColor = UIColor.lightGray.cgColor
cell.layer.borderWidth = 0.5
return cell
}
An error occurred in this line before this view presented
cell.subjectlabel.text = subjectarray[indexPath.item]
with error message: "Index out of range" but when i uncomment the line that error occurred and print out the data from subjectarray, i can see my data with array type
How can i fix this problem?
Inside numberOfItemsInSection
return subject.count
Then inside cellForItemAt you use
subjectarray[indexPath.item]
Is there a guarantee that both will be same size at a time , also use SDWebImage to load images
Also after you get the data reload
self.subjectarray = Array(self.subjectlist.components(separatedBy: ","))
self.collectionView.reloadData()
plus spreading UIAlertController everywhere isn't a good way for compact code , consider making an extension / function and call it with the appropriate message
I have this program which takes values from firestore and puts them in an array. I have confirmed that these arrays have data inside of them by using test print functions. When I declare 2 global arrays ( gloabalGPA and globalSAT) and pass the value of the gpaColleges and the satColleges into them through a function everything works. I placed test print functions inside of the functions (the swithcSATArray and the switchGPAArray). However when I attempt to print these global variables again in a different function the print function prints out an empty array. like so: ( [] )
import UIKit
import FirebaseAuth
import FirebaseDatabase
import Firebase
import FirebaseFirestore
class ScoresViewController: UIViewController {
var docRef: DocumentReference!
let defaultStore = Firestore.firestore()
var globalGPA = [String]()
var globalSAT = [String]()
override func viewDidLoad() {
super.viewDidLoad()
let userID: String = (Auth.auth().currentUser?.uid)!
docRef = Firestore.firestore().document("Users/\(userID)")
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var GpaScore: UITextField!
#IBOutlet weak var SATscore: UITextField!
#IBOutlet weak var ACT_Score: UITextField!
#IBAction func SubmitTapped(_ sender: Any) {
print("Submit Tapped")
let Sattext = SATscore.text
let Acttext = ACT_Score.text
let Gpatext = GpaScore.text
let gpaScore = Gpatext
let SatScore2 = Sattext
let Acttext2 = Acttext
let CombinedScores = Sattext! + Acttext!
if GpaScore.text == "" {
self.createAlert(titleText: "Error", messageText: "No Weighted GPA Entered")
}
else if CombinedScores == "" {
self.createAlert(titleText: "Error", messageText: "No SAT nor ACT Score Entered")
}
else{
let dataToSave: [String: Any] = ["GPA": gpaScore!, "SAT Score": SatScore2!, "ACT Score": Acttext2!]
docRef.setData(dataToSave) { (error) in
if let error = error {
print("error in sending data to fireStore: \(error.localizedDescription)")
}else {
print("Data was succesfully saved to FireStore")
}
}
self.presentLoggedInScreen()
sendToFireStore(gpa: gpaScore!, sat: SatScore2!)
self.addArrays()
}
}
func createAlert (titleText : String , messageText: String) {
let alert = UIAlertController (title: titleText, message: messageText, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Dissmis", style: .default, handler: { (action) in alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
func presentLoggedInScreen() {
let storyboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let HomeVC:HomeVC = storyboard.instantiateViewController(withIdentifier: "HomeVC") as! HomeVC
self.present(HomeVC, animated: true, completion: nil)
}
func sendToFireStore(gpa: String, sat: String) {
let db = Firestore.firestore()
var gpaColleges = [String]()
let gpaRef = db.collection("Colleges")
let query1 = gpaRef
.whereField("Average GPA", isLessThanOrEqualTo: gpa)
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
gpaColleges.append(document.documentID)
}
self.switchGPAArray(gpa: gpaColleges)
}
}
var satColleges = [String]()
let satRef = db.collection("Colleges")
let query2 = satRef
.whereField("Average SAT Score", isLessThanOrEqualTo: sat)
.getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
satColleges.append(document.documentID)
}
self.swithcSATArray(sat: satColleges)
}
}
}
func swithcSATArray(sat: Array<Any>) {
self.globalSAT = sat as! [String]
print("Printing inside of SAT function \(self.globalSAT)")
}
func switchGPAArray(gpa: Array<Any>) {
self.globalGPA = gpa as! [String]
print("Printing inside of GPA funtion \(self.globalGPA)")
}
func addArrays() {
print("INSIDE OF ADD ARRAYS SAT \(self.globalSAT)")
print("INSIDE OF ADD ARRAYS GPA \(self.globalSAT)")
}
}
Any help would be greatly appreciated.
First of all there is lot of code but little information about your problem. We don't even know which function you call first and what is the second one that prints empty?
I can edit this answer after you provide more details. But as far as I see, you have closures and the compiler won't wait closure to complete, to run the next line. If this is the problem you can use threads and run your code in main thread so you can be sure it is completed. Or you can use delegate pattern to be notified when it's complete.
Or just do this:
let dataToSave: [String: Any] = ["GPA": gpaScore!, "SAT Score": SatScore2!, "ACT Score": Acttext2!]
docRef.setData(dataToSave) { (error) in
if let error = error {
print("error in sending data to fireStore: \(error.localizedDescription)")
}else {
self.presentLoggedInScreen()
sendToFireStore(gpa: gpaScore!, sat: SatScore2!)
self.addArrays()
print("Data was succesfully saved to FireStore")
}
}
If no one above works, provide more details about your issue! :)
I am creating individual members in my app, and everything works well. I validate user input, store it in a local array, and then pass the data on to Firebase when I tap 'next'. The app takes me from Step 2 to Step 3. So far so good.
This is what Step 2 looks like if I load the app from scratch: Step 2 Existing Users. The users are pulled from Firebase, and everything is correct.
If I add a new user, everything updates fine. I tap the 'next' button, and Firebase updates with 3 users, all with correct data, and I'm taken to Step 3. All is good still.
But if I tap the 'back' button in the upper left corner of Step 3 (provided by my navigation controller), the app takes me back to Step 2 and now a duplicate entry of the new user shows up in my tableview. Somehow a duplicate user is appended to my array. This only shows up AFTER I click the 'back' button. It doesn't show up in Firebase, but I don't know where it's coming from. I've spent all day trying to figure this out. I'm sure it's a simple problem that I'm overlooking, but I could really use the community's help on this one.
I've looked at this but it didn't help me. I did some tests where I printed out users.count and found that on ViewDidLoad, the count was 0, but on the unwind segue, the count updated to 3 when I added a new user (this was correct, because there were 3 users). But then when I went to Step 3 and tapped the 'back' button to get back to Step 2, Step 2's ViewDidLoad showed a users.count of 4. I have no idea why. I'm completely stumped.
Here is my Step 2 View Controller code in its entirety:
class Step2VC: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var usersTableView: UITableView!
var users = [User]() // create variable called 'users' which is an array of type User (which is a class we created)
var firebaseUser: FIRUser!
var firebaseStorage: FIRStorage!
var ref: FIRDatabaseReference!
var cellStyleForEditing: UITableViewCellEditingStyle = .none
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "users"
usersTableView.dataSource = self
usersTableView.delegate = self
usersTableView.tableFooterView = UIView()
// --------
// Firebase
// --------
firebaseUser = FIRAuth.auth()?.currentUser
firebaseStorage = FIRStorage.storage()
ref = FIRDatabase.database().reference().child("users").child(firebaseUser.uid)
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "edit", style: .plain, target: self, action: #selector(editButtonTapped))
loadExistingUsers() // check to see if there are existing users, and if so, load them into tableview
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
usersTableView.reloadData()
}
// ----------
// Table View
// ----------
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! Step2Cell
cell.myLabel.text = users[indexPath.row].firstName
cell.userImage.image = users[indexPath.row].photo
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
deleteUserConfirmationAlert(tableViewIndexPath: indexPath)
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "EditUser", sender: users[indexPath.row])
}
// ----------
// Navigation
// ----------
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EditUser" {
let nextContoller = segue.destination as! Step2UsersVC
// 'sender' is retrieved from 'didSelectRow' function above
nextContoller.user = sender as? User
nextContoller.navBarTitle = "edit user"
} else if segue.identifier == "AddUser" {
let nextController = segue.destination as! Step2UsersVC
nextController.navBarTitle = "add user"
} else {
print("Segue Initiated:",segue.identifier!)
}
}
#IBAction func unwindToStep2VC(sender: UIStoryboardSegue) {
let sourceVC = sender.source as! Step2UsersVC
let updatedUser = sourceVC.user
if let selectedIndexPath = usersTableView.indexPathForSelectedRow {
// Update an existing user
users[selectedIndexPath.row] = updatedUser!
usersTableView.reloadData()
} else {
// Add a new user
let newIndexPath = IndexPath(row: users.count, section: 0)
users.append(updatedUser!)
usersTableView.insertRows(at: [newIndexPath], with: .automatic)
users.sort(by: {$0.birthday < $1.birthday})
usersTableView.reloadData()
}
}
#IBAction func nextButtonTapped(_ sender: UIButton) {
// check for at least two users
if users.count < 2 {
createAlert(alertTitle: "Users", alertMessage: "You have not created enough users. Please enter in at least two users.")
} else {
// check for at least one parent
if numberOfParents() < 1 {
createAlert(alertTitle: "Users", alertMessage: "You must have at least one parent. Please enter in a parent.")
} else {
confirmationAlert()
}
}
}
// ---------
// Functions
// ---------
// if users exist on Firebase, load them
func loadExistingUsers() {
ref.child("members").observe(.childAdded) { (snapshot: FIRDataSnapshot) in
if let dict = snapshot.value as? [String : Any] {
let userPhotoUrl = dict["profileImageUrl"] as! String
let userFirstName = dict["firstName"] as! String
let userBirthday = dict["birthday"] as! Int
let userPasscode = dict["passcode"] as! Int
let userGender = dict["gender"] as! String
let isUserChildOrParent = dict["childParent"] as! String
let storageRef = FIRStorage.storage().reference(forURL: userPhotoUrl)
storageRef.data(withMaxSize: 1 * 1024 * 1024, completion: { (data, error) in
let pic = UIImage(data: data!)
let user = User(profilePhoto: pic!,
userFirstName: userFirstName,
userBirthday: userBirthday,
userPasscode: userPasscode,
userGender: userGender,
isUserChildOrParent: isUserChildOrParent)
self.users.append(user)
self.users.sort(by: {$0.birthday < $1.birthday})
self.usersTableView.reloadData()
})
}
}
}
func saveUsersToFirebase() {
for user in users {
let storageRef = FIRStorage.storage().reference().child("users").child(firebaseUser.uid).child("members").child(user.firstName)
let profileImg = user.photo
let imageData = UIImageJPEGRepresentation(profileImg, 0.1) // compress photos
storageRef.put(imageData!, metadata: nil, completion: { (metadata, error) in
if error != nil {
return
}
// get Firebase image location and return the URL as a string
let profileImageUrl = (metadata?.downloadURL()?.absoluteString)!
// save user data to Firebase
self.ref?.child("members").child(user.firstName).setValue(["profileImageUrl" : profileImageUrl,
"firstName" : user.firstName,
"birthday" : user.birthday,
"passcode" : user.passcode,
"gender" : user.gender,
"childParent" : user.childParent])
})
}
}
func editButtonTapped() {
if cellStyleForEditing == .none {
cellStyleForEditing = .delete
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "done", style: .done, target: self, action: #selector(editButtonTapped))
} else {
cellStyleForEditing = .none
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "edit", style: .plain, target: self, action: #selector(editButtonTapped))
}
usersTableView.setEditing(cellStyleForEditing != .none, animated: true)
}
func deleteUserConfirmationAlert(tableViewIndexPath: IndexPath) {
// create alert for user to confirm user deletion
let alert = UIAlertController(title: "Delete User", message: "Are you sure you want to delete \(users[tableViewIndexPath.row].firstName)? This cannot be undone.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "okay", style: .default, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
// remove user from Firebase
self.ref.child("members").child(self.users[tableViewIndexPath.row].firstName).removeValue()
self.users.remove(at: tableViewIndexPath.row)
self.usersTableView.deleteRows(at: [tableViewIndexPath], with: .fade)
}))
alert.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
self.usersTableView.reloadData()
}))
present(alert, animated: true, completion: nil)
}
func numberOfParents() -> Int {
var parentCount = 0
for user in users {
if user.childParent == "parent" {
parentCount += 1
}
}
return parentCount
}
func createAlert(alertTitle: String, alertMessage: String) {
let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "okay", style: .cancel, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
}))
present(alert, animated: true, completion: nil)
}
func confirmationAlert() {
let alert = UIAlertController(title: "Users", message: "You have entered in \(users.count) users. Are you finished adding family members?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "continue", style: .default, handler: { (action) in
self.saveUsersToFirebase()
self.performSegue(withIdentifier: "GoToStep3", sender: self)
alert.dismiss(animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
}))
present(alert, animated: true, completion: nil)
}
}
I am trying to create an array on numbers and have the user save them on their device. However when the data is saved (by using NSUserDefaults method) it is converted to an [AnyObject] array. I need to convert it to an array of [Int]. Here is my current approach to this:
class ProgressViewController: UIViewController {
let kUserDefault = UserDefaults.standard
var chartData = [Int]()
override func viewWillAppear(_ animated: Bool) {
let weighting = UserDefaults.standard.array(forKey: "chartData")
footer1.text = "\((weighting))"
}
#IBAction func AddGraphComponent(_ sender: UIButton) {
var weighText:UITextField!
let alert = UIAlertController(title: "Enter new Weight!", message: "Please enter your Weight, followed by the date in which your weight was recorded", preferredStyle: UIAlertControllerStyle.alert)
alert.addTextField { (weighText) in
weighText.placeholder = "Weight"
weighText.keyboardType = UIKeyboardType.numberPad
}
alert.addTextField { (dateText) in
dateText.placeholder = "Date (MM/YY)"
}
let confirmAction = UIAlertAction(title: "Save", style: UIAlertActionStyle.default) { (_) in
let field = alert.textFields![0] as? UITextField
let weigh = alert.textFields![1] as? UITextField
if (field?.text)! == "" || (weigh?.text)! == "" {
let alert1 = UIAlertController(title: "Error!", message: "Please fill in BOTH fields", preferredStyle: UIAlertControllerStyle.alert)
alert1.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
self.present(alert1, animated: true, completion: nil)
}else {
print((field?.text)!,(weigh?.text)!)
let dataInt:Int = Int((field?.text!)!)!
self.chartData.append(dataInt)
self.chartLegend.append((weigh?.text)!)
self.kUserDefault.set([self.chartData], forKey: "chartData") //as? [Int]
self.kUserDefault.set([self.chartLegend], forKey: "chartLegend")
self.kUserDefault.synchronize()
}
}
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil))
alert.addAction(confirmAction)
self.present(alert, animated: true, completion: nil)
}
I've tried let weightData: Int = weighting as [Int] but it crashes saying fatal error
I've tried print("\(weighting?[0] as! Int)") but it crashes saying Could not cast value of type '__NSCFArray' (0x109f6ae88) to 'NSNumber' (0x108df0300).
when I try
let weighting = UserDefaults.standard.array(forKey: "chartData") as! [Int]
print("\((weighting[0]))")
my app crashes saying Could not cast value of type '__NSCFArray' (0x108190e88) to 'NSNumber' (0x107016300)
is there any way to convert a saved array from [AnyObject] to [String] or [Int] ?
In the line
self.kUserDefault.set([self.chartData], forKey: "chartData")
you are saving an object of type [[Int]] since chartData is already an array.
Remove the brackets
self.kUserDefault.set(self.chartData, forKey: "chartData")