How to get Stripe's STPPaymentCardTextField Data programmatically? - swift

I've successfully set my first view controller to STPAddCardViewController. I now need to get the user information in the STPPaymentCardTextField. Problem is, I'm used to using the storyboard to make outlets. How do I detect the STPPaymentCardTextField programmatically?
I've tried:
class ViewController: STPAddCardViewController, STPPaymentCardTextFieldDelegate {
let paymentCardTextField = STPPaymentCardTextField()
func paymentCardTextFieldDidChange(_ textField: STPPaymentCardTextField) {
print(paymentCardTextField.cardNumber)
//ERROR: printing nil in the console
}
}
But I'm getting nil as an output. Any help?

You should use either STPAddCardViewController, or STPPaymentCardTextField, not both. The SDK's ViewControllers are not designed to be extended. The intended use is:
class MyVC : STPAddCardViewControllerDelegate {
override func viewDidLoad() {
…
let addCardView = STPAddCardViewController()
addCardView.delegate = self
// Start the addCardView
self.navigationController.pushViewController(addCardView, animated: true)
}
…
func addCardViewController(_ addCardViewController: STPAddCardViewController, didCreatePaymentMethod paymentMethod: STPPaymentMethod, completion: #escaping STPErrorBlock) {
// TODO: do something with paymentMethod
// Always call completion() to dismiss the view
completion()
}
func addCardViewControllerDidCancel(_ addCardViewController: STPAddCardViewController) {
// TODO: handle cancel
}
}
But rather than my partial example I'd recommend reading these docs and trying out this example iOS code. Best wishes!

Related

Can't get QuickLook to work when trying to preview files

I am writing a macOS application with Swift using story boards. I have a NSTableView which contains files that I want the user to be able to preview via QuickLook.
I seemingly have everything in place and my code looks very similar to what has been described here: QuickLook consumer as a delegate from an NSViewController, but I keep getting the error
-[QLPreviewPanel setDataSource:] called while the panel has no controller - Fix this or this will raise soon.
See comments in QLPreviewPanel.h for -acceptsPreviewPanelControl:/-beginPreviewPanelControl:/-endPreviewPanelControl:.
I've been trying to adapt the solution of above post to my situation with Swift and story boards.
The main pieces are:
import Quartz
class ViewController: NSViewController, QLPreviewPanelDataSource, QLPreviewPanelDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let windowNextResponder = self.view.window?.nextResponder
self.view.window?.nextResponder = self
self.nextResponder = windowNextResponder
}
// *** Quicklook stuff ***
#IBAction func quickLookButtonAction(_ sender: Any) {
guard qlPanel != nil else {
return
}
if qlPanel!.currentController == nil {
print ("No controller")
//qlPanel!.windowController = self.view.window?.windowController
// qlPanel!.updateController()
} else {
print (qlPanel!.currentController)
}
qlPanel!.delegate = self
qlPanel!.dataSource = self
qlPanel!.makeKeyAndOrderFront(self)
}
func numberOfPreviewItems(in panel: QLPreviewPanel!) -> Int {
return CSVarrayController.selectedObjects.count
}
func previewPanel(_ panel: QLPreviewPanel!, previewItemAt index: Int) -> QLPreviewItem! {
let file = CSVarrayController.selectedObjects[index] as! CSVfile
return file.url as NSURL
}
override func acceptsPreviewPanelControl(_ panel: QLPreviewPanel!) -> Bool {
return true
}
override func beginPreviewPanelControl(_ panel: QLPreviewPanel!) {
panel.dataSource = self
panel.delegate = self
}
override func endPreviewPanelControl(_ panel: QLPreviewPanel!) {
panel.dataSource = nil
panel.delegate = nil
}
}
With or without messing with the responder chain I get the error.
The delegate functions all get called as expected as well.
Remove
qlPanel!.delegate = self
qlPanel!.dataSource = self
in quickLookButtonAction, the viewcontroller isn't in control yet. Wait for beginPreviewPanelControl.
From the documentation for currentController:
You should never change the preview panel’s state (its delegate, datasource, and so on) if you are not controlling it.
From comments in QLPreviewPanel.h for -beginPreviewPanelControl::
Sent to the object taking control of the Preview Panel.
The receiver should setup the preview panel (data source, delegate, binding, etc.) here.

Swift - ReSwift Subscribe to multiple substates

i am using ReSwift in my project to get a nice and clean redux architecture.
As i am not interested in the whole state i just subscribe to two substates for my viewcontroller:
extension ViewController: StoreSubscriber {
override func viewWillAppear(_ animated: Bool) {
store.subscribe(self) {
$0.select {
($0.subStateA, $0.subStateB)
}
}
}
override func viewWillDisappear(_ animated: Bool) {
store.unsubscribe(self)
}
func newState(state: (subStateA: SubStateA, subStateB: SubStateB)) {
print("test")
}
}
What happens:
My newState method is called every time any update happens to the store.
For example if i update subStateC it still triggers
func newState(state: (subStateA: SubStateA, subStateB: SubStateB)) {}
Can anybody explain why this happens?
Thanks and Greetings!
You can use skipRepeats after select invocation.
This problem is when you need only update state if substate was changed, using skipRepeats you can put a check if this is true you will skip the update, look this code to try to understand.
Example Code
This is a simple code about a state with navigation state and we want update state when navigation state change.
store.subscribe(self) { (subscriber:Subscription<State>) -> Subscription<RoutingState> in
subscriber.select({ (state:State) -> RoutingState in
return state.routing;
}).skipRepeats({ (oldRoutingState, newRoutingState) -> Bool in
return oldRoutingState.navigationState == newRoutingState.navigationState
})
}
This code will prevent call newState if nothing change in your filter.
I hope was helpful
Just do not subscribe whole ViewController or your ViewModel to states.
You can make subclasses (for example DataProvider) - subscribers for each state you need.
ViewController: UIViewController {
let dataProviderA = DataProviderA()
let dataProviderB = DataProviderB()
func viewDidLoad() {
super.viewDidLoad()
store.subscribe(self.dataProviderA) { $0.select { state in state.subStateA }. skipRepeats() }
store.subscribe(self.dataProviderB) { $0.select { state in state.subStateB }. skipRepeats() }
}
}
and your dataProviders must be StoreSubscribers of course:
class DataProviderA: StoreSubsciber<SubStateA> {
func newState(state: SubStateA) {
handle(state)
}
}
class DataProviderB: StoreSubsciber<SubStateB> {
func newState(state: SubStateB) {
handle(state)
}
}
I trust this is right approach - each object handle single state. Cheers!

How to call extension methods in overrideViewDidLoad in swift

I have the following code:
extension ViewController {
func AddLeftGesture(){
let SwipeLeft:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(MyDismissOnSwipeLeft))
self.view.addGestureRecognizer(SwipeLeft)
}
func MyDismissOnSwipeLeft(){
self.dismiss(animated: true, completion: nil)
}
and What I would like to accomplish is that override the viewDidLoad and
call AddLeftGesture method so that it'll be part of each VC I make
and I don't have to type it again and again in each viewDidLoad,
is this possible? or do you guys have any other suggestions?
well I don't think it's a good idea, because typically viewDidLoad is used for setting most properties and if you would like to override it in a view controller you should write it again.What I can suggest is that to make a base ViewController and add this code in the viewDidLoad of that and then subclass every viewController from the base view controller , This way whenever you want to change anything you just call super.viewDidLoad
class BaseViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
addLeftGesture()
}
}
class CustomViewController: BaseViewController{
}
Make this class which inherits UITapGestureRecognizer
open class BlockTap: UITapGestureRecognizer {
fileprivate var tapAction: ((UITapGestureRecognizer) -> Void)?
public override init(target: Any?, action: Selector?) {
super.init(target: target, action: action)
}
public convenience init (
tapCount: Int = 1,
fingerCount: Int = 1,
action: ((UITapGestureRecognizer) -> Void)?) {
self.init()
self.numberOfTapsRequired = tapCount
#if os(iOS)
self.numberOfTouchesRequired = fingerCount
#endif
self.tapAction = action
self.addTarget(self, action: #selector(BlockTap.didTap(_:)))
}
open func didTap (_ tap: UITapGestureRecognizer) {
tapAction? (tap)
}
}
then make an extension of UIView
extension UIView {
public func addTapGesture(tapNumber: Int = 1, action: ((UITapGestureRecognizer) -> ())?) {
let tap = BlockTap(tapCount: tapNumber, fingerCount: 1, action: action)
addGestureRecognizer(tap)
isUserInteractionEnabled = true
}
}
Then You can use this as
override func viewDidLoad() {
super.viewDidLoad()
self.view.addTapGesture(action: {[unowned self] (_) in
//Do whatever on click of View
})
}
Hope it helps!
There's two options AFAIK. Either you can subclass UIViewController and then make all of your controllers inherit from the subclassed one, or you can swizzle UIViewController's viewDidLoad().
I personally would choose swizzling, although it has one disadvantage - it hides the implementation and might be confusing for a new developer coming onto a project. So make sure you document this properly, somewhere in your project README and in the code as well.
Now for some code examples:
Subclassing UIViewController
MyViewController.swift
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addGesture()
}
func addGesture() {
// Do what you need
}
}
class OtherViewController: MyViewController {
// Automatically will add gesture because it's a subclass of MyViewController
}
Swizzling viewDidLoad
What method swizzling does is, that it exchanges implementations of your methods. That simply means that the name of your function points at code from a different function. For more information on this topic read this article.
UIViewController+Swizzle.swift
static func swizzle(selector originalSelector: Selector,
with newSelector: Selector,
on targetClass: AnyClass) {
let originalMethod = class_getInstanceMethod(targetClass, originalSelector)
let swizzledMethod = class_getInstanceMethod(targetClass, newSelector)
// If we were able to add the swizzled function, replace methods.
// Otherwise exchange implementations if method already exists.
if class_addMethod(targetClass, originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod)) {
class_replaceMethod(targetClass, newSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
extension UIViewController {
// This function is getting called automatically by the runtime,
// when this class is loaded to perform some additional intiialization.
// However, this has now been deprecated in Swift, so only option is to
// declare a static function which you need to remember to call from
// somewhere, preferably early in your app initialization, like your
// didFinishLaunching function in AppDelegate or even AppDelegate's init
// function. I kept the initialize function in the code as a reference,
// however you would probably want to write it like in the comment
// below, to silence the warning.
//
// class func swizzle()
//
open override class func initialize() {
if self != UIViewController.self { return }
let swizzlingClosure: () = {
swizzle(selector: #selector(UIViewController.viewDidLoad),
with: #selector(UIViewController.swizzled_viewDidLoad),
on: UIViewController.self)
}()
swizzlingClosure
}
#objc private func swizzled_viewDidLoad() {
// Calls the original implementation,
// because implementations are switched.
swizzled_viewWillAppear(animated)
// Do whatever you need
addGesture()
}
#objc func addGesture() {
// Add your gesture
}
}

KVO not working (swift 2.2)?

In my app, OneVC is one of child ViewControllers of PageViewController, TwoVC is the embed view controller of OneVC's Container View.
When the user drag the scroll view in OneVC, I want the drag action can be not just update the content in OneVC from web API, but notify TwoVC to update too.
Both OneVC and TwoVC will appear at interface at the same time when launch.
I'm following Apple's "Using Swift with Cocoa and Objective-C" "Key-Value Observing" instruction to imply KVO, but no notification is sent when the observed property changes. Please see below my code:
OneVC is the object to be observed.
class OneVC: UIViewController, UIScrollViewDelegate {
dynamic var isDragToUpdate = false
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if scrollView.contentOffset.y < -150 {
if isDragToUpdate {
isDragToUpdate = false
} else {
isDragToUpdate = true
}
print(isDragToUpdate)
}
}
}
TwoVC is the observer
class TwoVC: UIViewController {
let oneVC = OneVC()
override viewDidLoad() {
oneVC.addObserver(self, forKeyPath: "isDragToUpdate", options: [], context: nil)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
print("hoh")
guard keyPath == "isDragToUpdate" else {return}
print("hah")
}
deinit {
oneVC.removeObserver(self, forKeyPath: "isDragToUpdate")
}
}
I checked row by row, and find many other stackoverflow answers, but still no idea what's going wrong on my code, when drag and release the scrollview, none of "hoh" and "hah" are print in console, except print(isDragToUpdate) is printed properly.
Thank you in advance!

NSComboBox getGet value on change

I am new to OS X app development. I manage to built the NSComboBox (Selectable, not editable), I can get it indexOfSelectedItem on action button click, working fine.
How to detect the the value on change? When user change their selection, what kind of function I shall use to detect the new selected index?
I tried to use the NSNotification but it didn't pass the new change value, always is the default value when load. It is because I place the postNotificationName in wrong place or there are other method should use to get the value on change?
I tried searching the net, video, tutorial but mostly written for Objective-C. I can't find any answer for this in SWIFT.
import Cocoa
class NewProjectSetup: NSViewController {
let comboxRouterValue: [String] = ["No","Yes"]
#IBOutlet weak var projNewRouter: NSComboBox!
#IBAction func btnAddNewProject(sender: AnyObject) {
let comBoxID = projNewRouter.indexOfSelectedItem
print(“Combo Box ID is: \(comBoxID)”)
}
#IBAction func btnCancel(sender: AnyObject) {
self.dismissViewController(self)
}
override func viewDidLoad() {
super.viewDidLoad()
addComboxValue(comboxRouterValue,myObj:projNewRouter)
self.projNewRouter.selectItemAtIndex(0)
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(
self,
selector: “testNotication:”,
name:"NotificationIdentifier",
object: nil)
NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: projNewRouter.indexOfSelectedItem)
}
func testNotication(notification: NSNotification){
print("Found Combo ID \(notification.object)")
}
func addComboxValue(myVal:[String],myObj:AnyObject){
let myValno: Int = myVal.count
for var i = 0; i < myValno; ++i{
myObj.addItemWithObjectValue(myVal[i])
}
}
}
You need to define a delegate for the combobox that implements the NSComboBoxDelegate protocol, and then use the comboBoxSelectionDidChange(_:) method.
The easiest method is for your NewProjectSetup class to implement the delegate, as in:
class NewProjectSetup: NSViewController, NSComboBoxDelegate { ... etc
Then in viewDidLoad, also include:
self.projNewRouter.delegate = self
// self (ie. NewProjectSetup) implements NSComboBoxDelegate
And then you can pick up the change in:
func comboBoxSelectionDidChange(notification: NSNotification) {
print("Woohoo, it changed")
}