10
\$\begingroup\$

This piece of code is working - It gives me a lot of JSON back, which I have yet to parse, but I'd like to show my code here first to get tips on how to improve what I already have:

VenueService.swift

    class VenueService {

    private let __kVenueServiceClientID = "CLIENT_ID"
    private let __kVenueServiceClientSecret = "CLIENT_SECRET"

    func performVenueLocationRequest(location: CLLocationCoordinate2D, identifier: NSString, completion: (venues: NSDictionary?, error: NSError?) -> ()) {
        var error: NSError?
        var response: NSURLResponse?

        let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

        dispatch_async(queue, {
            if let data = NSURLConnection.sendSynchronousRequest(self.buildRequestForVenueLocation(location, identifier), returningResponse: &response, error: &error) {
                if(error == nil) {
                    let responseDictionary: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: nil, error:&error)
                    if let responseDictionary = responseDictionary as? NSDictionary {
                        completion(venues: responseDictionary, error: nil)
                    }
                } else {
                    completion(venues: nil, error: error)
                }
            } else {
                println("There was a problem with the request...")
            }
        })

    }

    func todaysDate() -> NSString {
        let date = NSDate()
        let formatter = NSDateFormatter()
        formatter.dateFormat = "yyyMMdd"
        return formatter.stringFromDate(date)
    }

    func buildRequestForVenueLocation(location: CLLocationCoordinate2D, _ identifier: NSString) -> NSURLRequest {
            return NSURLRequest(URL: NSURL(string: "https://api.foursquare.com/v2/venues/search?ll=\(location.latitude),\(location.longitude)&radius=500&limit=50&categoryId=\(identifier)&client_id=\(__kVenueServiceClientID)&client_secret=\(__kVenueServiceClientSecret)&v=\(self.todaysDate())")!)
    }
}

I use it like this in my ViewController:

struct Location {
    let location: CLLocationCoordinate2D

    init() {
        self.location = CLLocationCoordinate2D(latitude: 37.332331, longitude: -122.031219)
    }

}

class ViewController: UIViewController {

    let v = VenueService()
    let l = Location()

    override func viewDidLoad() {
        super.viewDidLoad()
    }


    @IBAction func testJSON(sender: AnyObject) {
        v.performVenueLocationRequest(l.location, identifier: "4d4b7105d754a06374d81259", completion: { dict, err in
            dispatch_async(dispatch_get_main_queue(), {
                if let err = err {
                    println("if let \(err)")
                } else {
                    if let dict = dict {
                        println("else: \(dict)")
                    }
                }
            })
        })
    }
}

One thing I'm really confused about:

Say I have an optional. I could use the if let syntax to unwrap it, but is it the same to just say if optinalVariable == nil {} else optinalVariable!?

In playground I get the same results.

\$\endgroup\$

1 Answer 1

6
\$\begingroup\$

To use:

if optionalVariable == nil {} else {
    // do stuff with optionalVariable!
}

would absolutely not be recommended.

For starters,

if optionalVariable != nil {
    // do stuff with optionalVariable!
}  

would be slightly better, but still, I can't even remotely recommend this.

Given that optionalVariable is nullable, what happens if it is made null inside this closure?

if optionalVariable != nil {
    doStuff(optionalVariable!)
    optionalVariable = funcThatCouldReturnNil()
    doStuff(optionalVariable!)
}

At the end of the day, we should simply minimize our use of forced unwraps.

if let variable = optionalVariable {
    doStuff(variable)
    variable = funcThatCouldReturnNil() // <-- compile time error
}

If variable is not a nullable, then you can't assign the result of a function that could return nil to it without force unwrapping the result.

The exclamation point should mark to us that something special is happening here... and if we can use the exclamation point, we might need to rethink our method.

At the end of the day, we shouldn't be asking ourselves purely whether or not our results remain the same for both methods. We should also ask ourselves whether one way or the other opens the path for future maintainers to do something stupid and write some bugs into your code.

If I'm assigning the result of a non-optional returning function to a non-optional variable, if it is later determined that the function needs to return an optional, then Swift and Xcode will politely alert me to every occurrence that I need to go look at for my variable.

And if I'm not using the if let syntax and instead using the ! force unwrap everywhere, then Xcode can't remind me, and I'm asking myself for a huge swampy headache of bugs...

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.