TextField will not load from RealmSwift - swift

So here is the problem that I have been going crazy with. I have an app that uses Realm as its Database. I have used Realm in the past with tableviews and it works properly. I can't seem to get the textField data that I saved to load into my view on viewDidLoad. With tableViews there is a reloadData method, but that isn't the case with textFields. I need the data that is in my data base to load into the view on viewDidLoad and I have confirmed several times that data has been saved and is sitting in the dataBase just waiting to load into the view, but it will not load.
import Cocoa
import RealmSwift
class PublisherViewController: NSViewController {
#IBOutlet weak var publisherName: NSTextField!
let realm = try! Realm()
var pubData : Results<Pub>?
override func viewDidLoad() {
super.viewDidLoad()
// Here is where textField.stringValues should load into the viewDidLoad
let theData = Pub()
theData.pubName = publisherName.stringValue
print("print \(theData)")
}
func save(pubData: Pub) {
do {
try realm.write {
realm.add(pubData)
}
} catch {
print("there was an error saving pubData \(error)")
}
}
#IBAction func savePublisher(_ sender: NSButton) {
let publisherData = Pub()
publisherData.pubName = publisherName.stringValue
save(pubData: publisherData)
}
}
Here is my data model
import Foundation
import RealmSwift
class Pub: Object {
#objc dynamic var pubName : String = """
}

Thanks to Mrkrisher on Discord here is the answer on how to display the last saved textViews and textFields from Realm into your viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
publisherName.stringValue = (pubData?.last?.pubName)?? ""
}

Related

How to create a Event in a normal class by swift?

I want to create an login template in a normal class,but in the class,the view can't call the event,no "sss" be printed when the Event triggered
import UIKit
class ViewController: UIViewController ,UITextFieldDelegate{
override func viewDidLoad() {
super.viewDidLoad()
let loginView=login(view: self.view,controller:self)
loginView.setView();
}
}
import UIKit
class login{
let PassWord=UITextField()
let view:UIView!
let controller:ViewController
init(view:UIView,controller:ViewController){
self.view=view
self.controller=controller
}
func setView(){
initPassWord()
print("1")
}
func initPassWord(){
PassWord.placeholder="PassWord"
PassWord.addTarget(self, action: #selector(login.exits(_:)), for:.allEvents)
//PassWord.addTarget(controller, action: #selector(login.exits(_:)), for:.allEvents)
}
#IBAction func exits(_ sender:UITextField){
print("sss")
}
You need
var loginView:Login! // hold a strong reference here , start class names with capital letter
override func viewDidLoad() {
super.viewDidLoad()
loginView = Login(controller:self)
loginView.setView();
}
Also make it weak
weak var controller:ViewController
as not to cause retain cycles
BTW you only need to send the controller , and there you can access it's view

VIPER architecture using Swift to store data in presenter

So I'm setting up a simple VIPER architecture in Swift.
The Interactor gets some data from an API, and passes the data to the presenter that then passes formatted data to the view.
The presenter will process the data, and just count the number of objects that are downloaded. To do so I have stored a var in the presenter. The question is should I store data in the presenter?
Interactor:
class Interactor {
weak var presenter: Presenter?
func getData() {
ClosureDataManager.shared.fetchBreaches(withURLString: baseUrl + breachesExtensionURL, completion: { [weak self] result in
guard let self = self else { return }
switch result {
case .failure(let error):
print(error)
case .success(let breaches):
self.presenter?.dataDidFetch(breaches: breaches)
self.presenter?.dataNumberDidFetch(number: breaches.count)
}
})
}
}
Presenter:
class Presenter {
var wireframe: Wireframe?
var view: ViewController?
var interactor: Interactor?
var dataDownloaded = 0
func viewDidLoad() {
print ("presenter vdl")
}
func loadData() {
interactor?.getData()
}
func dataDidFetch(breaches: [BreachModel]) {
view?.dataReady()
}
func showDetail(with text: String, from view: UIViewController) {
wireframe?.pushToDetail(with: text, from: view)
}
func dataNumberDidFetch(number: Int) {
dataDownloaded += number
view?.showData(number: String(dataDownloaded) )
}
}
View (ViewController)
protocol dataViewProtocol {
func showData(number: String)
}
class ViewController: UIViewController, dataViewProtocol {
#IBOutlet weak var showDetailButton: UIButton!
#IBOutlet weak var dataLabel: UILabel!
// weak here means it won't work
var presenter: Presenter?
#IBAction func buttonPressAction(_ sender: UIButton) {
presenter?.loadData()
}
#IBAction func buttonShowDetailAction(_ sender: UIButton) {
presenter?.showDetail(with: "AAA", from: self)
}
func dataReady() {
showDetailButton.isEnabled = true
}
func showData(number: String) {
dataLabel.text = number
}
override func viewDidLoad() {
super.viewDidLoad()
Wireframe.createViewModule(view: self)
presenter?.viewDidLoad()
}
}
Router (Wireframe)
class Wireframe {
static func createViewModule (view: ViewController) {
let presenterInst = Presenter()
view.presenter = presenterInst
view.presenter?.wireframe = Wireframe()
view.presenter?.view = view
view.presenter?.interactor = Interactor()
view.presenter?.interactor?.presenter = presenterInst
}
}
So should the presenter be used to store the number of objects downloaded?
What have you tried I've implemented the var, as shown above. This is a minimum example of the problem.
What resources have you used I've looked on StackOverflow, and Googled the issue. I can't find an answer, but know I could store the data in the view but I think this is incorrect. I could store the number of data in the Interactor, but this also doesn't seem right. It all seems...to violate separation of concerns...
I won't do your homework / use a different architecture / You should use protocols / Why is there a single protocol in your implementation This isn't homework, it is for my own self - study. There may be other architectures that can be used to do this (and coding to protocols is good practice) but this is about storing a variable in the presenter. I want to know if I should store the variable in the presenter, using VIPER and using Swift. Comments about trivia around the question are seldom helpful if they are about variable names, or the like.
What is the question? I want to know if I can store the number of downloaded data items in the presenter.

Firebase JSON Tree Data Retrieval in Swift

My Firebase data structure looks like:
The following code works to update the value of the label to be the current value of condition:
import UIKit
import Firebase
class ViewController: UIViewController {
let conditionRef = Database.database().reference().child("condition")
#IBOutlet weak var conditionLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
conditionRef.observe(.value) {
(snap: DataSnapshot) in
self.conditionLabel.text = (snap.value as! String).description
}
}
I want to update the value of the label to be that of test2. I've tried a lot of things, but the thing that made most sense to me was changing the constant conditionRef to:
let conditionRef = Database.database().reference().child("test1").child("test2")
This didn't work, and I'm not sure what will. I've gone through the Firebase documentation and multiple YouTube tutorials but can't seem to figure this trivial detail out.
Any help will be greatly appreciated, thanks in advance.
One solution is to create a reference to the node you want the value of and then observe it with a single event like this:
class ViewController: UIViewController {
var ref: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
self.ref = Database.database().reference()
let test2Ref = self.ref.child("fir-2-b1233").child("test1").child("test2")
test2Ref.observeSingleEvent(of: .value, with: { snapshot in
let val = snapshot.value as! Int
print(val)
})
}
}
The key is to ensure you include the entire path to the child node you want the data from.
and my Firebase Stucture
{
"fir-2-b1233" : {
"condition" : "foggy",
"test1" : {
"test2" : 0,
"test3" : 0
}
}
}

Parse PFUser not registering subclass

I am trying to use Parse PFUser in a software for OSX desktop. When I try to use it PFUser.query() it gives a message: Failed to set (contentViewController) user defined inspected property on (NSWindow): The class PFUser must be registered with registerSubclass before using Parse.
It is happening without registering the class.
I tried it registering the class this way: PFUser.registerSubclass() but it still doesn't work.
I will use the default PFUser without adding any fields to it, so I don't need to create a custom class to be my PFUser.
I tried to use PFUser.enableAutomaticUser() without success
Code below:
AppDelegate.swift
import Cocoa
import Parse
import Bolts
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
let APP_ID = "app_id"
let CLIENT_KEY = "client_key"
let SERVER = "https://parseserver.com/"
func applicationDidFinishLaunching(_ aNotification: Notification) {
PFUser.registerSubclass()
let configuracaoParse = ParseClientConfiguration {
$0.applicationId = self.APP_ID
$0.clientKey = self.CLIENT_KEY
$0.server = self.SERVER
}
Parse.initialize(with: configuracaoParse)
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
ViewController.swift
import Cocoa
import Parse
class ViewController: NSViewController {
#IBOutlet weak var emailTextField: NSTextField!
#IBOutlet weak var senhaSecureTextField: NSSecureTextField!
override func viewDidLoad() {
super.viewDidLoad()
contaUsuarios()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
#IBAction func entrarButtonClicked(_ sender: NSButton) {
}
func contaUsuarios() {
let query = PFUser.query()
query?.countObjectsInBackground(block: {
(count, error) -> Void in
let numeroUsers = Int(UInt32(count))
if numeroUsers > 0 {
}
print(numeroUsers)
})
}
}
Reading some content on the internet I discovered that in OSX the ViewController is launched before the AppDelegate finishes loading, so I initialized the Parse connection and subclassing in the ViewController's viewDidLoad instead of AppDelegate and it is working just fine.

How to set up a NSComboBox using prepare for segue or init?

I am really struggling to pass the contents of one array from a view controller to another to set up the contents of a nscombobox. I have tried everything I can think of, prepare for segue, init; but nothing seems to work.
the program flow is as follows: the user enter a number into a text field and based on it an array with the size of the number is created. Once the user presses a button the next VC appears that has a combo box and inside that combo box those numbers need to appear. All my attempts result in an empty array being passed. Could someone please take a bit of time and help me out. Im sure I'm doing a silly mistake but cannot figure out what.
Code listing below:
Class that take the user input. At this stage I'm trying to pass the contents of the array in the next class as I gave up on prepare for segue because that one crashes because of nil error. Please note that prepare for segue is uncommented in the code listing just for formatting purposes here. Im my program it is commented out as I am using perform segue at the moment.
Any solution would be nice please. Thank you.
import Cocoa
class SetNumberOfFloorsVC: NSViewController {
//MARK: - Properties
#IBOutlet internal weak var declaredNumber: NSTextField!
internal var declaredFloorsArray = [String]()
private var floorValue: Int {
get {
return Int(declaredNumber.stringValue)!
}
}
//MARK: - Actions
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction private func setNumberOfFloors(_ sender: NSButton) {
if declaredNumber.stringValue.isEmpty {
let screenAlert = NSAlert.init()
screenAlert.messageText = "Please specify the number of floors!"
screenAlert.addButton(withTitle: "Got it!")
screenAlert.runModal()
} else if floorValue == 0 || floorValue < 0 {
let screenAlert = NSAlert.init()
screenAlert.messageText = "Please input a correct number of floors!"
screenAlert.addButton(withTitle: "Got it!")
screenAlert.runModal()
} else {
for i in 0...floorValue - 1 {
declaredFloorsArray.append(String(i))
}
print("\(declaredFloorsArray)")
let declareNumberOfRoomsVC = SetNumberOfRoomsForFloorVC(boxData: declaredFloorsArray)
declareNumberOfRoomsVC.boxData = declaredFloorsArray
performSegue(withIdentifier: "set number of rooms", sender: self)
}
}
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if segue.identifier == "set number of rooms" {
if let addRoomsVC = segue.destinationController as? SetNumberOfRoomsForFloorVC {
addRoomsVC.floorBox.addItems(withObjectValues: declaredFloorsArray)
}
}
}
}
this is the class for the next VC with the combo box:
import Cocoa
class SetNumberOfRoomsForFloorVC: NSViewController, NSComboBoxDelegate, NSComboBoxDataSource {
//MARK: - Properties
#IBOutlet internal weak var floorBox: NSComboBox!
#IBOutlet private weak var numberOfRoomsTxtField: NSTextField!
internal var boxData = [String]()
//MARK: - Init
convenience init(boxData: [String]) {
self.init()
self.boxData = boxData
}
//MARK: - Actions
override func viewDidLoad() {
super.viewDidLoad()
floorBox.usesDataSource = true
floorBox.dataSource = self
floorBox.delegate = self
print("\(boxData)")
}
#IBAction private func setRoomsForFloor(_ sender: NSButton) {
}
//MARK: - Delegates
func numberOfItems(in comboBox: NSComboBox) -> Int {
return boxData.count
}
func comboBox(_ comboBox: NSComboBox, objectValueForItemAt index: Int) -> Any? {
return boxData[index]
}
}
First you should remove the following code.
let declareNumberOfRoomsVC = SetNumberOfRoomsForFloorVC(boxData: declaredFloorsArray)
declareNumberOfRoomsVC.boxData = declaredFloorsArray
I assume you think that the viewController you created here is passed to prepareForSegue. However the storyboard instantiates a new viewController for you.
After that you need to set your declaredFloorsArray as the the boxData of the new viewController in prepareForSegue and you should be good to go.