Swift 4 - Enable/Disable Two UI Buttons Based On Different TextField Inputs - input

I feel like I'm missing a basic step with this code set and really would appreciate any insight since I couldn't find a great solution despite searching these forums.
I have four textfields, two UI buttons, and two labels.
When the first three textfields have input, one of the UI buttons should be enabled allowing me to calculate the sum of those three textfields and display it on the first label.
The second UI button should only be enabled if the fourth textfield has input. The second label will contain the sum of all four textfields. If these conditions aren't met, the UI buttons should be disabled.
I have the first situation working great, but things get messed up when I try to incorporate the fourth text field and second button. See the last snippet: let regurgVTI = AIVTI.text, !regurgVTI.isEmpty
class AICalc: UIViewController
{
#IBOutlet weak var PISARadius: UITextField!
#IBOutlet weak var aliasingVelocity: UITextField!
#IBOutlet weak var AIVMax: UITextField!
#IBOutlet weak var AIVTI: UITextField!
#IBOutlet weak var EROAAnswer: UILabel!
#IBOutlet weak var RegurgVolumeAnswer: UILabel!
#IBOutlet weak var calcEROAButton: UIButton!
#IBOutlet weak var regurgVolumeButton: UIButton!
#IBAction func calcEROA(_ sender: UIButton)
{
EROAAnswer.text = String(Int(PISARadius.text!)! + Int(aliasingVelocity.text!)! + Int(AIVMax.text!)!)
}
#IBAction func calcRegurgVolume(_ sender: UIButton)
{
RegurgVolumeAnswer.text = String(Int(PISARadius.text!)! + Int(aliasingVelocity.text!)! + Int(AIVMax.text!)! + Int(AIVTI.text!)!)
}
override func viewDidLoad()
{
super.viewDidLoad()
calcEROAButton.isEnabled = false
regurgVolumeButton.isEnabled = false
PISARadius.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged)
aliasingVelocity.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged)
AIVMax.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged)
AIVTI.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc func editingChanged(_ textField: UITextField) {
if textField.text?.count == 1 {
if textField.text?.first == " " {
textField.text = ""
return
}
}
guard
let pisa = PISARadius.text, !pisa.isEmpty,
let aliasing = aliasingVelocity.text, !aliasing.isEmpty,
let vmax = AIVMax.text, !vmax.isEmpty
else {
calcEROAButton.isEnabled = false
regurgVolumeButton.isEnabled = false
return
}
calcEROAButton.isEnabled = true
let regurgVTI = AIVTI.text, !regurgVTI.isEmpty
}
}

Use textField.tag or textField.identifier to identify textfield then you can solve your problem easily.
Let say your 1st three textfields have tag 1,2,3 simultaneously.
Then in your textfield did end_Enditing :-
if textfield.tag == 1 {
//Do whatever you want
}
if textfield.tag == 2 {
//Do whatever you want
}
if textfield.tag == 3 {
//Do whatever you want
}
Referring this may solve your problem.
Best luck.

Related

Swift and #objc methods: How do I transform a method so that it can be represented by #objc?

As Swift is my first programming language and also seeing that I have no Objective C experience...
I'm having difficulty understanding #objc in relation to methods.
How do I use the #objc syntax to conform to my methods?
Is there another way to select a method without using the #selector syntax?
Here is the code that I'm having difficulty with(mainly the #objc attempt at the startGame method):
import UIKit
#objc class ViewController: UITableViewController {
var allWords = [String]()
var usedWords = [String]()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem =
UIBarButtonItem(barButtonSystemItem: .add, target: self, action:
#selector(promptForAnswer))
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "New
Word", style: .plain, target: self, action: #selector(startGame))
if let startWordsURL = Bundle.main.url(forResource: "start",
withExtension: "txt") {
if let startWords = try? String(contentsOf: startWordsURL) {
allWords = startWords.components(separatedBy: "\n")
}
}
if allWords.isEmpty {
allWords = ["silkworm"]
}
#objc func startGame() {
title = allWords.randomElement()
usedWords.removeAll(keepingCapacity: true)
tableView.reloadData()
{
startGame()
}
A few observations:
You do not need #objc in your view controller declaration.
The two action/selector methods should bear #objc qualifier.
I would suggest that you give these two methods descriptive names that clearly indicate that they are called when the user taps on a particular button, e.g.:
#objc func didTapNewWord(_ sender: UIBarButtonItem) {
...
}
#objc func didTapAdd(_ sender: UIBarButtonItem) {
...
}
Note, I also added a parameter to these methods. That makes it entirely unambiguous that they are button handlers. You do not need to do that, but now you can glance at the code and immediately grok what the method is for.
Obviously, you will change the code that adds these target actions accordingly:
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add,
target: self,
action: #selector(didTapAdd(_:)))
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "New Word",
style: .plain,
target: self,
action: #selector(didTapNewWord(_:)))
Be careful with the placement of braces. Swift allows you to declare functions inside functions. So make sure that these selector methods are instance methods of the view controller, and not, for example, private functions declared inside another function (i.e. viewDidLoad).
If you start to lose track of the braces, you can select all the code in this file and press control+i (or in Xcode menus, “Editor” » “Structure” » “Re-Indent”). If you have missing braces somewhere, the re-indentation of the code will make this jump out at you.
So pulling that together, you get something like:
// ViewController.swift
import UIKit
class ViewController: UITableViewController {
var allWords = [String]()
var usedWords = [String]()
override func viewDidLoad() {
super.viewDidLoad()
configureButtons()
fetchData()
}
}
// MARK: - Actions
extension ViewController {
#objc func didTapNewWord(_ sender: UIBarButtonItem) {
startGame()
}
#objc func didTapAdd(_ sender: UIBarButtonItem) {
...
}
}
// MARK: - UITableViewDataSource
extension ViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
...
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
}
}
// MARK: - Private utility methods
private extension ViewController {
func configureButtons() {
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add,
target: self,
action: #selector(didTapAdd(_:)))
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "New Word",
style: .plain,
target: self,
action: #selector(didTapNewWord(_:)))
}
func fetchData() {
guard
let startWordsURL = Bundle.main.url(forResource: "start", withExtension: "txt"),
let startWords = try? String(contentsOf: startWordsURL).components(separatedBy: "\n"),
!startWords.isEmpty
else {
allWords = ["silkworm"]
return
}
allWords = startWords.filter { !$0.isEmpty }
}
func startGame() {
title = allWords.randomElement()
usedWords.removeAll(keepingCapacity: true)
tableView.reloadData()
}
}
A few final observations on my code sample (not directly related to your question, but just to explain why structured it like I did):
I like to put methods into extensions, so that they are in logical groups. This makes it easier to follow what is going on at a glance. You can also collapse/expand these extensions so that while you are editing, you can focus on the relevant code.
The MARK comments just puts nice section headers in the Xcode jump bar, again, making it easier to jump about in one’s code.
I personally don't put anything in the action methods except a call to some method with the “business logic”. This separates the “view” code (the handling of the button) from the business logic. Some day, you may start using view models or presenter objects, so embracing this separation of responsibilities now will make that eventual transition easier. It will also make it easier to write unit tests when you get around to that (e.g. you write unit tests for the "start game" logic, not not the tapping of a button).
I think you have syntax error in the #objc method. It should be:
#objc
func functionName() {
}
for you it will be:
#objc
func startGame() {
title = allWords.randomElement()
usedWords.removeAll(keepingCapacity: true)
tableView.reloadData()
}

How to display which number was taken as random from image?

Can someone please explain, what I should add to code to display in UILabel which number was taken as random from image?
Here's my code:
#IBOutlet weak var diceImageView1: UIImageView!
#IBOutlet weak var diceImageView2: UIImageView!
#IBOutlet weak var Label: UILabel!
#IBAction func rollButtonPressed(_ sender: UIButton) {
let diceArray = [ #imageLiteral(resourceName: "DiceOne"),#imageLiteral(resourceName: "DiceTwo"),#imageLiteral(resourceName: "DiceThree"),#imageLiteral(resourceName: "DiceFour"),#imageLiteral(resourceName: "DiceFive"),#imageLiteral(resourceName: "DiceSix") ]
diceImageView1.image = diceArray.randomElement()
diceImageView2.image = diceArray.randomElement()
Label.text = (diceImageView1.image)
}
Here's error I'm getting:
Cannot assign value of type 'UIImage?' to type 'String?'
Thank you!

Change UIButton's state from a different View Controller - Swift 4.2

I have gameCenterButton in VC1. Its purpose is to take the user to Game Center's Leaderboards where they can see High Scores. If the user decides to authenticate with Game Center, then I want to change gameCenterButton's state (un-grey and enable). In my GameKitHelper class I have these:
func authenticateLocalPlayer() {
GKLocalPlayer.local.authenticateHandler =
{ (viewController, error) in
self.gameCenterEnabled = false
if viewController != nil {
self.authenticationViewController = viewController
NotificationCenter.default.post(name: NSNotification.Name(
GameKitHelper.PresentAuthenticationViewController),
object: self)
} else if GKLocalPlayer.local.isAuthenticated {
self.gameCenterEnabled = true
}
}
}
extension GameKitHelper: GKGameCenterControllerDelegate {
func gameCenterViewControllerDidFinish(_ gameCenterViewController: GKGameCenterViewController) {
gameCenterViewController.dismiss(animated: true, completion: nil)
}
}
In VC1 I have this:
#IBOutlet weak var gameCenterButton: UIButton!
#IBAction func gameCenter(_ sender: UIButton) {
GameKitHelper.sharedInstance.showGKGameCenterViewController(viewController: self)
}
I'm thinking that inside of extension GameKitHelper I can do ...
if gameCenterEnabled == true {
gameCenterButton.isEnabled = true // How do I allow for this?
gameCenterButton.alpha = 1 // How do I allow for this?
How do I allow gameCenterButton state to change outside of it's class. Is there something I need to do in AppDelegate?
Put var gameCenterEnabled = false outside (above) of your GameKitHelper class, thus making it "global". You will likely be prompted to remove the self. in self.gameCenterEnabled = false and in self.gameCenterEnabled = true. Do so.
Now, you can reference gameCenterEnabled in VC1's class and change gameCenterButton's state like this:
// code to determine gameCenterButton's state based on gameCenterEnabled's status
if gameCenterEnabled == false {
self.gameCenterButton.isEnabled = false
self.gameCenterButton.alpha = 0.37
} else {
self.gameCenterButton.isEnabled = true
self.gameCenterButton.alpha = 1
}

how to change dock icon using setContentView to display one big character in mac os x

I want to change the dock icon of an app into one big character like an "A" or "B" for example using swift or objective C
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var dockView: NSView!
#IBOutlet weak var dockText: NSTextField!
let appDockTile = NSApplication.sharedApplication().dockTile
func prepareDock(){
appDockTile.contentView = dockView
appDockTile.display()
}
func changeText(){
dockText.stringValue = "B"
appDockTile.display()
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
prepareDock()
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
#IBAction func btnChangeText(sender: AnyObject) {
changeText()
}
}
my two cents for OSX swift 4.x:
(make it flash..)
...
self.HeartBeatTimer = Timer.scheduledTimer(withTimeInterval: DELTA_T, repeats: true, block: { (t: Timer) in
let name = colored ? "heartbeat" : "heartbeat_red"
let image = NSImage(named: name)
let appDockTile = NSApplication.shared.dockTile
appDockTile.contentView = NSImageView(image: image!)
appDockTile.display()
}

Swift unique property in multiple instances

I know that theoretically it's possible to create multiple instances of the same class with a property that would have a different value for each instance.
The thing is, I can't make it happen.
Each time I'm creating a new instance, it gets the property's value of the other instances, and when I'm changing one value for an instance, it changes the other's too.
So my guess is that I'm doing something wrong (obviously), like accessing the class property value instead of the instance property value... Here's the code.
class CustomUIImageView: UIImageView {
var someParameter: Bool = false // This is the property I want to be different in each version of the instance.
}
class ClassSiege: UIViewController, UIGestureRecognizerDelegate {
var myView: CustomUIImageView! //the instance declaration.
// I use this gesture recognizer to find out the value of the instance I'm tapping on.
func handleTap (sender: UITapGestureRecognizer) {
print("value of someParameter \(self.myView.someParameter)")
}
func handlePan(recognizer: UIPanGestureRecognizer) {
let iv: UIView! = recognizer.view
let translation = recognizer.translationInView(self.view)
iv.center.x += translation.x
iv.center.y += translation.y
recognizer.setTranslation(CGPointZero, inView: self.view)
var centerBoardX = BlackBoard.center.x // 'Blackboard' is a fixed image on the screen.
var centerBoardY = BlackBoard.center.y
var centerRondX = iv.center.x
var centerRondY = iv.center.y
if centerRondY - centerBoardY < 100 {
self.myView.someParameter = true // If the distance between myView and the blackboard is under 100 I want the instance's property to become true.
} else {
self.myView.someParameter = false // On the other hand, if the distance is greater than 100, I want it to be false.
}
}
// When the user pushes a button, it triggers this method that creates a new instance of myView and add it to the screen.
#IBAction func showContent(sender: AnyObject) {
// some code...
// Here I'm creating the instance of the view and I give it the gesture recognizer parameters. I don't think that relevant to the issue, so I'm not adding the code.
}
}
So clearly that's not the good way to do it, but what's wrong, and how can it be solved?
Basing my answer on your related question.
If what you want to achieve is initializing a property with a value that you provide, just add a new parameter to the initializer. If for instance you are using the initializer with a CGRect passed in, then you can implement an initializer like this:
class CustomUIImageView : UIImageView {
let someParameter : Bool
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(frame: CGRect, someParameter: Bool) {
self.someParameter = someParameter
super.init(frame: frame)
}
}
I hope that this is what you are looking for - let me know otherwise.
I've found the solution, and if you've been facing the same issu, here's how to deal with it.
The secret is to downcast the recognizer.view to take the parameter of the subclass CustomUIImageView.
here's how :
func handleTap (sender: UITapGestureRecognizer) {
println("value of someParameter \(self.myView.someParameter)") //I use this gesture recognizer to find out the value of the instance I'm tapping on.
}
func handlePan(recognizer:UIPanGestureRecognizer) {
let iv : UIView! = recognizer.view
let translation = recognizer.translationInView(self.view)
iv.center.x += translation.x
iv.center.y += translation.y
recognizer.setTranslation(CGPointZero, inView: self.view)
var centerBoardX = BlackBoard.center.x //blackboard is a fixed image on the screen.
var centerBoardY = BlackBoard.center.y
var centerRondX = iv.center.x
var centerRondY = iv.center.y
var myParameter = recognizer.view as CustomUIImageView //<- this is the key point. Downcasting let you access the custom subclass parameters of the object that is currently moved
if centerRondY - centerBoardY < 100 {
myParameter.someParameter = true //so now I'm really changing the parameter's value inside the object rather than changing a global var like I did before.
} else {
myParameter.someParameter = false
}
}
//when user pushes a button, it triggers this func that creates a new instance of myView and add it to the screen.
#IBAction func showContent(sender: AnyObject) {
some code...
//here I'm creating the instance of the view and I give it the gesture recognizer parameters. I don't think that relevant to the issue, so I'm not adding the code.
}