Adrian
Adrian

Reputation: 16735

Checking if an NSURL is instantiated in Swift vs. Objective-C

I'm presently taking an iOS development course. As an assignment, I'm tasked with enabling iCloud on a project. I've found Tim Roadley's post to be helpful in explaining the process. The wrinkle: I've built my project in Swift.

In particular, one of the "checks" Mr. Roadley built in to check if there's an instance of the iCloud doesn't translate well to Swift. I'm trying to test if there's an instance of an NSURL called iCloud that's instantiated; if so, do one thing, if not do another.

From Mr. Roadley's tutorial:

            NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];

            if (iCloud) {

                NSLog(@"iCloud is working");

                // a bunch of code

                } else {
                NSLog(@"iCloud is working");

                // a bunch of code

                }

So I tried to convert that statement to Swift, as follows:

        let iCloud: NSURL = fileManager.URLForUbiquityContainerIdentifier(nil)!

        // TODO: having trouble "swiftifying" this line
        if (iCloud) {
            println("iCloud is working!")
        } else {
            println("iCloud is NOT working!")
        }

The compiler says this: Type 'NSURL' does not conform to protocol 'BooleanType'

What obvious thing am I missing?

Edit:

Thank you all for such fantastic, fast responses. They are greatly appreciated and I've learned something here.

Upvotes: 0

Views: 1220

Answers (3)

Ian
Ian

Reputation: 12768

You can check if it's equal to nil, or you can use the if let to unwrap it if it exists. fileManager.URLForUbiquityContainerIdentifier(nil) returns an optional NSURL, so you handle that as such:

Swift 3+

if let cloudURL = fileManager.url(forUbiquityContainerIdentifier: nil) {
    print("iCloud is working!")
} else {
    print("iCloud is NOT working!")
}

Older Versions

let iCloud = fileManager.URLForUbiquityContainerIdentifier(nil) // Remove the "!", and this should return an optional

if iCloud != nil {
    println("iCloud is working!")
} else {
    println("iCloud is NOT working!")
}

or with if let:

if let iCloud = fileManager.URLForUbiquityContainerIdentifier(nil) {
    // exists
} else {
    // doesn't exist
}

Upvotes: 2

Rob Napier
Rob Napier

Reputation: 299623

In most cases the best tool for this is if-let:

if let iCloud = fileManager.URLForUbiquityContainerIdentifier(nil) {
    println("iCloud is working!") // And you can access iCloud here
} else {
    println("iCloud is NOT working!") // And you don't need iCloud here
}

Of course, if these are very long, you should likely move them into their own functions, and have the "can access" function take a full NSURL rather than an optional one. That way you don't have lots of code nested inside of an if. But beyond that, if-let is the normal tool for this kind of problem.

Upvotes: 1

gnasher729
gnasher729

Reputation: 52632

This line of code will crash your application if fileManager.URLForUbiquityContainerIdentifier doesn't succeed.

let iCloud: NSURL = fileManager.URLForUbiquityContainerIdentifier(nil)!

In Objective-C, this method returns either a URL or nil. In Swift, there are no nil objects. Therefore the method returns an optional URL. By using the ! you force that optional URL to be unwrapped. Unlike Objective-C, you don't get a valid URL or nil, you get a valid URL or a crash.

The variable iCloud is therefore an NSURL*, and it is guaranteed to be not nil (because you would have crashed). There is no point checking whether iCloud is nil or not, because it can't be nil.

If you remove the ! then iCloud becomes an optional NSURL*. In that case, you can check whether it has a value by checking

if (iCloud != nil)

The syntax

if (iCloud)

is illegal. An if statement requires a boolean value, and Swift doesn't just convert everything to a boolean value (it was legal at some point, but then people figured out that optional booleans were a nightmare if this was allowed).

Upvotes: 1

Related Questions