Skip to content

Instantly share code, notes, and snippets.

@nazmulkp
Created November 27, 2016 21:25
Show Gist options
  • Save nazmulkp/7eff3dc3b9000066a9ed70d9c3dd9e8e to your computer and use it in GitHub Desktop.
Save nazmulkp/7eff3dc3b9000066a9ed70d9c3dd9e8e to your computer and use it in GitHub Desktop.
Building the Signals
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)")
})
}
@nazmulkp
Copy link
Author

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.

@nazmulkp
Copy link
Author

nazmulkp commented Nov 27, 2016

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)")
})
}
}

@nazmulkp
Copy link
Author

nazmulkp commented Nov 27, 2016

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 {
}
})
}
}

@nazmulkp
Copy link
Author

nazmulkp commented Nov 27, 2016

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
})()
})
}
}

@nazmulkp
Copy link
Author

nazmulkp commented Nov 27, 2016

    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 {
                }
            })()
        })
    }
  }

@nazmulkp
Copy link
Author

nazmulkp commented Nov 27, 2016

   class func sharedManager() -> Self {
             var sharedManager: Any? = nil
             var onceToken: dispatch_once_t
            dispatch_once(onceToken, {() -> Void in
                  self.sharedManager = self.init()
           })

       return sharedManager
 }

@nazmulkp
Copy link
Author

   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)
        })
    
    }

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