Setting UITableView editing in Swift - ios

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

Related

Property is accessed but result is unused

I saw there another similar one to my question but that was very old! , So I have an UIActivityIndicatorView but when i try to call the .hidesWhenStopped it just warns Property is accessed but result is unused for no reason?
What could be the problem?
I tried under viewDidLoad too but same :(
This is a part of my code:
Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { [self] _ in
monitorimiTableView.reloadData()
configureTableView()
loaderMonitorimi.hidesWhenStopped // Property is accessed but result is unused
}
You need to assign a value to the property:
loaderMonitorimi.hidesWhenStopped = true
(or false if you don't want to hide it)
If you just write loaderMonitorimi.hidesWhenStopped without any assignment, this expression will result in the boolean value stored in the hidesWhenStopped property, but the result of the expression is not used, hence the warning.

collectionView.indexPathsForSelectedItems.contains(x)

I am trying to run collectionView.selectItem(at: indexPath, animated: false, scrollPosition: []) if if(!collectionView.indexPathsForSelectedItems?.contains(x)) returns true. But I can't seem to get it to work.
I thought it had something to do with optionals, but it doesn't seem to.
I have tried if let, ? ?? ! etc. I have created an optional index_path object and still cannot get it to work.
You can't have an optional Bool? as the only member of an if condition. That's because the compiler (with good reason) refuses to infer what it must do when it gets a nil value.
You have several ways to solve this, the important thing is: make sure you're handling the nil case the way you intend it to.
From a quick look at the documentation we learn that indexPathsForSelectedItems returns nil if there are no selected items. In that case your condition must yield a true value, because when there are no selected items, x is most certainly not contained in the array of selected values.
So, a first solution might be to tell the compiler to treat a nil value from indexPathsForSelectedItems as an empty array, which seems quite reasonable: if there are no selected items the array that represents the selected items' indexPath should be empty:
// solution 1
if !(collectionView.indexPathsForSelectedItems ?? []).contains(x) {
// select item..
}
You have a second way to solve this if you consider that you can't have an optional Bool? inside an if condition, but you can always compare a Bool? with a Bool and thus explicitly tell the compiler the only case among the three you are interested in:
let isXSelected = collectionView.indexPathsForSelectedItems?.contains(x)
isXSelected returns nil → no items selected, i should select x
isXSelected returns true → nothing to do
isXSelected returns false → i should select x
You want to execute the "select x" code in both case 1 and 3, so you want to check if isXSelected is not true. In conclusion:
// solution 2
if collectionView.indexPathsForSelectedItems?.contains(x) != true {
// select item..
}
Result of
collectionView.indexPathsForSelectedItems?.contains(x)
is optional bool value: Bool?. Swift does not allow implicit cast to Bool type. To solve it, create unwrapping of optional array to non optional array indexPathsForSelectedItems :
if !(collectionView.indexPathsForSelectedItems?.contains(x) ?? false) {
//TODO:select item
}

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.

How to better understand optionals

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "segueone")
{
let cellIndexPath = self.tableView!.indexPathForCell(sender as UITableViewCell)
if let unwrappedCellindexPath = cellIndexPath
{
var nextVC = (segue.destinationViewController as TableTwo)
nextVC.items = items[unwrappedCellindexPath.row]
}
}
}
With this piece of code, I have a few questions regarding the optionals. I recently read-through the apple developer web document as well as a few personal explanations of optionals but still have question.
Anyways,
in the line
let cellIndexPath = self.tableView!.indexPathForCell(sender as UITableViewCell)
Is this statement only considered to be an optional because a user may not select one of the cells in my table? And with that, since I know that as long as a user wants to continue through the app, they must select a cell, I can place the exclamation point in to notify the compiler that this cell does in deed have a value(index path)?
Why does the exclamation point go after "self.tableview" and not after "sender as UITableView) in parentheses?
If my assuming is correct, I am able to use the if let syntax because I have an optional in the previous line of code?
let cellIndexPath = self.tableView!.indexPathForCell(sender as UITableViewCell)
Uses an exclamation point after tableView, because self.tableView! may not have been set (it may be nil).
It is an optional because it has the option to have a value, and it also has the option to be nil. Variables that are not optionals cannot be nil, they have to have a value.
The exclamation point goes after tableView because that is the optional which could be nil. If it went after .indexPathForCell(sender as UITableViewCell), that would imply that the value returned could be nil.
You can use the if let syntax because of this optional. This will return true if the value can be assigned to the variable. For example:
var myNilValue: String?
if(let nonNilValue = myNilValue){
//this will not be called
}
if let will return false, but:
var myNonNilValue: String? = "Hello, World!"
if(let nonNilValue = myNilValue){
//this will be called
}
Will return true.
Question marks ? are used after variable declarations to define that the variable may not have a value, and it may never have a value. They need to be unwrapped by using an exclamation point ! after the variable name. This can be used for results from a database, in case there is no result.
Exclamation points ! are used after variable declarations to define that the variable may not have a value, but it will have a value when you need to access it. They do not need to be unwrapped, but the compiler will throw an error if the variable is nil at the time of accessing it. This is typically used in #IBOutlets or #IBActions which are not defined until the program compiles
Both self.tableView and indexPathForCell() are optionals. By banging one, you only have one optional to dereference in the result. sender is also an optional and indexPathForCell() doesn't take an optional so it probably needs a bang too, but I haven't compiled it so I can't say for sure what the compiler will do.
self.tableView is reference to a property that might not have been set (e.g. is nil), so it is an optional. You can declare it for example an #IBOutlet with a ! at the end if you know it will ALWAYS be defined, such as from the Storyboard, and then you don't have to bang dereference it later.
A common thing to do is:
#IBOutlet var tableView : UITableView!
That's an implicitly unwrapped optional, and will generate an error if it's referenced when nil. But you don't need to use a ! to dereference.
Correct. The result of the line will produce an optional that you can test with if let

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

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)
}

Resources