How to use RxSwift to implement the following logic with UITextfield? - rx-swift

The TextCode has a UItextField on the right side.
The PassCode has a UItextField on the right side.
Use RxSwift to implement the following logic.
SelectAlertItem AlertViewControll sheet style has three options: A, B, C. Now I can implement the selection logic.
I don't know how to use RxSwift to implement the following logic.
The following is my key logic: Only when the selectedItem is B. TextCodeTextField text must be copied to PassCodeTextField at the end of editing.
In other word, SelectType is B, TextCodeTextField input "11111" and editingend, then PassCodeTextField will be "11111".
How to use RxSwift to implement the following logic with UITextfield?

Here's how to do it using my Cause Logic Effect architecture (with notes):
import Cause_Logic_Effect
import RxCocoa
import RxSwift
import UIKit
final class ViewController: UIViewController {
var textCodeField: UITextField!
var selectTypeAction: UIButton!
var selectTypeLabel: UILabel!
var passCodeField: UITextField!
let disposeBag = DisposeBag()
}
extension ViewController {
func connect() {
// when user taps the selectTypeAction, display an action sheet alert to
// get the selection type from the user.
let selectType = selectTypeAction.rx.tap
.flatMapFirst(
presentScene(animated: true, over: selectTypeAction, scene: {
UIAlertController(
title: nil,
message: "Select Item:",
preferredStyle: .actionSheet
)
.scene { $0.connectChoice(choices: ["A", "B", "C"]) }
})
)
.share()
// when the user selects "B" grab the last value entered in the
// textCodeField and push it to the passCodeField
selectType
.compactMap { $0 }
.filter { $0 == "B" }
.withLatestFrom(textCodeField.rx.text)
.bind(to: passCodeField.rx.text)
.disposed(by: disposeBag)
// when the user selects a value push the value to the selectTypeLabel
selectType
.bind(to: selectTypeLabel.rx.text)
.disposed(by: disposeBag)
}
}

Related

iOS DropDown CocoaPod

I am trying to get to grips with iOS DropDown cocoapod
import UIKit
import iOSDropDown
class CountryConfirmViewController: UIViewController {
//var buttonTapped = 0
#IBOutlet weak var countryLabel: DropDown!
override func viewDidLoad() {
super.viewDidLoad()
dropDown()
}
#IBAction func confirmCountry(_ sender: UIButton) {
performSegue(withIdentifier: "goToUser", sender: self)
}
func dropDown() {
countryLabel.optionArray = ["First", "Second", "Third"]
countryLabel.showList()
}
}
The code above produces a dropdown menu but I can't get the data chosen by the user and move it to another controller. I can't find anything on the CocoaPod website about it or anywhere else.
You need to follow related library's documentation properly, I've found this code block;
dropDown.didSelect{(selectedText , index ,id) in
self.valueLabel.text = "Selected String: \(selectedText) \n index: \(index)"
}
You can grab selection, from the method didSelect

How to fetch using string in swift

I was just wondering how would I be able to use a searched barcode to fetch using Core Data in Swift. I'm basically passing a barcode to a static func method, but how would I be able to use that to fetch the data from the Core Data?
Here is the barcode when detected:
func barcodeDetected(code: String) {
// Let the user know we've found something.
let alert = UIAlertController(title: "Found a Barcode!", message: code, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Search", style: UIAlertActionStyle.Destructive, handler: { action in
// Remove the spaces.
let trimmedCode = code.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
// EAN or UPC?
// Check for added "0" at beginning of code.
let trimmedCodeString = "\(trimmedCode)"
var trimmedCodeNoZero: String
if trimmedCodeString.hasPrefix("0") && trimmedCodeString.characters.count > 1 {
trimmedCodeNoZero = String(trimmedCodeString.characters.dropFirst())
// Send the doctored barcode
ProductDetailsViewController.searchCode(trimmedCodeNoZero)
} else {
// Send the doctored barcode
ProductDetailsViewController.searchCode(trimmedCodeString)
}
self.navigationController?.popViewControllerAnimated(true)
}))
self.presentViewController(alert, animated: true, completion: nil)
}
My Product Class:
import UIKit
import Foundation
import CoreData
class ProductDetailsViewController: UIViewController, NSFetchedResultsControllerDelegate {
#IBOutlet weak var productLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
#IBAction func addProduct(sender: AnyObject) {
let AppDel = UIApplication.sharedApplication().delegate as? AppDelegate
let context:NSManagedObjectContext = (AppDel?.managedObjectContext)!
let ent = NSEntityDescription.entityForName("Products", inManagedObjectContext: context)
var newProduct = ProductItem(entity: ent!, insertIntoManagedObjectContext: context)
newProduct.title = productLabel.text
//newProduct.price = priceLabel.text
/*context.save(nil)
print(newProduct)
print("Object Saved")*/
}
private(set) var PRODUCT_NAME = ""
private(set) var PRODUCT_PRICE = ""
private var menuItems:[ProductItem] = []
static func searchCode(codeNumber: String) -> String{
let barcodeNumber = codeNumber
return barcodeNumber
}
deinit{
NSNotificationCenter.defaultCenter().removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
productLabel.text = "Scan a Product"
priceLabel.text = ""
NSNotificationCenter.defaultCenter().addObserver(self, selector: "setLabels:", name: "ProductNotification", object: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I already added the items into Core Data successfully and was able to load all items into a table in my app. Now with the barcode scanned I want to be able to just load the products with the barcode and i'm stuck on that part. As you can see my static fun searchCode is receiving the barcode from barcodeDetected but what should I do next to fetch it? Thanks.
EDIT:
Core Data Entity
import Foundation
import CoreData
#objc(ProductItem)
class ProductItem: NSManagedObject{
#NSManaged var barcodeNum:String?
#NSManaged var box_height:NSNumber?
#NSManaged var box_length:NSNumber?
#NSManaged var box_width:NSNumber?
#NSManaged var price:NSNumber?
#NSManaged var sku:String?
#NSManaged var weight:NSNumber?
#NSManaged var title:String?
}
To fetch the correct ProductItem, you need to use a predicate (see the Apple Documentation here). In your case, you could use something like this:
let AppDel = UIApplication.sharedApplication().delegate as? AppDelegate
let context:NSManagedObjectContext = (AppDel?.managedObjectContext)!
let fetchRequest = NSFetchRequest(entityName: "ProductItem")
fetchRequest.predicate = NSPredicate(format: "barcodeNum == %#",codeNumber)
let results = try! context.executeFetchRequest(fetchRequest) as! [ProductItem]
if results.count > 0 { // great, you found (at least one) matching item
let scannedProduct = results[0]
// from here you can access the attributes of the product
// such as title, price, sku, etc.
...
} else { // not found
...
}
Note that I've use try! for brevity, but in practice you should use proper do ... catch syntax and handle any errors.
I'm not clear why you are using a static func in the ProductDetailsViewController; a common approach would be to use the above fetch within your barcodeDetected method, and then to segue to the ProductDetailsViewController passing the relevant ProductItem for display/editing or whatever. Or to display an alert view if the product was not found.

Label is nil in custom controller class

// This is in ViewController.swift
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var oneLabel: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
oneLabel.stringValue = "All is well" // Here it works
//...
}
}
// Separate Swift code file
import Cocoa
import Foundation
var si = Simulate()
class Simulate: NSViewController {
#IBOutlet weak var aLabel: NSTextField!
func simulationManager() -> Bool {
var ni: Int
var breakPoint = false
rd.simStatus = .Running
do {
if rd.rchIndex >= ld.NodeCount(.Reach) {
if InterStepConvergence() {
NextTimeStep()
if aLabel != nil { // This is always false
aLabel.stringValue = String(rd.elapsedSec)
}
else {
println("Label is nil")
}
//...
}
}
}
}
}
I am trying to set up a custom controller to update the interface while a
simulation is running. I need to show the status of the simulation. The simulation runs in a separate thread, but even if I do it in the main thread, same problem as described below.
The label text can be changed if I do it in the ViewController class as above.
But if I try to modify the text on the label in the Simulate class the label
is always nil and so it doesn't work. But the code compiles OK. What am I missing here such that the label is always nil in the Simulate class? Thanks much, in advance.

How do I get the return key to perform the same action as a button press in Swift?

I want to know how you allow an action to be made by either pressing the return key on the software keyboard or by tapping a UIButton.
The UI button is already set up to perform an IBAction.
How do I also allow users to press the return key on the keyboard to perform the same action?
Make sure your class extends the UITextFieldDelegate protocol
SomeViewControllerClass : UIViewController, UITextFieldDelegate
You can perform action as follows:
override func viewDidLoad() {
super.viewDidLoad()
self.textField.delegate = self
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
//textField code
textField.resignFirstResponder() //if desired
performAction()
return true
}
func performAction() {
//action events
}
UPDATE
If your deployment target is iOS 9.0 or later, you can connect the “Primary Action Triggered” event of your text field to an action, like this:
ORIGINAL
Make your view controller adopt the UITextFieldDelegate protocol.
Set your text field's delegate to your view controller.
Implement textFieldShouldReturn: to call your action.
Swift 4.2 :
Other approach for the textfield created programmatically and doesn't need delegate :
MyTextField.addTarget(self, action: #selector(MyTextFielAction)
, for: UIControl.Event.primaryActionTriggered)
And then perform your action like below :
func MyTextFielAction(textField: UITextField) {
//YOUR CODE can perform same action as your UIButton
}
If your deployment target is iOS 9.0 or later, you can connect the “Primary Action Triggered” event of your text field to an action, like this:
I was not able to get the "Primary Action Triggered" to work as suggested. I used "Editing Did End" and that works for now Screenshot of Editing Did End
Here is a complete example, with both:
button-action to write and also to clear label and text when pressing button repeatedly it alternates both actions
return-in-keyboard when pressing key it triggers action and also resigns first responder
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var label1: UILabel!
var buttonHasBeenPressed = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
textField1.delegate = self
}
#IBAction func buttonGo(_ sender: Any) {
performAction()
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
performAction()
return true
}
func performAction() {
buttonHasBeenPressed = !buttonHasBeenPressed
if buttonHasBeenPressed == true {
label1.text = textField1.text
} else {
textField1.text = ""
label1.text = ""
}
}
}

Passing Data in Swift

I have been looking for an answer for this, but have only found answers for segues.
I have viewController1 with a button that segues to viewController2. There is no code for this, I set it up through Interface builder. On viewController2 I have a button that dismisses itself with
self.dismissViewControllerAnimated(true, completion, nil)
I want to pass a string from viewController2 back to viewController1 when the view is dismissed. How do I go about doing this? Also, I am using swift.
Thanks in advance!
There are two common patterns, both of which eliminate the need for viewController2 to know explicitly about viewController1 (which is great for maintainability):
Create a delegate protocol for your for viewController2 and set viewController1 as the delegate. Whenever you want to send data back to viewController1, have viewController2 send the "delegate" the data
Setup a closure as a property that allows passing the data. viewController1 would implement that closure on viewController2 when displaying viewController2. Whenever viewController2 has data to pass back, it would call the closure. I feel that this method is more "swift" like.
Here is some example code for #2:
class ViewController2 : UIViewController {
var onDataAvailable : ((data: String) -> ())?
func sendData(data: String) {
// Whenever you want to send data back to viewController1, check
// if the closure is implemented and then call it if it is
self.onDataAvailable?(data: data)
}
}
class ViewController1 : UIViewController {
func doSomethingWithData(data: String) {
// Do something with data
}
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
// When preparing for the segue, have viewController1 provide a closure for
// onDataAvailable
if let viewController = segue.destinationViewController as? ViewController2 {
viewController.onDataAvailable = {[weak self]
(data) in
if let weakSelf = self {
weakSelf.doSomethingWithData(data)
}
}
}
}
}
I used the code from the first answer in a transition between controllers WITHOUT prepareForSegue and worked for me as well.
Here's the sample code.
The First View Controller:
#IBAction func dpAgendaClick(sender:UIBarButtonItem) {
///instantiating view controller with identifier
if let datePickerViewController = storyboard?.instantiateViewControllerWithIdentifier("DatePickerViewController")
as? DatePickerViewController {
///bring instantiated view controller to front
self.presentViewController(datePickerViewController, animated: true, completion: nil)
///wrapping the data returned
datePickerViewController.onDataFiltroAvailable = {[weak self]
(dataFiltro) in
if let weakSelf = self {
///use dataFiltro here
}
}
The second View Controller:
var onDataFiltroAvailable: ((dataFiltro: String) -> ())?
///private var
var dataFiltro: String = ""
///the returning data is obtained on the datePickerChanged event
#IBAction func datePickerChanged(sender: UIDatePicker) {
let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
dateFormatter.dateFormat = "yyyy-MM-dd"
dataFiltro = dateFormatter.stringFromDate(datePicker.date)
}
///dismiss the controller on button click
#IBAction func dpOkClick(sender: UIButton) {
///"returning" the data
self.onDataFiltroAvailable?(dataFiltro: dataFiltro)
dismissViewControllerAnimated(true, completion: nil)
}
(Swift 2.1, Xcode 7, iOS9)
If you don't want it to be tightly coupled only between 2 ViewControllers,
You can also use the Notification Design Pattern (Post & Observe), which is mainly used to pass on the same object/information from one VC to multiple View Controllers.
For your scenario :
In VC2.swift :
#IBAction func BackBtn(sender: UIButton) {
NSNotificationCenter.defaultCenter().postNotificationName("ThisIsTheMessage", object: nil, userInfo:["ObjectBeingSent":yourObject])
}
And in VC1.swift :
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("yourFunction:"), name: "ThisIsTheMessage", object: nil)
}
func yourFunction(theNotification : NSNotification) {
if let extractInfo = theNotification.userInfo {
//code to use the object sent from VC2, by extracting the object details
}
}
Common Practise is:
Pass data forward -> Use PrepareForSegue
Pass data backward to the previous View Controller-> Protocol and Delegation
Pass data across multiple View Controllers -> Notifications : Post and Observe(observe in all the View controllers where you are using the object details)

Resources