How can I get the opposite value of a Bool in Swift? - ios

My specific case is I am trying to toggle the nav bar hidden and showing.
let navHidden = !self.navigationController?.navigationBarHidden
self.navigationController?.setNavigationBarHidden(navHidden!, animated: true)
Is not working for me like it normally would in Obj-C.

The exclamation point is on the wrong side of the boolean. The way you've written it would indicate that the boolean could be nil. You want !navHidden.

navHidden! is to make sure this is not optional. !navHidden is the correct way to do that.
From Apple's book.
Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value.

navHidden is an optional. And you explictely unwrap that optional (which means you get a crash if navHidden is nil). Clearly something is wrong here. I suggest
if let navController = self.navigationController {
let navHidden = navController.navigationBarHidden
navController.setNavigationBarHidden (!navHidden, animated:true)
}

Related

Swift Optional Unwrapping Syntax

I am relatively new to Swift. Whilst doing some reading, I found the following sample code for programmatically creating a UINavigationController in the app delegate:
let mainVC = ViewController.init()
let nc = UINavigationController.init(rootViewController: mainVC)
self.window = UIWindow.init(frame: UIScreen.main.bounds)
self.window!.rootViewController = nc
self.window?.makeKeyAndVisible()
My question relates to the last line "self.window?.makeKeyAndVisible()". I would have expected it to use ! to unwrap self.window similar to the line above, but instead ? was used. I tried this code with both the ! and the ? and in both cases the app compiled and ran successfully.
What I would like to know is which punctuation (! or ?) is the best to use and why please?
If you use ? to unwrap an object if the object is null the app won't crash.(? notation will skip unwrapping, given the object is nil)
If you use ! to unwrap an object and if the object is null the app will crash. (you use ! when you expect the object, that it will never be nil).
Consider the following code snippet:
var tentativeVar: Array<Any>?
tentativeVar = Array()
tentativeVar?.append("FirstElement")
Now if you print the tentativeVar with optional unwrapping(using ?), you will get the following results.
(lldb) po tentativeVar?[0]
Optional<Any>
- some : "FirstElement"
For the same if you force unwrap the variable you can directly get the object omitting the unnecessary optional data.
(lldb) po tentativeVar![0]
"FirstElement"
For the same object if you don't initialise the object and try to access an element in it the following things will happen.
print("\(tentativeVar?[0])") //prints nil
print("\(tentativeVar![0])") //Crashes the app, trying to unwrap nil object.
What you are seeing is optional chaining. It differs slightly from optional unwrapping, since you aren't always assigning the result to a variable.
self.window!.rootViewController = nc will crash if window is nil.
self.window?.rootViewController = nc will do nothing at all if window is nil.
There's no benefit to force unwrapping the chain if you're not assigning it to a variable, so it's generally better to use ? unless you want your app to crash on a nil (if you do want that, I would suggest instead implementing your own error handling that reports some details on what went wrong).

IF Statement Incorrectly Evaluating to True when Using Optional Values in Swift

I have set up my view controllers so that they send a notification once their -viewDidLoad method is about to return. For example:
class MyViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
//Do Stuff
var notificationCenter = NSNotificationCenter.defaultCenter();
notificationCenter.postNotificationName("AViewControllerDidLoadNotification", object: self);
}
}
My AppDelegate class is listening for this notification and implementing the method shown in this picture.
In case the picture isn't loading, the method takes the notification sent by the view controllers as it's only argument and then tests whether the UIViewController's title property has a non-nil value. If the title property is non-nil it logs the title.
However, as you can see in the debugger panel, the title property of the view controller is nil and the if statement is still evaluating to true.
I am admittedly new to optional values. But I have recreated this situation in a swift playground and the if statement evaluates to false. Any ideas?
You've gotten yourself into rather an odd situation with your very peculiar use of the expression notification.object?.title, because notification.object is not, of itself, a UIViewController. It is an AnyObject.
Now, an AnyObject has no known properties, so it has no title and your expression, it would seem, should not even compile. But, by a special dispensation coming from certain oddities of Objective-C, you are in fact allowed to ask about an AnyObject's properties anyway. But when you do, the result is itself an Optional, because no such property might exist.
Thus, you are actually testing, not the value of a view controller's title property, but whether this unknown object has a title property in the first place; and if in fact it does have a title property at all, the value of that title property is double-wrapped inside that Optional.
To see this clearly, just test this (silly) code:
let n = NSNotification(name: "Howdy", object: "Hi")
let t = n.object?.title
Look at what type t is. It is not a String?; it is a String??. That's your double-wrapped Optional. This means that it would be an Optional-wrapping-a-String in case this object turns out to have a title property, but just in case, that value has itself been wrapped in an Optional.
Thus, your test doesn't do what you want it to do. To do what you want to do, just speak much more plainly and simply. You need to cast the object to a UIViewController first, and then examine its title. Like this:
func aViewControllerDidLoad(notification:NSNotification) {
if let vc = notification.object as? UIViewController {
if vc.title != nil {
// ...
}
}
}

Access Optional property in multiple function for calculations - Swift

I have a NSObject Subclass. Say CityWalks
class CityWalks{
var totalCount:Int?
}
How do I use this property further? Should I check the nil coalescing every time this value is accessed.
example:
let aObject =
say in one fucntion (function1()) , I need to access this value, then it would like (aObject!.totalCount ?? 0)
func function1(){
...Some Access code for the object....
(aObject!.totalCount ?? 0)
}
Similarly in every other function(function2()) , I will have to write the same code.
func function2(){
...Some Access code for the object....
(aObject!.totalCount ?? 0)
}
So, what could be a better approach for such field, considering this property might receive a value from server or might not.
If you have a default value for this property just assign this value as default value.
class YourClass {
var totalCount = 0
}
I'd recommend you avoid using an optional value if it's possible. Because optional values its a first place when you can get an error.
As stated in the comments and the other answer using an optional is not really optimal in your case. It seems like you might as well use a default value of 0.
However, to clarify, you have to check the value when unwrapping the optional.
Sometimes it's possible to pass an optional to UIElement etc and then you don't really need to do anything with them
There are pretty ways of checking for nil in optional values built into swift so you can build pretty neat code even though you work with optional.
Look in to guard let and if let if you want to know more about unwrapping values safely.
if let
if let totalWalks = aObject?.totalCount {
//operate on totalWalks
}
guard
guard let totalWalks = aObject?.totalCount else { return }
//operate on totalWalks
There are also cases where you will want to call a function on an optional value and in this case you can do so with ?
aObject?.doSomething()
Any return values this function might have will now be wrapped in an optional and you might have to unwrap them as well with an if let or guard
When working with optionals you should try to avoid forcing the unwrap with ! as even though you at the moment know that the value is not null that might after a change in the code not be true anymore.

Why is Apple using this "if let" code? [duplicate]

This question already has answers here:
Why would I use if and let together, instead of just checking if the original variable is nil? (Swift)
(2 answers)
Closed 7 years ago.
Apple has this segment of code on one of their sample projects:
let existingImage = cache.objectForKey(documentIdentifier) as? UIImage
if let existingImage = existingImage where cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage
}
why is apple using this if let? Isn't more logical to simply use
if cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage!
}
???!!
If you use
let existingImage = cache.objectForKey(documentIdentifier) as? UIImage
if let existingImage = existingImage where cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage
}
This will make sure that if existingImage == nil,it will not
execute return existingImage.
Besides,if let also unwrap existingImage from UIImage? to
UIImage
As Abhinav mentioned above, Apple introduced a new type called optional type with Swift.
What does optional mean?
Short and Sweet, "Optional types are types, which can contain a value of a particular data type or nil".
You can read more about optionals and their advantages here : swift-optionals-made-simple
Now whenever you want to make use of value present in an optional type, first you need to check what it contains i.e. does it contains a proper value or it contains nil. This process is called optional unwrapping.
Now there are two types of unwrapping,
Forced unwrapping : If you're sure that an optional will have an value all the time, you can then unwrap the value present in the optional type using "!" mark. This is force unwrapping.
The one more way is to use if let expression, this is safe unwrapping, here you'll check in your program that, if optional has a value you will do something with it; if it doesn't contain value you'd do something else. A simple example is this (You can test this in play ground:
func printUnwrappedOptional (opt:String?) {
if let optionalValue = opt { //here we try to assign opt value to optionalValue constant, if assignment is successful control enters if block
println(optionalValue) // This will be executed only if optionalValue had some value
}
else {
println("nil")
}}
var str1:String? = "Hello World" //Declaring an optional type of string and assigning it with a value
var str2:String? //Declaring an optional type of string and not assigning any value, it defaults to nil
printUnwrappedOptional(str1) // prints "Hello World"
printUnwrappedOptional(str2) // prints "nil"
Hope this clears your question, read through the link given above it'll be more clear to you. Hope this helps. :)
Edit: In Swift 2.0, Apple introduced "guard" statements, once you're good with optionals go through this link, guard statement in swift 2. This is another way to deal with optionals.
Using if let, makes sure that the object (existingImage) is not nil, and it unwraps it automatically, so you are sure inside the if that the condition is true, and the object is not nil, and you can use it without unwrap it !
With Swift, Apple has introduced a new concept/type - Optional Type. I think you better go through Apple Documentation.
Swift also introduces optional types, which handle the absence of a
value. Optionals say either “there is a value, and it equals x” or
“there isn’t a value at all”. Optionals are similar to using nil with
pointers in Objective-C, but they work for any type, not just classes.
Optionals are safer and more expressive than nil pointers in
Objective-C and are at the heart of many of Swift’s most powerful
features.
existingImage is an optional (as? UIImage) and therefor needs to be unwrapped before used, otherwise there would be a compiler error. What you are doing is called forced unwrapping via !. Your program will crash, if existingImage == nil and is therefor only viable, if you are absolutely sure, that existingImage can't be nil
if let and optional types is more help where is there is changes to get nil values to void crashes and unwanted code executions.
In Swift 2.0,
guard
will help us lot where our intention is clear not to execute the rest of the code if that particular condition is not satisfied

Setting UITableView editing in Swift

I'm just trying to perform a very simple system API call, setting a UITableView to editing.
However I have no idea what the compiler is complaining about:
let isEditing = self.tableView?.editing
self.tableView?.setEditing(!isEditing, animated: true)
Error Message:
Optional type '_' cannot be used as a boolean; test for '!= nil' instead
Thankful for any advice!
You can just unwrap optional and use !isEditing!, but I believe this approach will be much safer:
if let isEditing = self.tableView?.editing {
self.tableView?.setEditing(!isEditing, animated: true)
}
The question mark next to tableView means that if the property tableView is nil then tableView?.editing must return nil. This results in an optional Bool for the statement let isEditing = self.tableView?.editing
You can fix this using an exclamation mark instead of a question mark (if you are sure 100% that tableView exists), or more cleaner
if let isEditing = self.tableView?.editing {
//If isEditing exists, than self.tableView exists for sure! If it doesn't
//the only possible reason is that tableView is nil so there is no point
//to try to call setEditing on a nil object. If isEditing is nil, the if
//condition will fail and you will not get in this scope.
self.tableView!.setEditing(!isEditing, animated: true)
}
Your isEditing variable type is Bool optional so apart true and false , it may have nil value as well and thats because of question mark used in self.tableView?.editing. To make it work you will need to force unwrap its value by using ! in either self.tableView!.editing or self.tableView?.setEditing(!isEditing!, animated: true).
Be aware that force unwrapping may be harmful and lead to runtime exceptions, so try avoiding it by using optional unwrapping

Resources