wonderv
wonderv

Reputation: 45

How to check if NSMutableSet contains an element without nil error

I'm new to Swift (and iOS programming), and I'm struggling with properly finding whether certain data structures contain elements. More specifically, I have created an empty set into which I want to insert elements after further calculations:

var moviesInItinerary : NSMutableSet? = nil

Then, I want to proceed with the calculations only if the set is empty or if it doesn't contain a given element. I wrote this condition like this:

if((moviesInItinerary?.count == 0) || (!moviesInItinerary!.containsObject(movies[currentMovie.row].title)))

However, when I try to run this code, I'm getting this error:

fatal error: unexpectedly found nil while unwrapping an Optional value

What is the safe way to perform these checks?

Upvotes: 0

Views: 1468

Answers (3)

vacawama
vacawama

Reputation: 154671

You can simply do:

if !(moviesInItinerary?.containsObject(movies[currentMovie.row].title) == true) {
    // When we get here, we know either moviesInItinerary is nil, or the NSMutableSet
    // does not contain our movie.
}

This works because optional chaining makes moviesinItinerary?.constainsObject(movies[currentMovie.row].title) return a value of type Bool?. If it is nil because moviesInItinerary is nil, then it won't compare to true. If moviesInItinerary isn't nil, then containsObject will either return true or false and then the comparison with work if it is true. It is unnecessary to also check if count is zero, because that is redundant. A set with count zero will obviously not contain your object.

Upvotes: 2

zneak
zneak

Reputation: 138171

Typing moviesInItinerary as NSMutableSet? means that NSMutableSet can be nil, and it appears that you never assign an object to it.

This line here:

var moviesInItinerary : NSMutableSet? = nil

declares that moviesInItinerary itself is either an NSMutableSet, or nil (and in this specific case, since you never assign it anything other than nil, it stays like that).

Swift encourages people to use immutable variables and to avoid nullable variables whenever it makes sense to. If you always need moviesInItinerary to be a valid set, and you don't need to overwrite it with a different set, the best way to declare it would be:

let moviesInItinerary = NSMutableSet()

From the right-hand side of the assignment, Swift knows that the type of moviesInItinerary should be NSMutableSet, so there's no need to explicitly type it. It also knows that it cannot be nil, and that it cannot point to a different object after its initialization.

Since it can't be nil, you also no longer need to use the .? operator for it: just . will be enough.

Upvotes: 1

Sandy Chapman
Sandy Chapman

Reputation: 11341

You should read up on Swift's optional types. Going in blindly without understanding them is bound to lead to programming errors.

var moviesInItinerary : NSMutableSet? = nil

I'd change that to this:

var moviesInItinerary : NSMutableSet = NSMutableSet()

Then, moviesInItinerary cannot be nil. If you really want it to be an optional type (meaning it can possibly be nil), then change your condition to the following:

if let moviesSet = moviesInItineraray? {
    // use moviesSet in here. It will not be nil.
}

Upvotes: 4

Related Questions