-
-
Save nazmulkp/7eff3dc3b9000066a9ed70d9c3dd9e8e to your computer and use it in GitHub Desktop.
func fetchJSON(from url: URL) -> RACSignal { | |
print("Fetching: \(url.absoluteString)") | |
// 1 | |
return RACSignal.createSignal({(_ subscriber: RACSubscriber) -> RACDisposable in | |
// 2 | |
var dataTask = self.session.dataTask(withURL: url, completionHandler: {(_ data: Data, _ response: URLResponse, _ .error: Error) -> Void in | |
// TODO: Handle retrieved data | |
}) | |
// 3 | |
dataTask.resume() | |
// 4 | |
return RACDisposable(block: {() -> Void in | |
dataTask.cancel() | |
}) | |
}).doError({(_ error: Error) -> Void in | |
// 5 | |
print("\(.error)") | |
}) | |
} |
func fetchJSON(from url: URL) -> RACSignal {
print("Fetching: (url.absoluteString)")
// 1
return RACSignal.createSignal({(_ subscriber: RACSubscriber) -> RACDisposable in
// 2
var dataTask = self.session.dataTask(withURL: url, completionHandler: {(_ data: Data, _ response: URLResponse, _ .error: Error) -> Void in
// TODO: Handle retrieved data
do {
if !.error {
var jsonError: Error? = nil
var .json = try JSONSerialization.jsonObject(withData: data, options: kNilOptions)!
if jsonError == nil {
// 1
subscriber.sendNext(.json)
}
else {
// 2
subscriber.sendError(jsonError)
}
}
else {
// 2
subscriber.sendError(.error)
}
}
catch {
}
// 3
subscriber.sendCompleted()
})
// 3
dataTask.resume()
// 4
return RACDisposable(block: {() -> Void in
dataTask.cancel()
})
}).doError({(_ error: Error) -> Void in
// 5
print("(.error)")
})
}
}
func fetchCurrentConditions(forLocation coordinate: CLLocationCoordinate2D) -> RACSignal {
// 1
var urlString = "http://api.openweathermap.org/data/2.5/weather?lat=\(coordinate.latitude)&lon=\(coordinate.longitude)&units=imperial"
var url = URL(string: urlString)!
// 2
return self.fetchJSON(from: url).map({(_ json: [AnyHashable: Any]) -> Void in
// 3
do {
return try MTLJSONAdapter.modelOfClass(WXCondition.self, fromJSONDictionary: .json)
}
catch {
}
})
}
}
func fetchHourlyForecast(forLocation coordinate: CLLocationCoordinate2D) -> RACSignal {
var urlString = "http://api.openweathermap.org/data/2.5/forecast?lat=\(coordinate.latitude)&lon=\(coordinate.longitude)&units=imperial&cnt=12"
var url = URL(string: urlString)!
// 1
return self.fetchJSON(from: url).map({(_ json: [AnyHashable: Any]) -> Void in
// 2
var list = .json["list"].rac_sequence()
// 3
return list.map({(_ item: [AnyHashable: Any]) -> Void in
// 4
do {
return try MTLJSONAdapter.modelOfClass(WXCondition.self, fromJSONDictionary: item)
}
catch {
}
// 5
})()
})
}
}
func fetchDailyForecast(forLocation coordinate: CLLocationCoordinate2D) -> RACSignal {
var urlString = "http://api.openweathermap.org/data/2.5/forecast/daily?lat=\(coordinate.latitude)&lon=\(coordinate.longitude)&units=imperial&cnt=7"
var url = URL(string: urlString)!
// Use the generic fetch method and map results to convert into an array of Mantle objects
return self.fetchJSON(from: url).map({(_ json: [AnyHashable: Any]) -> Void in
// Build a sequence from the list of raw JSON
var list = .json["list"].rac_sequence()
// Use a function to map results from JSON to Mantle objects
return list.map({(_ item: [AnyHashable: Any]) -> Void in
do {
return try MTLJSONAdapter.modelOfClass(WXDailyForecast.self, fromJSONDictionary: item)
}
catch {
}
})()
})
}
}
class func sharedManager() -> Self {
var sharedManager: Any? = nil
var onceToken: dispatch_once_t
dispatch_once(onceToken, {() -> Void in
self.sharedManager = self.init()
})
return sharedManager
}
override init() {
super.init()
// 1
self.locationManager = CLLocationManager()
self.locationManager.delegate = self
// 2
self.client = WXClient()
// 3
RACObserve(self, currentLocation).ignore(nil).flattenMap({(_ newLocation: CLLocation) -> Void in
return RACSignal.merge([self.updateCurrentConditions(), self.updateDailyForecast(), self.updateHourlyForecast()])
// 6
}).deliver(on: RACScheduler.mainThreadScheduler).subscribeError({(_ error: Error) -> Void in
TSMessage.showNotification(withTitle: "Error", subtitle: "There was a problem fetching the latest weather.", type: TSMessageNotificationTypeError)
})
}
You’ll need a master method to build a signal to fetch data from a URL. You already know that three methods are required for fetching the current conditions, the hourly forecast and the daily forecast.
But instead of writing three separate methods, you can follow the DRY (Don’t Repeat Yourself) software design philosophy to make your code easy to maintain.
Some of the following ReactiveCocoa parts may look rather unfamiliar at first. Don’t worry, you’ll go through it piece by piece.