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
}
Related
As an example, would it be possible to restrict the accessibility of this extension to arrays whose elements are NOT optional?
extension Array {
subscript(safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
The goal would be that
let array = [String?]()
array[safe: 2]
would give a compile error.
This turned out to be an XY problem. The reason why you wanted to do this seems to just be that you cannot distinguish a nil returned by your subscript, and an actual nil in the array.
Well, you can. When you use the subscript on an array of optionals, it would return a double optional. e.g. for [String?], it would return String??.
Here's an example of determining all 3 cases with a switch. You can use if case if you just want to check one of them.
switch array[safe: 1] {
case .none: // subscript returned nil
break
case .some(nil): // subscript returned non-nil, but that index in the array contained nil
break
case .some(let x): // subscript returned non-nil, and that index contained x
break
}
So there is really no need to restrict your subscript to non-Optional arrays. Swift is not designed to allow you to do that anyway.
Just for a bit of fun though, here's how you can abuse Swift's features to make a warning:
extension Array {
subscript<T>(safe index: Int) -> Element? where Element == T {
return indices ~= index ? self[index] : nil
}
#available(swift, deprecated: 1, message: "Do not use this on arrays of optionals!")
subscript<T>(safe index: Int) -> Element? where Element == T? {
return indices ~= index ? self[index] : nil
}
}
I added an extra subscript that only works on arrays of optionals, but it is marked deprecated since Swift 1 (lol). I added an extra type parameter to the other overload too, so that overload resolution would consider them equally. Otherwise it would always prefer the one with fewer type parameters - we want it to decide based on the generic constraints instead.
Now when you do array[safe: 1], overload resolution chooses the one marked deprecated, and produces a warning.
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.
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
In The Swift Programming Language (book of Apple) I've read that you can create optional variables in 2 ways: using a question mark (?) or by using an exclamation mark (!).
The difference is that when you get the value of an optional with (?) you have to use an exclamation mark every time you want the value:
var str: String? = "Question mark?"
println(str!) // Exclamation mark needed
str = nil
While with an (!) you can get it without a suffix:
var str: String! = "Exclamation mark!"
println(str) // No suffix needed
str = nil
What is the difference and why are there 2 ways if there is no difference at all?
The real benefit to using implicitly unwrapped optionals (declared with the !) is related to class initialisation when two classes point to each other and you need to avoid a strong-reference cycle. For example:
Class A <-> Class B
Class A's init routine needs to create (and own) class B, and B needs a weak reference back to A:
class A {
let instanceOfB: B!
init() {
self.instanceOfB = B(instanceOfA: self)
}
}
class B {
unowned let instanceOfA: A
init(instanceOfA: A) {
self.instanceOfA = instanceOfA
}
}
Now,
Class B needs a reference to class A to be initialised.
Class A can only pass self to class B's initialiser once it's fully initialised.
For Class A to be considered as initialised before Class B is created, the property instanceOfB must therefore be optional.
However, once A's been created it would be annoying to have to access instanceOfB using instanceOfB! since we know that there has to be a B
To avoid this, instanceOfB is declared as an implicity unwrapped optional (instanceOfB!), and we can access it using just instanceOfB. (Furthermore, I suspect that the compiler can optimise the access differently too).
An example of this is given on pages 464 to 466 of the book.
Summary:
Use ? if the value can become nil in the future, so that you test for this.
Use ! if it really shouldn't become nil in the future, but it needs to be nil initially.
You should go beyond the syntactic sugar.
There are two completely different polymorphic types. The syntactic sugar just uses either one or the other of these types.
When you write Foo? as a type you really have Optional<Foo>, while when you write Foo! you really have ImplicitlyUnwrappedOptional<Foo>.
These are two different types, and they are different from Foo as well.
The values you create with ? are plain optional values as you mentioned, you should access it via optional binding (if let unwrappedValue = myOptionalValue) or by using the exclamation point syntax myOptionalValue!.doSomething().
The values you create with ! are called implicitly unwrapped optionals. With them, you don't need to manually unwrap before using them. When you do val myOptionalValue!.doSomething().
The value will be automatically unwrapped for you when you use myOptionalValue directly, be careful with this though, because accessing an implicitly unwrapped value when there is actually no value in it (when it is nil) will result in a runtime error.
? (Optional) indicates your variable may contain a nil value while ! (unwrapper) indicates your variable must have a memory (or value) when it is used (tried to get a value from it) at runtime.
The main difference is that optional chaining fails gracefully when the optional is nil, whereas forced unwrapping triggers a runtime error when the optional is nil.
To reflect the fact that optional chaining can be called on a nil value, the result of an optional chaining call is always an optional value, even if the property, method, or subscript you are querying returns a nonoptional value. You can use this optional return value to check whether the optional chaining call was successful (the returned optional contains a value), or did not succeed due to a nil value in the chain (the returned optional value is nil).
Specifically, the result of an optional chaining call is of the same type as the expected return value, but wrapped in an optional. A property that normally returns an Int will return an Int? when accessed through optional chaining.
var defaultNil : String? // declared variable with default nil value
println(defaultNil) >> nil
var canBeNil : String? = "test"
println(canBeNil) >> optional(test)
canBeNil = nil
println(canBeNil) >> nil
println(canBeNil!) >> // Here nil optional variable is being unwrapped using ! mark (symbol), that will show runtime error. Because a nil optional is being tried to get value using unwrapper
var canNotBeNil : String! = "test"
print(canNotBeNil) >> "test"
var cantBeNil : String = "test"
cantBeNil = nil // can't do this as it's not optional and show a compile time error
For more detail, refer a document by Apple Developer Commitee, in detail
The String! kind is called an implicitly unwrapped optional:
Sometimes it’s clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed, because it can be safely assumed to have a value all of the time.
These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional.
in the optional chaining section you find the answer:
example class:
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
If you try to access the numberOfRooms property of this person’s residence, by placing an exclamation mark after residence to force the unwrapping of its value, you trigger a runtime error, because there is no residence value to unwrap:
let roomCount = john.residence!.numberOfRooms
// this triggers a runtime error
The code above succeeds when john.residence has a non-nil value and will set roomCount to an Int value containing the appropriate number of rooms. However, this code always triggers a runtime error when residence is nil, as illustrated above.
Optional chaining provides an alternative way to access the value of numberOfRooms. To use optional chaining, use a question mark in place of the exclamation mark:
if let roomCount = john.residence?.numberOfRooms {
println("John's residence has \(roomCount) room(s).")
} else {
println("Unable to retrieve the number of rooms.")
}
// prints "Unable to retrieve the number of rooms."
Well mentioned by #tarmes above. Noticed another usage of implicit optional:
Lets say I have an optional Int:
let firstInt: Int? = 9
And I'm trying to use optional pattern matching and use this optional Int like this:
if case let myFirstInt? = firstInt where myFirstInt > 1 {
print("Valid")
} else {
print("Invalid")
}
Notice that I'm using implicit optional with local parameter myFirstInt making it safe for nil condition linked with optional firstInt. If now, I make firstInt as nil, it will execute else condition. If, instead, I use force-unwrap with firstInt that would lead to crash, something like this:
ok so I am trying to return nil if a certain type is passed into my function. In this case im passing in an instance of my class "BlogPost" and a type within this blogpost. I also have an array called "types" and I have assigned the variable Videos to the last index of that array. If this type is passed into my function I would like to return nil (so assuming im going to need an optional here for returning a possible nil) this is what I have so far :-
so all in all I need to pass in an instance of my blog post but always return nil if a certain type is passed in. Hope this makes sense
Update:
The types array is defined as follows:
let types : [String] = ["technology", "Fashion", "Animals"]
this is the array I am referring to in the function. Basically if that last entry of the array is entered into the function I need to return nil
sure this is blogpost it does actually have an empty string for type
great so im getting there what Ive done now is change the blogpost.type to choose one at random. So now if the specfic type is chosen from this array how would I do that still getting an error. This is what I have updated to
so now all I need to do is access the 2 type in that array and if I do access it return nil. Any thoughts on that? so to drag it on thanks
I don't think you can. You can create failable initialisers which does what you need but you cannot use it with normal function.
The best solution for you would be return optional Int or String and when you call the function just check the result for nil and do what you need to do, otherwise ignore it:
func randomViews(blog : BlogPost.Type) -> Int? {
case 10:
return nil
case 10, 20 :
return 0
default:
random
}
if (randomViews(parameter) == nil) {
//function returned nil
}
You have displayed error because you compare optional blog to Videos, you have to unwrap it first, for example if you are sure the blog has always have a value use:
if blog! == Videos
if not sure is safer to use:
if let blg = blog {
if blg == Videos {
}
else {
// blog has not have a value
}
You are passing blog as a BlogPost.Type parameter. That is not correct. You should have either just passed it the String parameter, or you could pass it the BlogPost itself:
func randomViews(blog: BlogPost) {
let videos = types[2]
if blog.type == videos {
// do whatever you want
}
// carry on
}
Unrelated to your question at hand, but notice that I use let instead of var when defining videos. Always use let if the value will not (and cannot) change.
Also note that I use lowercase letter v in videos, because Cocoa naming conventions dictate that variables generally start with lowercase letters, whereas types, classes, structs, and enums generally start with uppercase letters.