Skip to content

Instantly share code, notes, and snippets.

@rodericj
Last active May 27, 2016 13:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rodericj/0bf0b70dc8a7faf0cce5a5c52b60d917 to your computer and use it in GitHub Desktop.
Save rodericj/0bf0b70dc8a7faf0cce5a5c52b60d917 to your computer and use it in GitHub Desktop.
//: Playground - Track the ISS from a playground
import MapKit
import XCPlayground
class ISSFetcher: NSObject {
var completion: (Double, Double) -> Void
var timer: NSTimer?
init(inCompletion: (Double, Double) -> Void) {
completion = inCompletion
}
func getNext() {
guard let url = NSURL(string: "http://api.open-notify.org/iss-now.json") else {
print("we need a url")
return
}
let request = NSURLRequest(URL: url)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) in
if let data = data, json = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? [String: AnyObject],
position = json?["iss_position"],
latitude = position["latitude"],
longitude = position["longitude"] {
self.completion(latitude as! Double, longitude as! Double)
}
if let error = error {
print("error fetching new coordinates", error)
}
})
task.resume()
}
func stop() {
timer?.invalidate()
}
func start() {
// kick things off
getNext()
// set it up so we do it again after 5 seconds
timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: #selector(getNext), userInfo: nil, repeats: true)
}
}
class ISSAnnotation: NSObject, MKAnnotation {
dynamic var coordinate: CLLocationCoordinate2D
var title: String? = "ISS"
init(lat: Double, lon: Double) {
coordinate = CLLocationCoordinate2D(latitude: lat, longitude: lon)
}
func update(newLatitude: Double, newLongitude: Double) {
coordinate = CLLocationCoordinate2D(latitude: newLatitude, longitude: newLongitude)
}
}
// This is our main()
let frame = CGRect(x: 0, y: 0, width: 400, height: 400 )
let mapView = MKMapView(frame: frame )
mapView.mapType = .Satellite
let annotation = ISSAnnotation(lat: 0,lon: 0)
mapView.addAnnotation(annotation)
// Create the fetcher object with completion block
let fetcher = ISSFetcher(inCompletion: {(lat, lon) in
dispatch_async(dispatch_get_main_queue(), {
UIView.animateWithDuration(3, animations: {
print("new coordinates", lat, lon)
annotation.update(lat, newLongitude: lon)
mapView.centerCoordinate = annotation.coordinate
})
})
})
// start the fetcher
fetcher.start()
// view the map in the timeline!
XCPlaygroundPage.currentPage.liveView = mapView
@rodericj
Copy link
Author

Cool, I think I'm remembering back in swift 1, possibly before if let where if let was supposed to be the savior. I'm probably mis-remembering. But I'm definitely seeing the value of not having if let.

@adamstener
Copy link

The selector syntax also has been updated:
selector: #selector(ISSFetcher.getNext)

@adamstener
Copy link

if let is more common for me to use where I need a non-optional value to call into something. So I need to make sure it's there and if it is, then I can use the non-optional thing to make the call and if it's not there I can make a different decision. In this case, if the timer is not there then there's no other decision to make. If it is there then it gets invalided and that's all there is to do.

@adamstener
Copy link

adamstener commented May 27, 2016

This one is purely preference, but I like the look of this trailing closure syntax better (I think this is what pzearfoss was referring to, though there are many variations of syntax closure syntax). There are many many people who will say they like other ways better, because there are lots of ways of writing closure syntax, but the trailing ')' at the end of a method is just less appealing to me. The argument that most people have is that your current syntax looks more like a closure, so its' more obvious what is going on, I just think this way is cleaner, and I've gotten used to it. There is no performance benefit, strictly which syntax works better for whatever team/person is working on the code:

// Create the fetcher object with completion block
let fetcher = ISSFetcher() { lat, lon in
    dispatch_async(dispatch_get_main_queue()) {
        UIView.animateWithDuration(3) {
            print("new coordinates", lat, lon)
            annotation.update(lat, newLongitude: lon)
            mapView.centerCoordinate = annotation.coordinate
        }
    }
}




let task = session.dataTaskWithRequest(request) { data, response, error in
            if let data = data, json = try? NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? [String: AnyObject],
                position = json?["iss_position"],
                latitude = position["latitude"],
                longitude = position["longitude"] {
                self.completion(latitude as! Double, longitude as! Double)
            }
            if let error = error {
                print("error fetching new coordinates", error)
            }
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment