-
-
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 |
The selector syntax also has been updated:
selector: #selector(ISSFetcher.getNext)
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.
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)
}
}
Cool, I think I'm remembering back in swift 1, possibly before
if let
whereif let
was supposed to be the savior. I'm probably mis-remembering. But I'm definitely seeing the value of not havingif let
.