Swift: Variable values don't carry over to didSet - swift

This is my first project in Swift so please bear with me.
punkteLimit should be initialized with value 30. The value of the variable as well as a label should be updated everytime a slider value is changed.
var punkteLimit: Int = 30
#IBAction func sliderPunktelimitChanged(_ value: Float) {
punkteLimit = Int(value)
labelPunktelimit.setText("Punkte-Limit: \(punkteLimit)")
}
This seems to work fine. The label updates correctly, i.e. when I change the slider to 28, it says "Punkte-Limit: 28". However, punkteLimit is stuck at the initial value of 30 in the following part (the same is true for considerPunktelimit but the solution should be identical). The haptic feedback will be triggered at gesamtPunkte == 30 regardless of the changes above.
I use a button that performs gesamtPunkte += 1 to adjust the value, if it matters.
var gesamtPunkte: Int = 0 {
didSet {
if gesamtPunkte == punkteLimit && considerPunktelimit == true {
WKInterfaceDevice.current().play(WKHapticType.stop)
}
...
}
}
I'm not exactly sure where to go from here.
Help is much appreciated.

I solved the problem by moving the variable(s) in question outside of the InterfaceController class (making them global?). I have read mixed opinion about this approach, if anyone wants to comment on why it didn't work inside of the class and whether or not there are problems with making them global, feel free to.

Related

Angular Ag Grid - Has anyone figured out a way to wait for a cell node update to happen and THEN fire a function, like a callback?

I am utilizing cellChanged.node.setDataValue(fieldChanged, oldValue) inside of the (cellValueChanged) event emitter, and I'm having trouble figuring out how to call a function once the setDataValue function has finished executing. I need to do this to do a check to see if a user has the permission to update a cell.
Here is the full code that checks:
if(this.showPaywallNotification) {
// Okay, so the budget is above what we allow HOWEVER...
if(budget > BUDGET_AMOUNT) {
this.showPaywallNotification = false;
cellChanged.node.setDataValue(fieldChanged, oldValue)
// Note: This timeout is in place to prevent the infinite updating bug
// This is problematic because if the user changes the cells fast enough, they can get around the paywall. If I change the timeout to be smaller, the resulting change triggers the update, which ends up creating an infinite loop of updates.
setTimeout(() => {
this.showPaywallNotification = true;
}, 230)
}
}
Is there a way I can replace my setTimeout() function with something better that can always ensure the user can't get around my paywall by just updating the cell faster than the timeout can execute?
You don't have to do polling. setDataValue is a not an async function.
Also, onCellValueChanged won't get called again if you call node.setDataValue.
Have a look at this plunk: Cell Editing - Revert to old value. Try updating any Age value to negative.
onCellValueChanged($event) {
if ($event.colDef.field === 'age' && $event.newValue < 0) {
// debugger
$event.node.setDataValue('age', $event.oldValue);
console.log('value reverted');
}
}
Let me know if something is not clear, or this is not sufficient.

Cannot override prefersHomeIndicatorAutoHidden() method

I use this line of code in an app with XCode 10 in order to dim the home indicator on iPhone X and associated edgeless apple devices.
override func prefersHomeIndicatorAutoHidden() -> Bool {
return true
}
Now the funny thing is, I have an exact copy of this app and on one copy the code works, whilst on the over the code does not compile:
Method does not override any method from its superclass
Indeed when I start typing "prefers..." , prefersHomeIndicatorAutoHidden appears as a read-only property on the one hand, whilst it does appear as a method on the other hand, and gets the override prefix by default.
Thanks for taking the time,
Best
EDIT WITH SOLUTIONS thanks to #inokey
Solution 1: check deployment (starting i0S 12, prefersHomeIndicatorAutoHidden cannot be overridden as a method)
Solution 2 :
override var prefersHomeIndicatorAutoHidden : Bool { return true }
I assume that default deploy target in Xcode 10 is 12 and your previous project is 11 or 10, so it just reflects the changes in API.
Changes in SDK indicate that this was changed
in Xcode 10 = Swift 4.2 (Sep 2018)
Just use the code below:
override var prefersHomeIndicatorAutoHidden: Bool { return true }

How to write if and else statement more elegantly in Swift

I'm having a bit of a brain fart in Swift and I know this code could be written better. Basically what it is, I have two images and I check if a value is over 3 to show an image and hide the other.
currently I have it like this
let greaterThanThree = value > 3
image1.isHidden = greaterThanThree
image2.isHidden = !greaterThanThree
But I feel like there is a more elegant way to write this.
I'd write it like this:
image1.isHidden = value > 3
image2.isHidden = !image1.isHidden
Anything shorter than that is just code golfing.
There seems to be a rule here that exactly one of these two views should be visible at all times. If so, I'd create, as part of my view controller's viewDidLoad, an instance of this struct:
struct AlternateViews {
let views : [UIView]
init(_ v1:UIView, _ v2:UIView) {
views = [v1,v2]
}
func hide(first:Bool) {
views[0].isHidden = first
views[1].isHidden = !first
}
}
let alternateViews = AlternateViews(image1, image2)
Okay, that's a lot of work to set up initially, but the result is that later you can just say
self.alternateViews.hide(first: value > 3)
The struct is acting as a tiny state machine, making sure that your view controller's views remain in a coherent state. This technique of moving the rules for state into utility structs attached to your view controller is recommended in a WWDC 2016 video and I've been making a lot of use of it ever since.
If you have more pairs of alternating views, just make and maintain more instances of the struct.
(If the rule that I've assumed is not quite the real rule, make a struct that does express the real rule.)
You can do this:
(image1.isHidden, image2.isHidden) = (value > 3) ? (true, false) : (false, true)
Basically if the value is greater than 3, the first image will be hidden and the second one won't. Otherwise, the second image will be hidden and the first one will not.

How to setup printing in cocoa, swift?

I have made printing functionality for custom NSView of NSPopover by the assigning the following action to button for this NSView in mainController:
#IBOutlet var plasmidMapIBOutlet: PlasmidMapView!
#IBAction func actionPrintfMap(sender: AnyObject)
{
plasmidMapIBOutlet.print(sender)
}
It is working, but the print window has no option for Paper Size and Orientation, see screenshot below.
What should I do to get these options in the print window?
And, how to make the NSView fitting to the printable area? Now it is not fitting.
I have figured out some moments, but not completely. So, I can setup the printing by the following code
#IBAction func actionPrintMap(sender: AnyObject)
{
let printInfo = NSPrintInfo.sharedPrintInfo()
let operation: NSPrintOperation = NSPrintOperation(view: plasmidMapIBOutlet, printInfo: printInfo)
operation.printPanel.options = NSPrintPanelOptions.ShowsPaperSize
operation.printPanel.options = NSPrintPanelOptions.ShowsOrientation
operation.runOperation()
//plasmidMapIBOutlet.print(sender)
}
But, I still have problem. From the code above I can get only orientation (the last, ShowsOrientation), but not both PaperSize and Orientation. How can I manage both ShowsPaperSize and ShowsOrientation?
Finally I have found the answer which is simple to write but it is not really obvious from apple documentation.
operation.printPanel.options.insert(NSPrintPanelOptions.showsPaperSize)
operation.printPanel.options.insert(NSPrintPanelOptions.showsOrientation)
The problem in the code originally posted is that options is being assigned twice, so the first value assigned, ShowsPaperSize is overwritten by the value ShowsOrientation. That's why you only see the ShowsOrientation option in the dialog.
By using multiple insert operations, you are adding options rather than overwriting each time. You can also do it this way which I think reads better:
operation.printPanel.options.insert([.showsPaperSize, .showsOrientation])
And finally, it also works to "set" the options, and by supplying the existing options as the first array value, you achieve the affect of appending:
operation.printPanel.options = [
operation.printPanel.options,
.showsPaperSize,
.showsOrientation
]
(The first array element operation.printPanel.options means that the old options are supplied in the list of new options.)

Best way to count length of UITextInput text value in Swift?

I have two UITextInput controls that I want to count the number of characters in.
For context, I have two inputs: one for email address and one for password. I also have a “Login” button. The button is inactive by default, but as soon as at least one character is entered into both inputs, I’ll programatically enable the button. This is to prevent login attempts until the user has entered a value in both fields.
So far, I’m using this approach:
if count(emailInput.text) > 0 && count(passwordInput.text) > 0 {
// Enable button
} else {
// Disable button
}
Is using the count() function acceptable? Or is there a better way? As I recall there are some gotchas with checking the length of strings in iOS/Swift.
For me personally the following code has worked fine in past.
if (!emailInput.text.isEmpty && !passwordInput.text.isEmpty) {
// enable button
} else {
// disable button
}
if((emailInput.text!.characters.count) > 0 && (passwordInput.text!.characters.count) > 0) {
// Enable button
} else {
// Disable button
}
Swift 4
emailInput.text!.count
Swift 2
self.emailInput.text!.characters.count
but if you need to do something more elegant you can create an extension like this
Nowadays, after putting count directly on text property my guess is to use this directly without extension, but if you like to isolate this sort of things, go ahead!.
extension UITextField {
var count:Int {
get{
return emailInput.text?.count ?? 0
}
}
}