How can I catch that #Published has changed with combine ? (UIKit) - swift

It takes data in my #Published variable in CarDetailViewModel, but I could not pass the data inside this variable to the variable in the ViewController.
ViewModel:
class CarDetailViewModel: ObservableObject {
#Published var carDetail: Car = Car(brand: "", features: CarFeatures(model: "", km: 0, year: 0, price: 0, image: "", gearType: "", fuelType: "", carVersion: ""))
private var anyCancellable = Set<AnyCancellable>()
var carSubject = PassthroughSubject<Car, Never>()
func prepareCarDetail() {
carSubject
.sink {[weak self] car in
self?.carDetail = car
print("car: \(self?.carDetail)") // it is working.
}
.store(in: &anyCancellable)
}
}
ViewController:
When the assignmentDataToUI function runs, the label on the screen is blank.
class CarDetailViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var brandLabel: UILabel!
#IBOutlet weak var modelLabel: UILabel!
#IBOutlet weak var gearTypeLabel: UILabel!
#IBOutlet weak var fuelTypeLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
var carDetailViewModel = CarDetailViewModel()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
carDetailViewModel.prepareCarDetail()
assignmentDataToUI()
}
func assignmentDataToUI() {
brandLabel.text = carDetailViewModel.carDetail.brand
}
}

I listened to carDetail in ViewModel with sink.
carDetailViewModel.$carDetail
.sink {[weak self] car in
guard let self = self else { return }
self.assignmentDataToUI()
}
.store(in: &anyCancelable)

Related

pass data from tableviewcontroller to another tableviewcontroller in swift

I have a form I am creating
this form gets filled with textfields the user inputs. After answering all the questions a button pops up to save.
I am having a problem making this tableviewcontroller to pass the data to a new tableviewcontroller. I'm stuck and not sure how to go about this.
import UIKit
class TableViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var saveBtn: UIButton!
#IBOutlet var firstNameField: UITextField!
#IBOutlet var middleNameField: UITextField!
#IBOutlet weak var lastNameField: UITextField!
#IBOutlet weak var addressField: UITextField!
#IBOutlet weak var aptNumField: UITextField!
#IBOutlet weak var cityField: UITextField!
#IBOutlet weak var stateField: UITextField!
#IBOutlet weak var zipField: UITextField!
#IBOutlet weak var phoneOneField: UITextField!
#IBOutlet weak var phoneTwoField: UITextField!
#IBOutlet weak var allergiesField: UITextField!
#IBOutlet weak var DobField: UILabel!
#IBOutlet weak var sexField: UILabel!
#IBOutlet weak var hospitalField: UITextField!
#IBOutlet weak var doctorField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
//Notifications to push datepicker
NotificationCenter.default.addObserver(forName: .saveDateTime, object: nil, queue: OperationQueue.main) { (notification) in
let dateVc = notification.object as! DatePopupViewController
self.DobField.text = dateVc.formattedDate
}
//Notifications to push genderpicker
NotificationCenter.default.addObserver(forName: .saveGender, object: nil, queue: OperationQueue.main) { (notification) in
let genderVc = notification.object as! GenderPopupViewController
self.sexField.text = genderVc.selectedGender
}
updateWidthsForLabels(labels: labels)
}
//Save Button Function
func textFieldDidChange(_ textField: UITextField) {
if textField == firstNameField || textField == lastNameField || textField == middleNameField || textField == addressField || textField == lastNameField || textField == cityField || textField == cityField || textField == stateField || textField == zipField || textField == phoneOneField || textField == phoneTwoField || textField == allergiesField {
saveBtn.isHidden = true
} else {
saveBtn.isHidden = false
}
}
#IBAction func saveBtnPressed(_ sender: Any) {
performSegue(withIdentifier: "saveFirstPageSegue", sender: self)
}
}
what about starting creating a model:
Form.swift
struct Form {
var firstname: String?
var middlename: String?
....
var doctor: String?
init(firstname: String, middlename: String, ..., doctor: String) {
self.firstname = firstname
self.middlename = middlename
...
self.doctor = doctor
}
}
now you can create this form instance when saving and pushing the data to the new VC:
yourCurrentForm.swift
#IBAction func saveBtnPressed(_ sender: Any) {
let formData = Form(firstname: firstNameField.text, middlename: middleNameField.text, ..., doctor: doctorField.text)
let newVC = myNewViewController()
newVC.form = formData
self.navigationController?.pushViewController(newVC, animated: true)
}
NewViewController.swift
class myNewViewController: UIViewController {
var form: Form?
.....
}
UPDATE:
Here is the repo: https://github.com/FlorianLdt/LFEasyDelegate
If you have some question just ask me
Hope it helps.
First Option - Structs - Preferred
Make use of Structs :
struct Manager
{
static var value : String = ""
}
Noe Update value of that function by just calling
Manager.value = "newValue"
Access that value anywhere Assign it to other Variables
let newStr : String = Manager.value
Second Option - AppDelegate - Not ideal
Create new object in AppDelegate
Now create a new object to access appDelegate
let appDel = UIApplication.shared.delegate as! AppDelegate
Access Value and update as below
appDel.Frequency = 1.0
Third Option - NSObjectClass
Create a new NSObject class as below
//Instance created when NSObject class is first time loaded in memory stack
static let shared = wrapperClass()
//Create a value to access Globally in Object class
var newValueInClass : String = ""
Now time to access that created Object
wrapperClass.shared.newValueInClass = "iosGeek"
Now Anywhere write this Line
print(wrapperClass.shared.newValueInClass)
Console Output
Better to use struct classes to manage data globally

How to Store NSPopUpButton TitleOfSelectedItem to Core Data Model Field?

I have created the following view controller and wired up the controls in my storyboard to it.
import Foundation
import CoreData
import AppKit
protocol SubmissionViewControllerDelegate {
func controller(_controller: SubmissionViewController,
didAddSubmissionWithID profileID: Int64)
}
class SubmissionViewController : ViewController {
#IBOutlet var profileIDComboBox: NSPopUpButton!
var profileSelectedValue: String!
#IBOutlet var transcriptTypeComboBox: NSPopUpButton!
var transcriptTypeSelectValue: String!
#IBOutlet var submissionTypeComboBox: NSPopUpButton!
var submissionTypeSelectValue: String!
#IBOutlet var transcriptionTurnaroundComboBox: NSPopUpButton!
var turnaroundSelectValue: String!
#IBOutlet var persistentNoteComboBox: NSPopUpButton!
var persistentNoteSelectValue: String!
#IBOutlet var notesTextField: NSTextField!
#IBOutlet var batchIdentifierTextField: NSTextField!
#IBOutlet var languageInAudioComboBox: NSPopUpButton!
var languageSelectValue: String!
#IBOutlet var addResultViewButton: NSButton!
#IBOutlet var submissionFiles: NSTableView!
var delegate: SubmissionViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func save(_ sender: Any) {
guard case profileIDComboBox.titleOfSelectedItem =
profileSelectedValue else { return }
guard case transcriptTypeComboBox.titleOfSelectedItem =
transcriptTypeSelectValue else { return }
guard let delegate = delegate else { return }
delegate.controller(self, didAddSubmissionWithID:
profileSelectedValue)
}
}
I now want to store the titleOfSelectedItem from each NSPopUpButton in my Core Data Submission model. However, when I set the variables to be strings, I receive the error as follows:
Cannot convert value of type 'String?' to expected argument type '_OptionalNilComparisonType'
How do I accomplish this task?

ProgressBar display only end

ProgressBar only shows the progress when the loop ends.
How do in this example for the bar to be updated in real time?
#IBAction func btnStart(sender: AnyObject) {
for var xx:Float = 0 ; xx<=1.0; xx=xx+0.00001 {
progressView.setProgress(xx, animated: false)
}
}
#IBOutlet weak var progressLabel: UILabel!
#IBOutlet weak var progressView: UIProgressView!
UI only updates in the main loop and at the end of the current scope,
so try this
#IBAction func btnStart(sender: AnyObject) {
NSThread.detachNewThreadSelector("process", toTarget: self, withObject: nil)
}
func process() {
for var xx:Float = 0 ; xx<=1.0; xx=xx+0.00001 {
dispatch_async(dispatch_get_main_queue(), {
progressView.setProgress(xx, animated: false)
})
}
}
#IBOutlet weak var progressLabel: UILabel!
#IBOutlet weak var progressView: UIProgressView!

Update labels from unwind segue

I'm trying to change the labels of a viewController after a certain action is taken from a modal view which triggers an unwind segue.
Once unwind segue happens the labels of the current view (the one which the modal was covering) should be changed.
My current attempt at doing this is resulting in a "unexpectedly found nil while unwrapping an Optional value" error. Here is the code:
class DataViewController: UIViewController {
var experiment: NSDictionary?
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var bodyLabel: UILabel!
#IBOutlet weak var tlRightLine: UIImageView!
#IBOutlet weak var tlLeftLine: UIImageView!
#IBOutlet weak var brRightLine: UIImageView!
#IBOutlet weak var brLeftLine: UIImageView!
#IBOutlet weak var bodyTest: UITextView!
#IBAction func removeExperimentSegue(unwindSegue:UIStoryboardSegue) {
removeExperiment = true
titleLabel.text = "Done"
bodyLabel.text = "Done"
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if let dict: NSDictionary = experiment {
if let title = dict.objectForKey("title") as? String {
self.titleLabel!.text = title
}
if let body = dict.objectForKey("body") as? String {
self.bodyTest!.text = body
}
} else {
self.titleLabel!.text = ""
self.bodyLabel!.text = ""
}
}
}
What am I doing wrong?
I did! I ended up using a global boolean variable. I set it true on the initial load of the menu and then had it flip to false during the unwind segue.
var removeExperiment = false
class DataViewController: UIViewController {
#IBAction func removeExperimentSegue(unwindSegue:UIStoryboardSegue) {
removeExperiment = true
}
if removeExperiment == true {
doneLabel.text = "You've completed this experiment. You won't see it again unless you hit 'Reset' from the Home menu."
}
}
Hope that helps!

Compose Email with multiple uitextfield (swift)

How do I compose an email through Swift with multiple UITextField? It seems like I can only enter one data (named UITextField) under messageBody. How do can I add multiple UITextField to my messageBody?
import UIKit
import CoreData
import MessageUI
class EmailTableViewController: UITableViewController, MFMailComposeViewControllerDelegate, UITextFieldDelegate {
#IBOutlet weak var name: UITextField!
#IBOutlet weak var phone: UITextField
#IBOutlet weak var email: UITextField!
#IBOutlet weak var base: UITextField!
#IBOutlet weak var rig: UITextField!
#IBOutlet weak var wellhead: UITextField!
#IBOutlet weak var connector: UITextField!
#IBOutlet weak var size: UITextField!
#IBOutlet weak var depth: UITextField!
#IBOutlet weak var pressure: UITextField!
#IBOutlet weak var temp: UITextField!
#IBAction func SendEmailButton(sender: AnyObject) {
var emailTitle = "Interface Information"
var messageBody = name.text
var toRecipents = ["test.com"]
var mc: MFMailComposeViewController = MFMailComposeViewController()
mc.mailComposeDelegate = self
mc.setSubject(emailTitle)
mc.setMessageBody(messageBody, isHTML: false)
mc.setToRecipients(toRecipents)
self.presentViewController(mc, animated: true, completion: nil)
}
func mailComposeController(controller:MFMailComposeViewController, didFinishWithResult result:MFMailComposeResult, error:NSError) {
switch result.value {
case MFMailComposeResultCancelled.value:
println("Mail cancelled")
case MFMailComposeResultSaved.value:
println("Mail saved")
case MFMailComposeResultSent.value:
println("Mail sent")
case MFMailComposeResultFailed.value:
println("Mail sent failure: %#", [error.localizedDescription])
default:
break
}
self.dismissViewControllerAnimated(true, completion: nil)
}
You can just create a little helper function and put the fields in an array, like this:
func appendTextFromTextField(string: String, textField: UITextField) -> String {
return string + textField.text + "\n"
}
#IBAction func SendEmailButton(sender: AnyObject) {
var fields: [UITextField] = [name, phone, email, base, rig, wellhead, connector,
size, depth, pressure, temp]
var messageBody = ""
for f in fields {
messageBody = appendTextFromTextField(messageBody, textField: f)
}
// etc.
}