How to add elements to a realm database - swift

I am working on a simple app that catalogues information. Right now I am just trying to collect information and then add it to a realm database. Unfortunately I cannot figure it out and no matter what method I try (based on tutorials and the Realm website) I get the error "Use of unresolved identifier 'realm'.
This is the code based on the command button executing the command.
#IBAction func Submit(_ sender: Any) {
let myList = WineList()
myList.vinyard = Vinyard.text
myList.type = typeField.text
myList.name = Name.text
myList.grape = Grape.text
myList.year = Year.text
myList.price = Price.text
myList.rating = rateField.text
myList.purchased = purch
myList.notes = Notes.text
//from realm website example
try! realm.write{
realm.add(myList)
}
//from tutorials
//realm.beginWrite()
//realm.add(myList)
//try realm.commitWrite()
}
Can anyone please advise me on what I am doing wrong? I will post all of my code below.
import UIKit
import RealmSwift
class RankViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
var purch = ""
#IBOutlet weak var typeField : UITextField!
#IBOutlet weak var rateField : UITextField!
#IBOutlet weak var Vinyard: UITextField!
#IBOutlet weak var Name: UITextField!
#IBOutlet weak var Grape: UITextField!
#IBOutlet weak var Year: UITextField!
#IBOutlet weak var Price: UITextField!
#IBOutlet weak var Notes: UITextField!
#IBAction func Purchased(_ sender: UISwitch) {
if (sender.isOn == true){
purch = "Yes"
}
else {
purch = "No"
}
}
let wineTypes = ["Red","White","Rose","Sparkling","Ice - Red","Ice - White", "Port","Fruit","Other"]
let wineRate = ["Hurray", "Meh", "Boo"]
var typeView = UIPickerView()
var rateView = UIPickerView()
override func viewDidLoad() {
super.viewDidLoad()
let realm = try! Realm()
print (Realm.Configuration.defaultConfiguration.fileURL)
typeView.delegate = self
typeView.dataSource = self
rateView.delegate = self
rateView.dataSource = self
Vinyard.delegate = self
Name.delegate = self
Grape.delegate = self
Year.delegate = self
Price.delegate = self
Notes.delegate = self
typeField.inputView = typeView
rateField.inputView = rateView
}
public func numberOfComponents(in pickerView: UIPickerView) -> Int {
if pickerView == typeView {
// Returns for typeView
return 1
}
else if pickerView == rateView {
// Returns for rateView
return 1
}
return 1
}
public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if pickerView == typeView {
// Returns for typeView
return wineTypes.count
}
else if pickerView == rateView {
// Returns for rateView
return wineRate.count
}
return wineRate.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if pickerView == typeView {
// Returns for typeView
return wineTypes[row]
}
else if pickerView == rateView {
// Returns for rateView
return wineRate[row]
}
return wineRate[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if pickerView == typeView {
// Do stuff for typeView
typeField.text = wineTypes[row]
typeField.resignFirstResponder()
}
else if pickerView == rateView {
// Do stuff for rateView
typeField.text = wineRate[row]
typeField.resignFirstResponder()
}
}
#IBAction func Submit(_ sender: Any) {
let myList = WineList()
myList.vinyard = Vinyard.text
myList.type = typeField.text
myList.name = Name.text
myList.grape = Grape.text
myList.year = Year.text
myList.price = Price.text
myList.rating = rateField.text
myList.purchased = purch
myList.notes = Notes.text
//from realm website example
try! realm.write{
realm.add(myList)
}
//from tutorials
//realm.beginWrite()
//realm.add(myList)
//try realm.commitWrite()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
Year.resignFirstResponder()
Price.resignFirstResponder()
}
}
extension RankViewController : UITextFieldDelegate{
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
Separate file
import Foundation
import RealmSwift
class WineList: Object {
#objc dynamic var vinyard: String?
#objc dynamic var name: String?
#objc dynamic var grape: String?
#objc dynamic var year: String?
#objc dynamic var price: String?
#objc dynamic var notes: String?
#objc dynamic var type: String?
#objc dynamic var rating: String?
#objc dynamic var purchased: String?
}

Variables only exist with the function or class they are created. So take these two functions
func getData() {
let realm = Realm()
let results = realm.objects...
}
and
func printData() {
print(results) //this won't work
}
as you can see, the var 'realm' is instantiated in getData so that var is only available within that function and would not be available within the printData function.
In your case you've instantiated the realm var within viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
let realm = try! Realm()
therefore it will only be available within the viewDidLoad function.
To correct your issue, you need to instantiate realm within the function where you're trying to use it
#IBAction func Submit(_ sender: Any) {
let myList = WineList()
...
let realm = try! Realm()
try! realm.write{
realm.add(myList)
}
to expand on that a bit. Take your RankViewController class
class RankViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
var purch = ""
See the 'purch' var? That's called a 'class var' and because it's defined at a high level within the class, it would be available throughout the class.
func printData() {
print(self.purch) //this will work
}
note that I preceded purch with self. when I referenced it. To me, that's a good indicator it's a class var and makes the code more readable. However, it's not required.

Related

Passing data between Main VC to second VC doesn't work in Swift

Would you please help me? :) I've been struggling with this problem for like a week and couldn't solve it. my problem is - I can't pass data between my two view controllers, let me explain myself better:
I've got one VC which is the main VC that has the Clock animation, and I've got another VC which takes care of the SettingsVC. now no matter what I do (delegation, anything..) it doesn't let me to pass my UILabel's text to the main VC. I beg for a help since I can't keep going with my app and I'm about to finish it.
MyCode:
1st ViewController:
import UIKit
import CircleProgressView
import AVFoundation
import Foundation
import PickerViewCell
class PomodoroViewController: UIViewController{
//MARK: - Outlets Section:
#IBOutlet weak var playSymbol: UIButton!
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var settingsSymbol: UIBarButtonItem!
#IBOutlet weak var timeLabel: UILabel!
#IBOutlet weak var deleteTask: UIButton!
#IBOutlet weak var tasksLabel: UILabel!
#IBOutlet weak var circleProgressView: CircleProgressView!
// MARK: - Class Variables
private var timerIsOn = false
var timeRemaining = 1500
private var totalTime = 1500
private var completedTasks = 0
private var secondsPassed = 0 // AINT SURE
private var counter = 0
//Instance objects:
private var timer = Timer()
var calculateManager = CalculateManager()
//MARK:- ViewDidLoad Section:
override func viewDidLoad() {
textField.delegate = self
deleteTask.isHidden = true
}
//MARK: - Play Function:
#IBAction func playPreesedButton(_ sender: UIButton) {
//What will happen once we hit the play button:
counter += 1 //1 = play, 2 = pause, 3 = play, 4 = pause
if !timerIsOn
{ // means its true cause the user pressed the play button:
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(onTimerFires), userInfo: nil, repeats: true)
timerIsOn = true
deleteTask.isHidden = false // showing up the delete button.
}
playSymbol.setBackgroundImage(UIImage(named: T.P.pausePic), for: .normal) // setting the image to pause button
if counter.isMultiple(of: 2) {
timer.invalidate()
timerIsOn = false // cause we stopped the timer due to the Pause Button.
playSymbol.setBackgroundImage(UIImage(named: T.P.playPic), for: .normal) // setting the image to play button
}
}
//MARK: - Update Function:
#objc func onTimerFires()
{
print("the total time is - \(timeRemaining)")
timeRemaining -= 1 //1499 - in seconds
secondsPassed = totalTime - timeRemaining
//Updating the timeLabel:
let minutesLeft = Int(timeRemaining) / 60 % 60
let secondsLeft = Int(timeRemaining) % 60
let timeToDisply = String(format:"%02i:%02i", minutesLeft, secondsLeft)
timeLabel.text = timeToDisply
//Updating the progressBar View:
let cal = calculateManager.updateProgressView(seconds: secondsPassed, time: totalTime)
circleProgressView.setProgress( cal , animated: true)
if timeRemaining <= 0 {
//what happen once we finish the 25mins:
timer.invalidate()
//Updating the tasks:
if completedTasks < 10 {
completedTasks += 1
}
tasksLabel.text = "Tasks: \(completedTasks)/10"
//TODO: Play the sound that the user chose:
//Setting up the timer to 5mins break after an interval is done:
timeLabel.text = T.breakTime // Setting up the TimeLabel to be 5:00 of the break
timeRemaining = T.breakInMins // Setting up the totalTime to 300seconds which is 5 mins
playSymbol.setBackgroundImage(UIImage(named: T.P.playPic), for: .normal) // Setting up the Icon to the play button.
}
}
//MARK: - Reset Function:
#IBAction func resetTapped(_ sender: UIButton) {
let alert = UIAlertController(title: "Are you sure you want to skip this task?", message: .none, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Skip", style: .destructive, handler: { action in
//Once the user wants to reset the task - known as the Reset Button.
self.timer.invalidate()
self.timeRemaining = 1500
self.timeLabel.text = "25:00"
self.textField.text = "" //setting the textfield to be empty
self.timerIsOn = false
self.playSymbol.setBackgroundImage(UIImage(named: T.P.playPic), for: .normal)
self.circleProgressView.setProgress( T.resetProgress , animated: false)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true)
}
//MARK: - Settings Section:
#IBAction func settingsPreesedButton(_ sender: UIButton) {
}
}
//MARK: - UITextField Delegate Methods:
extension PomodoroViewController: UITextFieldDelegate
{
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
extension PomodoroViewController: CalculateManagerDelegate {
func updateTotalTime(time: Int) {
timeRemaining = time
}
}
my second ViewController:
import Foundation
import UIKit
import AVFoundation
import PickerViewCell
//MARK: - Settings View Controller:
class SettingsViewController: UITableViewController, PickerTableCellDelegate, PickerTableCellDataSource {
#IBOutlet weak var workInterval: UILabel!
#IBOutlet weak var shortBreak: UILabel!
#IBOutlet weak var longBreakAfter: UILabel!
#IBOutlet weak var dailyIntervals: UILabel!
let defaults = UserDefaults.standard
var calculateManager = CalculateManager()
override func viewDidLoad() {
checkForSavedWorkTime()
}
var timesDictionary = [0: "30 Minutes",
1: "25 Minutes",
2: "20 Minutes",
3: "15 Minutes",
4: "10 Minutes",
5: "5 Minutes"
]
var intervalsDictionary = [ 0: "1 Intervals",
1: "2 Intervals",
2: "3 Intervals",
3: "4 Intervals",
4: "5 Intervals",
5: "6 Intervals",
6: "7 Intervals",
7: "8 Intervals",
8: "9 Intervals",
9: "10 Intervals"
]
var totalWorkTime = 0
//MARK: Picker TableCell Delegate Methods:
//This func chooses the title of every row in the UIPickerView selection:
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int, forCell cell: PickerTableViewCell) -> String? {
let identifier = cell.reuseIdentifier
switch identifier {
case "timeCell":
return timesDictionary[row]
case "shortBreakCell":
return timesDictionary[row]
case "longBreakAfterCell":
return timesDictionary[row]
case "intervalsCell":
return intervalsDictionary[row]
default:
print("There was a problem with titleforrow")
}
return nil
}
//This func takes control of what will happen once the user choose an optaion in the UIPickerView Selection:
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int, forCell cell: PickerTableViewCell) {
let identifier = cell.reuseIdentifier
switch identifier {
case "timeCell":
workInterval.text = timesDictionary[row]
let myString = workInterval.text!
if let totalTime = calculateManager.calculateTotalTime(convertString: myString) {
totalWorkTime = totalTime
}
saveTime(labelText: myString)
case "shortBreakCell":
shortBreak.text = timesDictionary[row]
case "longBreakAfterCell":
longBreakAfter.text = timesDictionary[row]
default:
print("There was a problem with Switch")
}
self.view.endEditing(true)
}
func saveTime(labelText: String) {
defaults.set(labelText, forKey: "workInterval")
}
func checkForSavedWorkTime() {
if let time = defaults.string(forKey: "workInterval") {
workInterval.text = time
}
}
func onPickerOpen(_ cell: PickerTableViewCell) {
}
func onPickerClose(_ cell: PickerTableViewCell) {
}
//MARK: Picker TableCell DataSource:
func numberOfComponents(in pickerView: UIPickerView, forCell cell: PickerTableViewCell) -> Int {
return 1
}
//the amount of rows in component(UIPicker):
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int, forCell cell: PickerTableViewCell) -> Int {
if cell.reuseIdentifier == "timeCell"{
return timesDictionary.count
}
return intervalsDictionary.count
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: indexPath) as? DatePickerTableViewCell {
// cell.delegate = self
if !cell.isFirstResponder {
_ = cell.becomeFirstResponder()
}
} else if let cell = tableView.cellForRow(at: indexPath) as? PickerTableViewCell {
cell.delegate = self
cell.dataSource = self
if !cell.isFirstResponder {
_ = cell.becomeFirstResponder()
}
}
}
}
//MARK: - Completed View Controller:
class CompletetedSoundViewController: UITableViewController {
/// Class Variables
private var soundsArray = [Track]()
override func viewDidLoad() {
// tableView.delegate = self
// tableView.dataSource = self
}
///TableView Data Soruce Methods:
// Return the number of rows for the table.
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return soundsArray.count
}
// Provide a cell object for each row.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Fetch a cell of the appropriate type.
tableView.deselectRow(at: indexPath, animated: true)
let cell = tableView.dequeueReusableCell(withIdentifier: "trackCell", for: indexPath)
// Configure the cell’s contents.
cell.textLabel!.text = soundsArray[indexPath.row].trackName
return cell
}
///TableView Delegate Methods:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
//MARK: - Break Sound Controller:
class BreakSound: UITableViewController {
override func viewDidLoad() {
//
}
}
my Struct:
import Foundation
import UIKit
protocol CalculateManagerDelegate {
func updateTotalTime(time: Int)
}
struct CalculateManager {
var totalAmountOfTime = 0
var delegate: CalculateManagerDelegate?
//TODO: Calculate the Progress-View:
func updateProgressView(seconds: Int, time: Int ) -> Double {
return Double(seconds) / Double(time)
}
mutating func calculateTotalTime(convertString: String) -> Int? {
let newString = convertString.dropLast(8)
let subToString = String(newString)
if let turnToInt = Int(subToString)
{
totalAmountOfTime = turnToInt * 60
delegate?.updateTotalTime(time: totalAmountOfTime)
return totalAmountOfTime
}
return nil
}
}
first declare the delegate:
protocol SettingsDelegate {
func userSettings(interval:String?,shortBreak:String?,longBreak:String?)
}
then inside I would declare 3 strings (or whatever you want to pass back) and the delegate:
class SettingsViewController: UIViewController {
// this variables are optionals but it would be a good idea to set the initial value, maybe from UserSettings
var workIntervalString: String?
var shortBreakString: String?
var longBreakAfterString: String?
// your delegate
var delegate: SettingsDelegate?
// the inside the didSelectRow set the string variables
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int, forCell cell: PickerTableViewCell) {
let identifier = cell.reuseIdentifier
switch identifier {
case "timeCell":
workInterval.text = timesDictionary[row]
self.workInterval = timesDictionary[row] // set string
let myString = workInterval.text!
if let totalTime = calculateManager.calculateTotalTime(convertString: myString) {
totalWorkTime = totalTime
}
saveTime(labelText: myString)
case "shortBreakCell":
shortBreak.text = timesDictionary[row]
self.shortBreakString = timesDictionary[row] // set string
case "longBreakAfterCell":
longBreakAfter.text = timesDictionary[row]
self.longBreakAfterString = timesDictionary[row] // set string
default:
print("There was a problem with Switch")
}
// use your delegate
self.delegate?.userSettings(interval: self.workIntervalString,shortBreak:self.shortBreakString ,longBreak:self.longBreakAfterString)
self.view.endEditing(true)
}
in your PomodoroViewController:
class PomodoroViewController: UIViewController, SettingsDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func userSettings(interval: String?, shortBreak: String?, longBreak: String?) {
guard let interval = interval else {return}
guard let shortBreak = shortBreak else {return}
guard let longBreak = longBreak else {return}
//User your variables .......
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "your identifier" {
let destination = segue.destination as! SettingsViewController
destination.delegate = self // set the delefate as self
}
}

how to filter data with multiple buttons using delegate?

The Delegate that I am using is used to filter out the specified category using a delegate when a button is pressed in the FilterVC
what im struggling with is setting up buttons in the FilterVC so that filter works in the HomeVC
ive noticed that issue might be in my FilterVC when using the delegate in the #IBAction func acceptSelections where im getting the error Cannot convert value of type 'RoundButton?' to expected argument type 'String?' when calling the buttons when using the delegate to control which category
import UIKit
import Firebase
import FirebaseFirestore
class HomeViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
#IBOutlet var activeFiltersStackView: UIStackView!
#IBOutlet var stackViewHeightConstraint: NSLayoutConstraint!
#IBOutlet var jewelryFilterLbl: UILabel!
#IBOutlet var hatFilterLbl: UILabel!
#IBOutlet var shoeFilterLbl: UILabel!
#IBOutlet var apparelFilterLbl: UILabel!
#IBOutlet var gearFilterLbl: UILabel!
private lazy var baseQuery: Query = {
return Firestore.firestore().collection("products").limit(to: 50)
}()
fileprivate var query: Query?
lazy private var filters: (navigationController: UINavigationController,
filtersController: FilterViewController) = {
return FilterViewController.fromStoryboard(delegate: self)
}()
#IBAction func didTapClearBtn(_ sender: Any){
filters.filtersController.clearFilters()
controller(filters.filtersController, didSelectCategory: nil, sativa: nil, indica: nil, hybrid: nil, gear: nil)
}
var productSetup: [ProductList] = []
var products: ProductList?
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
// arranges products by store nearest you
fetchProducts { (products) in
self.productSetup = products.sorted(by: { $0.itemName < $1.itemName })
self.productListTableView.reloadData()
}
}
// fetches Firebase Data
func fetchProducts(_ completion: #escaping ([ProductList]) -> Void) {
let productQuery = Firestore.firestore().collection("products").limit(to: 50)
productQuery.addSnapshotListener { (snapshot, error) in
guard error == nil, let snapshot = snapshot, !snapshot.isEmpty else {
return
}
completion(snapshot.documents.compactMap( {ProductList(dictionary: $0.data())} ))
}
// shows Firestore data in log (not neccessary code just used to be seen in logs)
productQuery.getDocuments { (snapshot, error) in
if let error = error {
print("Oh no! Got an error! \(error.localizedDescription)")
return
}
guard let snapshot = snapshot else { return }
let allDocuments = snapshot.documents
for productDocument in allDocuments {
print("I have this product \(productDocument.data())")
}
}
}
}
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return productSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "HomeCell") as?
HomeCell else { return UITableViewCell() }
cell.configure(withProduct: productSetup[indexPath.row])
return cell
}
}
extension HomeViewController: FiltersViewControllerDelegate{
func query(withCategory jewelry: String?, hat: String?, shoe: String?, gear: String?, apparel: String?) -> Query {
if jewelry == nil && hat == nil && shoe == nil && gear == nil && apparel == nil {
stackViewHeightConstraint.constant = 0
activeFiltersStackView.isHidden = true
} else {
stackViewHeightConstraint.constant = 44
activeFiltersStackView.isHidden = false
}
var filtered = baseQuery
// Sort and Filter data
if let jewelry = jewelry, !jewelry.isEmpty {
filtered = filtered.whereField("category", isEqualTo: jewelry)
}
if let hat = hat, ! hat.isEmpty {
filtered = filtered.whereField("category", isEqualTo: hat)
}
if let shoe = shoe, !shoe.isEmpty {
filtered = filtered.whereField("category", isEqualTo: shoe)
}
if let gear = gear, !gear.isEmpty {
filtered = filtered.whereField("category", isEqualTo: gear)
}
if let apparel = apparel, !apparel.isEmpty {
filtered = filtered.whereField("category", isEqualTo: apparel)
}
return filtered
}
func controller(_ controller: FilterViewController,
didSelectCategory jewelry: String?,
hat: String?,
shoe: String?,
gear: String?,
apparel: String?) {
if jewelry == nil && hat == nil && shoe == nil && gear == nil && apparel == nil {
stackViewHeightConstraint.constant = 0
activeFiltersStackView.isHidden = true
} else {
stackViewHeightConstraint.constant = 44
activeFiltersStackView.isHidden = false
}
let filtered = query(withCategory: jewelry, hat: hat, shoe: shoe, gear: gear, apparel: apparel)
if let jewelry = jewelry, ! jewelry.isEmpty {
jewelryFilterLbl.text = jewelry
jewelryFilterLbl.isHidden = false
} else {
jewelryFilterLbl.isHidden = true
}
if let hat = hat, ! hat.isEmpty {
hatFilterLbl.text = hat
hatFilterLbl.isHidden = false
} else {
hatFilterLbl.isHidden = true
}
if let shoe = shoe, ! shoe.isEmpty {
shoeFilterLbl.text = shoe
shoeFilterLbl.isHidden = false
} else {
shoeFilterLbl.isHidden = true
}
if let gear = gear, !gear.isEmpty {
gearFilterLbl.text = gear
gearFilterLbl.isHidden = false
} else {
gearFilterLbl.isHidden = true
}
if let apparel = apparel, ! apparel.isEmpty {
apparelFilterLbl.text = apparel
apparelFilterLbl.isHidden = false
} else {
apparelFilterLbl.isHidden = true
}
query = filtered
}
}
import UIKit
import Firebase
protocol FiltersViewControllerDelegate: NSObjectProtocol {
func controller(_ controller: FilterViewController,
didSelectCategory jewelry: String?,
hat: String?,
shoe: String?,
gear: String?,
apparel: String?)
}
class FilterViewController: UIViewController {
#IBOutlet weak var jewelryBtn: RoundButton!
#IBOutlet weak var hatBtn: RoundButton!
#IBOutlet weak var shoeBtn: RoundButton!
#IBOutlet weak var gearBtn: RoundButton!
#IBOutlet weak var apparelBtn: RoundButton!
static func fromStoryboard(delegate: FiltersViewControllerDelegate? = nil) ->
(navigationController: UINavigationController, filtersController: FilterViewController) {
let navController = UIStoryboard(name: "Main", bundle: nil)
.instantiateViewController(withIdentifier: "FiltersViewController")
as! UINavigationController
let controller = navController.viewControllers[0] as! FilterViewController
controller.delegate = delegate
return (navigationController: navController, filtersController: controller)
}
weak var delegate: FiltersViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func filterSelect(_ sender: Any) {
if let button : UIButton = sender as? UIButton
{
button.isSelected = !button.isSelected
if (button.isSelected)
{
button.backgroundColor = .green
}
else
{
button.backgroundColor = .gray
}
}
}
func clearFilters() {
apparelBtn.isSelected = false
jewelryBtn.isSelected = false
shoeBtn.isSelected = false
hatBtn.isSelected = false
gearBtn.isSelected = false
}
#IBAction func closeFilter(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBAction func acceptSelections(_ sender: Any) {
delegate?.controller(self, //Problem integrating the buttons to get the correct category
didSelectCategory: jewelryBtn,
hat: hatBtn,
shoe: shoeBtn,
gear: gearBtn,
apparel: apparelBtn)
dismiss(animated: true)
}
}
As the filter functionality is pure boolean I recommend to just return the isSelected values of the buttons
protocol FiltersViewControllerDelegate: NSObjectProtocol {
func controller(_ controller: FilterViewController,
didSelectCategory jewelry: Bool,
hat: Bool,
shoe: Bool,
gear: Bool,
apparel: Bool)
}
And call it
#IBAction func acceptSelections(_ sender: Any) {
delegate?.controller(self,
didSelectCategory: jewelryBtn.isSelected,
hat: hatBtn.isSelected,
shoe: shoeBtn.isSelected,
gear: gearBtn.isSelected,
apparel: apparelBtn.isSelected)
dismiss(animated: true)
}
It seems to be a multiple choice selection so you have to combine the options in the query.

How to prevent cells from mirroring button pressed action in another cell? Part #2

This would be part # 2 of my question How to prevent cells from mirroring button pressed action in another cell?
What im trying to do is have my buttons have a button pressed turn red while a previously selected button deselects to back to blue, and also preventing it from mirroring the pressed button action in another cell, I have achieved that in a previous question I posted
what Im trying to do is integrate this with classes that pass data from Firebase Firestore. since I don't know where to go to convert this prevent the cells from mirroring the same button select action in another and changes the button selected to red and automatically deselects previous button back to blue
I have been stuck trying to make this work and just not getting the right luck to make it happen, I have been getting error codes in 3 different areas in ViewController preventing my code from compiling and making it work so that it works with my cells that pass data to labels from my cloud Firestore
any help would be appreciated and thank you for your time
import Foundation
import UIKit
class Labels {
var id: String
var lbl1: String
var lbl2: String
var lbl3: String
init(id: String,
lbl1: String,
lbl2: String,
lbl3: String) {
self.id = id
self. lbl1 = lbl1
self. lbl2 = lbl2
self. lbl3 = lbl3
}
convenience init(dictionary: [String : Any]) {
let id = dictionary["id"] as? String ?? ""
let lbl1 = dictionary["lbl1"] as? String ?? ""
let lbl2 = dictionary["lbl2"] as? String ?? ""
let lbl3 = dictionary["lbl3"] as? String ?? ""
self.init(id: id,
lbl1: lbl1,
lbl2: lbl2,
lbl3: lbl3)
}
}
enum ButtonSelectionIdentity {
case first
case second
case third
}
struct CellModel {
let buttonSelectionIdentity: ButtonSelectionIdentity
let labels: Labels
}
import UIKit
import SDWebImage
import Firebase
protocol OptionSelectDelegate: class {
func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity)
}
class Cell: UITableViewCell {
weak var labels: Labels!
private var elements: [ButtonSelectionIdentity] = []
weak var optionSelectDelegate: OptionSelectDelegate?
#IBOutlet weak var lbl1: UILabel!
#IBOutlet weak var lbl2: UILabel!
#IBOutlet weak var lbl3: UILabel!
#IBOutlet weak var btnOne: RoundButton!
#IBOutlet weak var btnTwo: RoundButton!
#IBOutlet weak var btnThree: RoundButton!
func configure(withLabels labels: Labels) {
lbl1.text = labels.lbl1
lbl2.text = labels.lbl2
lbl3.text = labels.lbl3
}
override func layoutSubviews() {
super.layoutSubviews()
}
func update(with model: ButtonSelectionIdentity) {
btnOne.backgroundColor = UIColor.blue
btnTwo.backgroundColor = UIColor.blue
btnThree.backgroundColor = UIColor.blue
switch model {
case .first:
btnOne.backgroundColor = UIColor.red
case .second:
btnTwo.backgroundColor = UIColor.red
case .third:
btnThree.backgroundColor = UIColor.red
}
}
#IBAction func optionSelectOne(_ sender: RoundButton!) {
optionSelectDelegate?.onCellModelChange(cell: self, model: .first)
}
#IBAction func optionSelectTwo(_ sender: RoundButton!) {
optionSelectDelegate?.onCellModelChange(cell: self, model: .second)
}
#IBAction func optionSelectThree(_ sender: RoundButton!) {
optionSelectDelegate?.onCellModelChange(cell: self, model: .third)
}
}
import UIKit
import Firebase
import FirebaseFirestore
class ViewController: UIViewController {
private var elements: [CellModel] = []
#IBOutlet weak var tableView: UITableView!
var labelSetup: [Labels] = []
override func viewDidLoad() {
super.viewDidLoad()
//▼ Cannot convert value of type 'ButtonSelectionIdentity' to expected argument type 'CellModel'
elements.append(ButtonSelectionIdentity.first) // error one
tableView.dataSource = self
tableView.delegate = self
fetchLabels { (labels) in
self.labelSetup = labels.sorted(by:
self.tableView.reloadData()
}
}
func fetchLabels(_ completion: #escaping ([Labels]) -> Void) {
let ref = Firestore.firestore().collection("labels")
ref.addSnapshotListener { (snapshot, error) in
guard error == nil, let snapshot = snapshot, !snapshot.isEmpty else {
return
}
completion(snapshot.documents.compactMap( {Labels(dictionary: $0.data())} ))
}
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return labelSetup.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? Cell else { return UITableViewCell() }
cell.configure(withLabels: labelSetup[indexPath.row])
cell.optionSelectDelegate = self
let model = elements[indexPath.row]
//▼ Cannot convert value of type 'CellModel' to expected argument type 'ButtonSelectionIdentity'
cell.update (with: CellModel) //error 2
return cell
}
}
extension ViewController: OptionSelectDelegate {
func onCellModelChange(cell: Cell, model: ButtonSelectionIdentity) {
guard let indexPath = productListTableView.indexPath(for: cell) else {
return
}
let index = indexPath.row
elements[index] = model
//▼ Cannot assign value of type 'ButtonSelectionIdentity' to type 'CellModel'
cell.update(with: model) //error 3
}
}

Can't save data from UIPickerView

I tried to program a sign up view controller and use a UIPickerView for country choice. The issue is that when I tried to pass the picker country to Parse to save the input, Xcode give me an error. Why Xcode can't allow me to use the selected data to Parse? The error is in the last line.
Any help guys?
#IBOutlet var usernameTextField: UITextField!
#IBOutlet var fullnameTextField: UITextField!
#IBOutlet var emailTextField: UITextField!
#IBOutlet var passwordTextField: UITextField!
#IBOutlet var phonenumberTextField: UITextField!
#IBOutlet var countryPicker: UIPickerView!
let countryData: [String] = ["Saudi Arabia", "Turkey"]
#available(iOS 2.0, *)
public func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return countryData.count
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let countrySelect = countryData[row]
print(countrySelect)
}
override func viewDidLoad() {
super.viewDidLoad()
countryPicker.dataSource = self
countryPicker.delegate = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func signUpAction(sender: AnyObject) {
// Declare user object
let newUser = PFUser()
let fullName = fullnameTextField.text!
let username = usernameTextField.text!
let email:String = emailTextField.text!
let password:String = passwordTextField.text!
let phoneNumber:Int? = Int(phonenumberTextField.text!)
// Passing arguments
newUser.username = username
newUser["fullName"] = fullName
newUser.email = email
newUser.password = password
newUser["phoneNumber"] = phoneNumber! as Int
newUser["country"] = countryData [row]
Based on your comment that the error is "unresolved identifier row":
You are never declaring a variable named row, yet you're using it. You can either replace the use of this undefined variable with the correct array index that will give you the country from the countryData variable OR you make sure that row is actually declared and accessible in your function.

How use coredata in MVC

I can use Core Data in Functions but i can´t create in MVC, like this:
class addBD{
func add(){
let entityDescripition = NSEntityDescription.entityForName("Radar",inManagedObjectContext: managedObjectContext!)
let task = Radar(entity: entityDescripition!, insertIntoManagedObjectContext: managedObjectContext)
task.descricao = vlrDesc.text
task.latitude = fieldLatitude.text
task.longitude = fieldLongitude.text;
task.velocidade = picker.selectedRowInComponent(0)
managedObjectContext?.save(nil)
}
}
import UIKit
import CoreData
class adicionarRadar: UIViewController, NSFetchedResultsControllerDelegate {
func createTask() {
adic.add()
}
I have this errors:
Use of unresolved identifier 'managedObjectContext'
Use of unresolved identifier 'vlrDesc'
... all of the variables
class addBD{
func add(){
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let entityDescripition = NSEntityDescription.entityForName("Radar",inManagedObjectContext: managedContext)
let task = Radar(entity: entityDescripition!, insertIntoManagedObjectContext: managedContext)
task.descricao = vlrDesc.text
task.latitude = fieldLatitude.text
task.longitude = fieldLongitude.text;
task.velocidade = picker.selectedRowInComponent(0)
managedContext.save(nil)
}
}
import UIKit
import CoreData
class adicionarRadar: UIViewController, NSFetchedResultsControllerDelegate {
var velocidade = ["40","50","70","90","100","120"]
var latitude:String = ""
var longitude:String = ""
var descrip:String = ""
var velocid:NSNumber = 0.0
var task: Radar? = nil
var idPicker:Int = 0
let adic = adiciona()
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
#IBOutlet weak var fieldLatitude: UITextField!
#IBOutlet weak var fieldLongitude: UITextField!
#IBOutlet weak var picker: UIPickerView!
#IBOutlet weak var vlrDesc: UITextField!
#IBAction func adicionar(sender: AnyObject) {
if task != nil {
editTask()
} else {
createTask()
}
dismissViewController()
}
func createTask() {
adic.add()
}
func editTask() {
task?.descricao = vlrDesc.text
task?.latitude = fieldLatitude.text
task?.longitude = fieldLongitude.text
task?.velocidade = picker.selectedRowInComponent(0)
println(picker.selectedRowInComponent(0))
managedObjectContext?.save(nil)
}
func dismissViewController() {
navigationController?.popViewControllerAnimated(true)
}
func textFieldSouldReturn (textField: UITextField) -> Bool{
textField.resignFirstResponder()
return true
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
self.view.endEditing(true)
}
override func viewDidLoad() {
vlrDesc.text = descrip
fieldLatitude.text = latitude
fieldLongitude.text=longitude
idPicker = Int(velocid)
picker.selectRow(idPicker, inComponent: 0, animated: true)
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return velocidade[row]
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return velocidade.count
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
First, I would start by having a look here:
http://www.raywenderlich.com/85578/first-core-data-app-using-swift
That should get you started and should guide you on where you need to go.
For the first error: Use of unresolved identifier 'managedObjectContext', this is happening because you haven't actually retrieved this context from the AppDelegate
Use this in your add() function:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
Now you have access to the managed context shared throughout your app for CoreData.
For the second error, you must have not declared or instantiated these variables somewhere in your code.
EDIT: Second Error:
So, the problem is that the function does not have a reference to those variables. They are declared in a different class and thus the class addBD can not interact with them.
One solution could be to add parameters to the function func add(), try changing it to something like
func add(vlrDesc: String, etc, etc)
And when you call add, pass in the vlrDesc and other variables as arguments.