What is the actual meaning of " ! " prefix in Swift? - swift

I want to know about prefix !. I have created an app, and it has tableView. And I have used setEditing:animated property for editing a tableView, it allows multiple selection. When user start selecting? We need to cancel segue operations. Of course we need to override shouldPerformSegueWithIdentifier method. Here's my code
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
return !editing
}
Firstly I've tried to use return editing. Xcode does not gave me any errors even run time errors. Everything seems to works just fine. But segues are still works. And then I've tried to use with prefix return !editing. Works perfect! What's the actual meaning of this prefix ! ?
Thanks

The ! operator is the logical NOT of a boolean value; i.e. !true becomes false, !false becomes true.

Related

Text label not updating on screen, even though it shows up on `print()`

I'm writing an application which has an NSSplitViewController as the main View-Controller. I have it linked-up so that clicking a button in the menubar will trigger an #IBAction which then calls a function in one of the sub-View-Controllers.
if let board = storyboard {
let imageController = board.instantiateController(withIdentifier: "VC_image_ID") as! VC_image
imageController.viewDidAppear() // necessary or else I'll get an "Unexpectedly found nil" later on
DispatchQueue.global().async{imageController.processImage(path)} // path variable was set earlier in the code, but not shown here
}
Inside the sub-View-Controller (named VC_image), I'm trying to change the stringValue of a label by using the following code:
public func processImage(_ path: String) {
DispatchQueue.main.async {
self.imageText.stringValue = path
print(self.imageText.stringValue)
}
}
Although the imageText.stringValue actually seems to have changed based on the fact that it prints the updated text (through the console), the text in the window never changes. Why is this happening? The reason is probably really obvious to professionals, but I'm still an amateur and can't figure it out. Thanks.

How can I limit a text field to only intaking Double values

So essentially I'm creating a calculator type app, in which I only want to intake numbers, decimals, and the negative sign. I'm fairly new to Xcode and swift so I wouldn't consider my knowledge extensive when it comes to knowing how to handle these sorts of issues.
Here is my current attempt at a solution
let v = Double(inputOne.text!)!
(inputOne. is the associated text field)
This works well in my algorithm when everything is inputted as it should be, however when inputting anything other than a valid double I receive "Fatal error: Unexpectedly found nil while unwrapping an Optional value", and the app crashes.
I figured someone may have already come up with a creative solution to this problem or that there may be some command in Xcode that limits text fields in this way, however I am new to Xcode and unaware of such things if they exist. Maybe there is some way I can implement an error message that occurs whenever something other than a valid double is inputted without crashing the app? Any creative solutions would be appreciated.
You can use a UITextView as your input field (if you want a one-line input, use a textField). Then, simply set your ViewController as the textView's delegate -inside your ViewController add the following line (and don't forget to inherit UITextViewDelegate):
textView.delegate = self
Essentially, what this does is allow the ViewController to take ownership of some of the textView's functionalities. In this case, we are interested in filtering the user input and for that you can use the following function:
/// Intercept whatever character the user is typing on the keyboard
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// If the user presses "enter", handle it the way you want
guard text.rangeOfCharacter(from: CharacterSet.newlines) == nil else {
// Handle new line
}
// If character is a digit, a dot, or a dash, allow input, else reject it.
if text == "-" || text.rangeOfCharacter(from: CharacterSet.decimalDigits) != nil || text == "." {
return true
} else {
return false
}
}

function doesn't return true unless I call it once before I need it

I have a function called iCloudIsOn() which checks whether a user has opted to use iCloud with the app by comparing the value of a UserDefaults key with a predefined one, and then I am using this on my initial View Controller to sync iCloud and implement pull to refresh, but only if the user is using iCloud, otherwise this code is not needed.
What's strange however is that the function only returns true if I call it right before I need to use it, even with just a print(iCloudIsOn())
The function itself looks like this:
func iCloudIsOn() -> Bool {
if UserDefaults.standard.url(forKey: "UDDocumentsPath") == iCloudPath { return true }
else { return false }
}
Then under viewDidLoad of my initial vc:
override func viewDidLoad() {
super.viewDidLoad()
if iCloudIsOn() {
// sync iCloud
}
}
This will not work however and iCloudIsOn() will return false at that time unless I add a print(iCloudIsOn()) before if iCloudIsOn() { // sync iCloud }
I tried asking iCloudIsOn to print both the value of the UserDefaults key and iCloudPath every time it is called and they are always identical: file:///private/var/mobile/Library/Mobile%20Documents/iCloud~cristian~thrive-storage/Documents/
So there isn't something in my code changing the value for one of them at some point (the value is printed before the return).
Any idea on why this is happening? Is it something to do with how UD works or am I missing something else? I find it a little strange, but I'm sure I'm just making a mistake somewhere.
Thanks in advance.
The problem ended up being that UserDefaults stored a value without a "/" the first time yet when being compared to the original URL, iCloudPath, iCloudPath had the original "/".
UserDefaults.standard.url(forKey: "UDDocumentsPath") = someURL
iCloudPath = someURL/
This would only happen on the first go around. Workaround is to cover both bases as you don't know which one you are on, especially if you are doing multiple checks in one session of the application.
if UserDefaults.standard.url(forKey: "UDDocumentsPath") == iCloudPath || UserDefaults.standard.url(forKey: "UDDocumentsPath").appendPathComponent("/") == iCloudPath
Technically, though, this is odd and unexpected behavior.

Should I use a For - in loop in swift to set field value

I have created an app with a codeable array in Swift. I have a boolean field to show which item in my list is the active record. If I choose another item in my list to make active (true) I would like to mark all other records as false. I was wondering if using a for-in loop would be the proper way to do this?
I have this code to activate the button but have been told that is not the proper way to do it.
#IBAction func activateButtonTapped(_ sender: UIButton) {
activateButton.isSelected = !activateButton.isSelected
updateSaveButtonState()
}
Any suggestions would be appreciated.
A for-loop would be the most naive (simple) way to do this, but not the most performant as the number of button increases (you're bound by O(n) time).
If one and only one button can be active at a time then you're better off using another variable to reference the currently active button. Your code would instead look like this:
private weak var activeButton: UIButton?
#IBAction func activateButtonTapped(_ sender: UIButton) {
activeButton?.isSelected = false
sender.isSelected = true
activeButton = sender
}
This ensures O(1) time.
If you want multiple buttons active at once, you can use an array of active buttons, which you'd loop over to deactivate. In that case, you still have a worst case O(n) time complexity, but you're almost always going to be looping over a smaller subset of the buttons.
Yes, a for in loop would be perfect for this. You could set all the buttons selection status to false and then set the one you just activated to true.
for button in buttons {
button.isSelected = false
}
activateButton.isSelected = true
Or you could check in the loop if the button being tapped is the one that in the loop.
for button in buttons {
button.isSelected = button == activateButton
}

Swift 2.2: Optional Binding in a function

Heys guys,
I am pretty new into programming and therefore I've followed I course on Udemy to teach me Swift 2.2.
For learning purpose I have been trying to program a BMI-calculator where I have a textfield (which just displays the value) and a slider where I can put my weight in kg. After dragging the slider the value is visible in the textfield. I cannot put a value into the textfield so that it is displayed on the slider!
The same textfield-slider relation is used with the height in cm. Now I created an IBAction the bring my kgSlider.value into my kgField.text and it looks like this:
#IBAction func kgSet(sender: AnyObject) {
kgField.text! = String(Int(kgSlider.value))
}
Thats works fine but I unwrapped (like the teacher in the course) without knowing, if there really is a value. Okay, I know in this case that there will be a value, but I would like to go more real and therefore I tried to use an Optional-Binding to find out, if there is a value instead of directly unwrap it.
Therefore I used the cm.Field and the cm.Slider in my code but it doesn't work for now and I don't know why. The code is the following:
#IBAction func cmSet(sender: AnyObject) {
if let tempCm = String(Int(cmSlider.value)) as String! {
cmField.text = tempCm
}
}
So I created the constant called tempCM which will got the value from the cmSlider, if there is a value. Therefore I casted the cmSlider.value like in the other IBAction into an Int and then into a String. If there is the value it will carry it into the cmField.text. This didn't work, therefore I tried to use the "as String!" statement but know I get always 0 instead of the correct value.
So what am I doing wrong there?
So, this should compile fine and provide you with your desired result.
#IBAction func cmSet(sender: AnyObject) {
if let tempCm = String(Int(cmSlider.value)) {
cmField.text = tempCm
}
}
You could also try this
cmField.text = String(Int(cmSlider.value)) ?? " "
in the second example, you are using the optional operator to say if you can convert this to an Int then that Int to a string set the cmField.text property to its value, otherwise use a blank space as the default value.