Swift 2 - Send Object to function - uitextfield

How can I send another object to textFieldDidChange function?
regName.delegate = self
regName.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
func textFieldDidChange(textField: UITextField, errorLabel: UILabel) {
validateReg(textField.text!, textField: textField, errorLabel: errorLabel)
}

As far as I know you cannot do this

Related

Obtaining a View Controller Reference

I read quite a few questions and answers no this problem. Some are for Ojective C. Some are for iOS. The ones that were close to what I need didn't work.
I've set up a protocol for delegation. It doesn't work. The problem is that delegate variable isn't set. I need the reference to an active controller.
Delegator
protocol SwitchTabDelegate: class {
func selectTab(tab: Int)
}
class ViewController: NSViewController {
weak var delegate: SwitchTabDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func selectCompositions(_ sender: NSButton) {
if let delegate = self.delegate {
delegate.selectTab(tab: 2)
}
else {
print("self.delegate is nil")
}
print("delegate called")
}
}
Delegatee
class TabViewController: NSTabViewController, SwitchTabDelegate {
var viewController : ViewController?;
override func viewDidLoad() {
super.viewDidLoad()
//viewController = storyboard?.instantiateController(withIdentifier: "viewController") as? ViewController
// viewController?.delegate = self
// print(viewController)
}
func selectTab(tab: Int) {
print("In the delegate")
switchToDataTab()
}
func switchToDataTab() {
Timer.scheduledTimer(timeInterval: 0.2, target: self,
selector: #selector(switchToDataTabCont),
userInfo: nil, repeats: false)
}
func switchToDataTabCont(){
self.selectedTabViewItemIndex = 2
}
}
The delegatee is the main NSViewContoller. On the storyboard, it contains two buttons and a Container view controller. Embedded in the container view controller is the TabViewController, the delegatee. You can see in the delegatee where I tried to get a reference. It does get a reference, presumably to the newly instantiated instance. I need a reference to the original view controller that was spun up when the application started.
Answer
I added the following code to the delegator:
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
let controller = segue.destinationController as! TabViewController
self.delegate = controller as SwitchTabDelegate
}
That's not how it should work following the design pattern. The delegator should have no knowledge of the delegatee. I've spent way too much time on this issue so a hack is going to do.
When using storyboards, you want to "push" references to children when they are created vs. pulling them from an upstream controller. This is what -prepareForSegue:sender: is used for.

UISwitch: Swift 3: Programmatically

How can I programmatically add a uiswitch and call an action when on and one when off? Ive been searching for hours now. Can I please have some help? I know how to add the switch but it stays on the screen no matter what scene I'm on. So far, I've been able to add the button and make it switch from on to off, but for some reason the switch just says on the screen in every scene. I was lost after that so I followed this; from How to programmatically put a UISwitch in a SpriteKit/Skcene
Yes it is possible. Just use this code in your SKScene class:
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let switchDemo = UISwitch(frame:CGRectMake(150, 300, 0, 0))
switchDemo.on = true
switchDemo.setOn(true, animated: false)
switchDemo.addTarget(self, action: "switchValueDidChange:", forControlEvents: .ValueChanged)
self.view!.addSubview(switchDemo)
}
Helper method:
func switchValueDidChange(sender:UISwitch!)
{
if (sender.on == true){
print("on")
}
else{
print("off")
}
}
I kept getting errors so I did what Xcode suggested which ended up with the SIGBART error.
You are calling the selector wrong on the addTarget action line. They finally changed it at one point in Swift 2 to get rid of using strings for selector method calls, which now makes them a lot less error prone.
Change it to this (Swift 3 syntax)
switchDemo.addTarget(self, action: #selector(switchValueDidChange(_:)), for: .valueChanged)
You basically call #selector in the action parameter and include the method you want to call, in your case switchValueDidChange. Note the (_:) syntax at the end, thats indicating that the method you want to call takes a parameter, in your case a UISwitch.
func switchValueDidChange(_ sender: UISwitch) {
...
}
If you want to call a regular method that takes no parameters e.g
func switchValueDidChange() {
}
than you would just say
switchDemo.addTarget(self, action: #selector(switchValueDidChange), for: .valueChanged)
without the (_:) syntax.
Hope this helps
Updated to swift 5
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let switchDemo = UISwitch(frame:CGRect(x: 150, y: 300, width: 0, height: 0))
switchDemo.isOn = true
switchDemo.setOn(true, animated: false)
switchDemo.addTarget(self, action: #selector(switchValueDidChange(_:)), for: .valueChanged)
self.view!.addSubview(switchDemo)
}
Helper method:
#objc func switchValueDidChange(_ sender: UISwitch!) {
if (sender.isOn){
print("on")
}
else{
print("off")
}
}
With parameter:
#IBOutlet var categorySwitch:UISwitch!
var categorySwitchIsOn:Bool = false
On viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
categorySwitch.addTarget(self, action:#selector(ViewController.categorySwitchValueChanged(_:)), for: .valueChanged)
}
Associated function:
func categorySwitchValueChanged(_ sender : UISwitch!){
if sender.isOn {
categorySwitchIsOn = true
} else {
categorySwitchIsOn = false
}
}

New Xcode 7.3 error - Ambiguous us of 'view'

The following code worked properly prior to upgrading to Xcode 7.3;
func myMethod() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(CreateButtonObject.notifyButtonAction(_:)))
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(CreateButtonObject.notifyButtonAction(_:)))
tapGesture.numberOfTapsRequired = 1
}
#IBAction #objc func notifyButtonAction (sender: AnyObject) {
let userInfo:Dictionary<String,AnyObject!>
print("Sender from tap or longpress: \(sender)")
**let button = sender.view as! UIButton**
let soundName = button.currentTitle!
userInfo = ["sender" : sender]
NSNotificationCenter.defaultCenter().postNotificationName(sleepEZButtonActionNotificationKey, object: nil, userInfo: userInfo)
DDLogDebug("CreateButtonObject.notifyButtonAction: Notificaiton! ButtonViewController")
DDLogDebug("CreateButtonObject.notifyButtonAction: Posted Notification sleepEZButtonActionNotificationKey to initiate buttonAction")
DDLogDebug("CreateButtonObject.notifyButtonAction: Button Name: \(soundName)")
DDLogDebug("")
}
But now when I do this in Xcode 7.3 I get the following error on the line with sender.view ;
Ambiguous use of 'view'
followed by a compiler error.
Anyone know what's going on here and how to fix. Can't figure this out. Basically I need to get the UIButton attributes out of the UITapGesureRecognizer object that is created and then activated on a button press. Stuck.
Thanks in advance...
In the declaration func notifyButtonAction (sender: AnyObject), you have typed sender as AnyObject. But an AnyObject doesn't have a view. So in your line sender.view as! UIButton, the phrase sender.view is illegal.
Type sender as a UIGestureRecognizer if that's what it is: func notifyButtonAction (sender: UIGestureRecognizer). A gesture recognizer does have a view, so all will be well.

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