Delay in Updating UILabel from API call - swift

I am updating my UILabels from an API Call. I have an API Client file which pulls the needed information and then passes it over to the DataStore and then parses through the information and then creates movie Objects. The collectionViewController accesses the information without a problem but when it passes the information to the next view controller, a problem occurs. The information does not appear on the view controller and then when I click back in the information will appear. There is some sort of delay in the information from the API Client or something which I can't seem to figure out.
//Second API call to get information for the Second View Controller (Detail View Controller)
class func getDescriptiveMovieResultsFromSearch(movieID: String, completion:(NSDictionary)-> ())
{
var descriptiveDictionary: [String: String] = [:]
let searchURL = "https://www.omdbapi.com/?i=\(movieID)&?plot=short"
let nsurl = NSURL(string: searchURL)
//convert the url into an NSURL
guard let unwrappedNSURL = nsurl else {print("ERROR OCCURRED HERE"); return}
//unwrap the nsurl using guard let
//let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: unwrappedNSURL)
//creation of the request
request.HTTPMethod = "GET"
//By Default everythiing is a GET request if you are getting information and you don't need it
//request has an HTTPMethod of type "GET" to obtain information
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) in
guard let unwrappedData = data else {print("Error occurred here"); return}
if let responseDictionary = try? NSJSONSerialization.JSONObjectWithData(unwrappedData, options: []) as? NSDictionary
{
let castedResponseDictionary = responseDictionary as? [String : String]
guard let unwrappedResponseDictionary = castedResponseDictionary else {print("This did not work!"); return}
descriptiveDictionary = unwrappedResponseDictionary
}
completion(descriptiveDictionary)
}
task.resume()
}
//MovieDataStore function to parse through the information
/Second API Call
func getDescriptiveMovieInformationWith(movie: Movie, Completion: (Bool) -> ())
{
guard let unwrappedimdbID = movie.imdbID else {print("AN ERROR OCCURRED HERE"); return}
OMDBAPIClient.getDescriptiveMovieResultsFromSearch(unwrappedimdbID) { (descriptiveResponseDictionary) in
let desMovieDirector = descriptiveResponseDictionary["Director"] as? String
let desMovieWriters = descriptiveResponseDictionary["Writer"] as? String
let desMovieActors = descriptiveResponseDictionary["Actors"] as? String
let desMovieShortPlot = descriptiveResponseDictionary["Plot"] as? String
let desMovieimbdRating = descriptiveResponseDictionary["imdbRating"] as? String
//unwrapping each of the of the json information
guard let
unwrappedDesMovieDirector = desMovieDirector,
unwrappedDesMovieWriters = desMovieWriters,
unwrappedDesMovieActors = desMovieActors,
unwrappedDesMovieShortPlot = desMovieShortPlot,
unwrappedDesMovieimbdRating = desMovieimbdRating
else {print("AN ERROR OCCURRED HERE!"); return}
movie.director = unwrappedDesMovieDirector
movie.writers = unwrappedDesMovieWriters
movie.actors = unwrappedDesMovieActors
movie.shortPlot = unwrappedDesMovieShortPlot
movie.imdbRating = unwrappedDesMovieimbdRating
print("******************************************")
print("Movie Director: \(movie.director)")
print("Movie writers: \(movie.writers)")
print("Movie actors: \(movie.actors)")
print("Movie shortPlot: \(movie.shortPlot)")
print("Movie imdbRating: \(movie.imdbRating)")
print("******************************************")
//Completion(true)
Completion(true)
}
}
//Detail View Controller
/Second API Call
func getDescriptiveMovieInformationWith(movie: Movie, Completion: (Bool) -> ())
{
guard let unwrappedimdbID = movie.imdbID else {print("AN ERROR OCCURRED HERE"); return}
OMDBAPIClient.getDescriptiveMovieResultsFromSearch(unwrappedimdbID) { (descriptiveResponseDictionary) in
let desMovieDirector = descriptiveResponseDictionary["Director"] as? String
let desMovieWriters = descriptiveResponseDictionary["Writer"] as? String
let desMovieActors = descriptiveResponseDictionary["Actors"] as? String
let desMovieShortPlot = descriptiveResponseDictionary["Plot"] as? String
let desMovieimbdRating = descriptiveResponseDictionary["imdbRating"] as? String
//unwrapping each of the of the json information
guard let
unwrappedDesMovieDirector = desMovieDirector,
unwrappedDesMovieWriters = desMovieWriters,
unwrappedDesMovieActors = desMovieActors,
unwrappedDesMovieShortPlot = desMovieShortPlot,
unwrappedDesMovieimbdRating = desMovieimbdRating
else {print("AN ERROR OCCURRED HERE!"); return}
movie.director = unwrappedDesMovieDirector
movie.writers = unwrappedDesMovieWriters
movie.actors = unwrappedDesMovieActors
movie.shortPlot = unwrappedDesMovieShortPlot
movie.imdbRating = unwrappedDesMovieimbdRating
print("******************************************")
print("Movie Director: \(movie.director)")
print("Movie writers: \(movie.writers)")
print("Movie actors: \(movie.actors)")
print("Movie shortPlot: \(movie.shortPlot)")
print("Movie imdbRating: \(movie.imdbRating)")
print("******************************************")
//Completion(true)
Completion(true)
}
}
//detail view Controller
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.blackColor()
self.titleLabel.textColor = UIColor.yellowColor()
self.yearLabel.textColor = UIColor.yellowColor()
self.directorLabel.textColor = UIColor.yellowColor()
self.writersLabel.textColor = UIColor.yellowColor()
self.actorsLabel.textColor = UIColor.yellowColor()
self.shortPlotLabel.textColor = UIColor.yellowColor()
self.imdbIDLabel.textColor = UIColor.yellowColor()
self.typeLabel.textColor = UIColor.yellowColor()
self.imdbRating.textColor = UIColor.yellowColor()
stackViewLabel.translatesAutoresizingMaskIntoConstraints = false
stackViewLabel.topAnchor.constraintEqualToAnchor(self.topImage.bottomAnchor, constant: 5).active = true
stackViewLabel.widthAnchor.constraintEqualToAnchor(self.view.widthAnchor, multiplier: 1.00).active = true
stackViewLabel.heightAnchor.constraintEqualToAnchor(self.view.heightAnchor, multiplier: 0.50).active = true
stackViewLabel.leftAnchor.constraintEqualToAnchor(self.view.leftAnchor).active = true
//unwrapped Movie Object
guard let unwrappedMovieObject = movieObject else {print("AN ERROR OCCURRED HERE!"); return}
self.store.getDescriptiveMovieInformationWith(unwrappedMovieObject) { (isWorking) in
if isWorking {
dispatch_async(dispatch_get_main_queue()){
guard let unwrappedPosterURL = unwrappedMovieObject.posterURL else {print("AN ERROR OCCURRED HERE"); return}
if unwrappedPosterURL == "N/A"{
self.topImage.image = UIImage.init(named: "star_PNG1592")
}
else {
if let url = NSURL(string: unwrappedPosterURL){
if let data = NSData(contentsOfURL: url){
//print("I have an image to display")
self.topImage.image = UIImage.init(data: data)
}
}
}
self.titleLabel.text = unwrappedMovieObject.title
self.yearLabel.text = unwrappedMovieObject.year
self.imdbIDLabel.text = unwrappedMovieObject.imdbID
self.typeLabel.text = unwrappedMovieObject.type
guard let
unwrappedDirector = unwrappedMovieObject.director,
unwrappedWriters = unwrappedMovieObject.writers,
unwrappedActors = unwrappedMovieObject.actors,
unwrappedShortPlot = unwrappedMovieObject.shortPlot,
unwrappedRating = unwrappedMovieObject.imdbRating
else {print("PROPERTIES WERE UNWRAPPED"); return}
self.directorLabel.text = unwrappedDirector
self.writersLabel.text = unwrappedWriters
self.actorsLabel.text = unwrappedActors
self.shortPlotLabel.text = unwrappedShortPlot
self.imdbRating.text = unwrappedRating
}
}
else{
print("AN ERROR OCCURRED HERE")
}
}
}

NSURLSession.sharedSession().dataTaskWithRequest(request)
I'm not sure what callback queue the sharedSession uses, If its not the main thread you will need to
DispatchQueue.main.async {
completion(descriptiveDictionary)
}

Related

route between two markers in google maps - Swift

I want him to draw the route between the two coordinates and go to the route, but he doesn't draw the route. It prints out success but cannot draw the route. What is the problem? How can I draw two routes on the map and show the details of this route?
func drawPath()
{
let kordinatgetir = keychain.get("uyeKordinat")
let doubleKordinat :Double = Double(kordinatgetir!)!
let kordinatgetir1 = keychain.get("uyeKordinat1")
let doubleKordinat1 :Double = Double(kordinatgetir1!)!
let origin = "\(doubleKordinat),\(doubleKordinat1)"
let destination = "\(doubleKordinat1),\(doubleKordinat)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=..."
Alamofire.request(url).responseJSON { response in
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
do {
let json = try JSON(data: response.data!)
let routes = json["routes"].arrayValue
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline.init(path: path)
polyline.map = self.mapView
}
} catch {
print(error)
}
}
}
func drowRoute(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {
self.mapView.clear()
let origin = "\(source.latitude),\(source.longitude)"
let destinationn = "\(destination.latitude),\(destination.longitude)"
guard let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destinationn)&mode=driving&key=Your Key") else {
let error = NSError(domain: "LocalDomain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create object URL"])
print("Error: \(error)")
//completionHandler(nil, error)
return
}
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
SVProgressHUD.show()
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
if error != nil {
print(error!.localizedDescription)
SVProgressHUD.dismiss()
}
else {
do {
if let json : [String:Any] = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]{
guard let routes = json["routes"] as? NSArray else {
DispatchQueue.main.async {
SVProgressHUD.dismiss()
}
return
}
if (routes.count > 0) {
let overview_polyline = routes[0] as? NSDictionary
let dictPolyline = overview_polyline?["overview_polyline"] as? NSDictionary
let points = dictPolyline?.object(forKey: "points") as? String
DispatchQueue.main.async {
//
let legs = overview_polyline?["legs"] as! Array<Dictionary<String, AnyObject>>
let distance = legs[0]["distance"] as? NSDictionary
let distanceValue = distance?["value"] as? Int ?? 0
let duration = legs[0]["duration"] as? NSDictionary
let totalDurationInSeconds = duration?["value"] as? Int ?? 0
let miles = Double(distanceValue) / 1609.344
print("\(miles)")
if distanceValue > Int(32186.9){
SVProgressHUD.dismiss()
self.showAlert(title: Appname, message: "Your dropping point is more than 20 miles")
self.txtToLocation.text = ""
self.txtToLocation.becomeFirstResponder()
}else{
self.showPath(polyStr: points!)
let startLocationDictionary = legs[0]["start_location"] as! Dictionary<String, AnyObject>
let originCoordinate = CLLocationCoordinate2DMake(startLocationDictionary["lat"] as! Double, startLocationDictionary["lng"] as! Double)
let endLocationDictionary = legs[legs.count - 1]["end_location"] as! Dictionary<String, AnyObject>
let destinationCoordinate = CLLocationCoordinate2DMake(endLocationDictionary["lat"] as! Double, endLocationDictionary["lng"] as! Double)
let marker1 = GMSMarker()
marker1.position = CLLocationCoordinate2D(latitude:destinationCoordinate.latitude, longitude: destinationCoordinate.longitude)
marker1.icon = UIImage(named: "icn_pin-1")
marker1.map = self.mapView
let marker2 = GMSMarker()
marker2.position = CLLocationCoordinate2D(latitude:originCoordinate.latitude, longitude: originCoordinate.longitude)
marker2.icon = UIImage(named: "icn_pin2")
marker2.map = self.mapView
}
}
}
else {
print(json)
DispatchQueue.main.async {
SVProgressHUD.dismiss()
}
}
}
}
catch {
print("error in JSONSerialization")
DispatchQueue.main.async {
SVProgressHUD.dismiss()
}
}
}
})
task.resume()
}
func showPath(polyStr :String){
SVProgressHUD.dismiss()
let path = GMSPath(fromEncodedPath: polyStr)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 5.0
polyline.strokeColor = UIColor.UIColorFromHex(hex: "#F6881F")
polyline.map = mapView
DispatchQueue.main.async {
let bounds = GMSCoordinateBounds(path: path!)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsets(top: 170, left: 30, bottom: 30, right: 30))
self.mapView.moveCamera(update)
}
}

How to work with async functions swift? Completion handlers [duplicate]

This question already has answers here:
Run code only after asynchronous function finishes executing
(2 answers)
Closed 5 years ago.
Im trying to wait for the function to process in order to show my image. I have try many things but none of this worked. I know this is an async function and basically i have to wait in order to get the right values but I dont know how to fix this function right here. I hope you can help me out. Thank you!
func createListProductsGood(Finished() -> void) {
refProducts.child("Products").queryOrderedByKey().observe(.childAdded, with: { snapshot in
let prod = snapshot.value as! NSDictionary
let active = snapshot.key
let rejected = prod["NotInterested"] as! String
let photoURL = prod["photoURL"] as! String
var findit = false
// print(rejected)
if (rejected != self.userUID){
//print(active)
if rejected.contains(","){
var pointsArr = rejected.components(separatedBy: ",")
for x in pointsArr{
if x.trimmingCharacters(in: NSCharacterSet.whitespaces) == self.userUID {
// print("dont show")
findit = true
return
}
}
if (findit == false){
if let url = NSURL(string: photoURL) {
if let data = NSData(contentsOf: url as URL) {
self.ProductId = active
self.productPhoto.image = UIImage(data: data as Data)
}}
}
}else{
print(active)
if let url = NSURL(string: photoURL) {
if let data = NSData(contentsOf: url as URL) {
self.ProductId = active
self.productPhoto.image = UIImage(data: data as Data)
}}
}
}
})
finished()
}
Edited:
This is how my viewDidLoad looks like:
override func viewDidLoad() {
super.viewDidLoad()
setAcceptedOrRejected()
createListProductsGood{_ in
}
}
func createListProductsGood(finished: #escaping (_ imageData: Data) -> Void) {
refProducts.child("Products").queryOrderedByKey().observe(.childAdded, with: { snapshot in
let prod = snapshot.value as! NSDictionary
let active = snapshot.key
let rejected = prod["NotInterested"] as! String
let photoURL = prod["photoURL"] as! String
var findit = false
// print(rejected)
if (rejected != self.userUID){
//print(active)
if rejected.contains(","){
var pointsArr = rejected.components(separatedBy: ",")
for x in pointsArr{
if x.trimmingCharacters(in: NSCharacterSet.whitespaces) == self.userUID {
// print("dont show")
findit = true
return
}
}
if (findit == false){
if let url = NSURL(string: photoURL) {
if let data = NSData(contentsOf: url as URL) {
self.ProductId = active
DispatchQueue.main.async {
self.productPhoto.image = UIImage(data: data as Data)
}
}}
}
}else{
print(active)
if let url = NSURL(string: photoURL) {
if let data = NSData(contentsOf: url as URL) {
self.ProductId = active
DispatchQueue.main.async {
self.productPhoto.image = UIImage(data: data as Data)
}
}}
}
}
})
}
This is my second method:
func setAcceptedOrRejected() {
refProducts.child("Products").queryOrderedByKey().observe(.childAdded, with: { snapshot in
let prod = snapshot.value as! NSDictionary
if self.ProductId == snapshot.key{
self.texto = prod["NotInterested"] as! String
self.refProducts.child("Products").child(self.ProductId).updateChildValues(["NotInterested": self.texto + ", " + self.userUID])
} })
}
You should change:
func createListProductsGood(Finished() -> void) {
to:
func createListProductsGood(finished: #escaping (_ something: SomeType) -> Void) {
or to be more specific:
func createListProductsGood(finished: #escaping (_ imageData: Data) -> Void) {
then wherever in your function you get the image, you call
finished(imageData)
so you can pass the imageData through a closure to where its needed.
then you call this function like this:
createListProductsGood{ imageData in
...
let image = UIImage(data: imageData)
// update UI from main Thread:
DispatchQueue.main.async {
self.productPhoto.image = image
}
}
Also:
it's not convention to use Finished(), you should use finished()
using void is wrong. You must use Void or ()
If you're having problems with closures and completionHandlers, I recommend you first try getting your hands dirty with a simple UIAlertController. See here. Try creating an action with a closure, e.g. see here
EDIT :
Thanks to Leo's comments:
func createListProductsGood(finished: #escaping(_ imageData: Data?, MyError?) -> Void) {
let value: Data?
let error = MyError.someError("The error message")
refProducts.child("Products").queryOrderedByKey().observe(.childAdded, with: { snapshot in
let prod = snapshot.value as! NSDictionary
let active = snapshot.key
let rejected = prod["NotInterested"] as! String
let photoURL = prod["photoURL"] as! String
var findit = false
// print(rejected)
if (rejected != self.userUID){
//print(active)
if rejected.contains(","){
var pointsArr = rejected.components(separatedBy: ",")
for x in pointsArr{
if x.trimmingCharacters(in: NSCharacterSet.whitespaces) == self.userUID {
// print("dont show")
findit = true
return
}
}
if (findit == false){
if let url = NSURL(string: photoURL) {
if let data = NSData(contentsOf: url as URL) {
self.ProductId = active // REMOVE
self.productPhoto.image = UIImage(data: data as Data) // REMOVE
finished(data, nil) //ADD
}else{
finished(nil,error) //ADD
}
}
}
}else{
print(active)
if let url = NSURL(string: photoURL) {
if let data = NSData(contentsOf: url as URL) {
self.ProductId = active // REMOVE
self.productPhoto.image = UIImage(data: data as Data) // REMOVE
finished(data,nil) //ADD
}else{
finished(nil,error) //ADD
}
}
}
}
})
}
And then you call it like:
createListProductsGood { imageData, error in guard let value = imageData, error == nil else { // present an alert and pass the error message return }
...
let image = UIImage(data: imageData)
// update UI from main Thread:
DispatchQueue.main.async {
self.ProductId = active
self.productPhoto.image = image } }
Basically this way the createListProductsGood takes in 2 closures, one for if the image is present, another for if an error was returned.

Mulitple calls to meetup api swift

I am trying to get a list of events from the meetup's api. Its crashes when request mulitple times as it states can only request once and is limited to 200 requests. I am getting groups then using the "urlName" api call to get the event coming up for that group. The result would be an array of events from a bunch of meetup groups. Here is my code.
func getEventsFromMeetup(complete: (groups: [Meetup], succes: Bool) -> Void) {
var currentUserInterests = [String]()
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let recommendedBaseUrl = "https://api.meetup.com/recommended/groups?key=\(meetupAPIKey)"
let url = NSURL(string: recommendedBaseUrl)
let request = NSMutableURLRequest(URL: url!)
request.HTTPMethod = "GET"
session.dataTaskWithRequest(request) { (data, response, error) in
guard error == nil else {
print(error)
complete(groups: [Meetup](), succes: false)
return
}
guard let data = data else {
print("Error with data")
complete(groups: [Meetup](), succes: false)
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments) as! [NSDictionary]
var groups = [Meetup]()
CurrentUserFM.sharedInstance.getCurrentUserInterests { (interests) in
currentUserInterests = interests
var ints = [String]()
print(json.count)
for j in json {
let m = Meetup(data: j)
ints.append(m.name!)
if let i = m.interestName {
if currentUserInterests.contains(i) {
groups.append(m)
}
}
print("ints: \(ints.count)")
print("json: \(json.count)")
if Int(ints.count) >= Int(json.count) {
dispatch_async(dispatch_get_main_queue(), {
complete(groups: groups, succes: true)
return
})
}
}
}
}catch {
print(error)
}
}.resume()
}
func getEventsForGroups(completionHandler: (meetupEvents: [MeetupEvent]) -> ()) {
self.getEventsFromMeetup { (groups, success) in
var meetupEvents1 = [MeetupEvent]()
var ints = [String]()
for group in groups {
let eventBaseUrl = "https://api.meetup.com/\(group.urlname!)?key=\(meetupAPIKey)"
let url = NSURL(string: eventBaseUrl)
let request = NSMutableURLRequest(URL: url!)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
session.dataTaskWithRequest(request, completionHandler: { (data, reponse, error) in
guard error == nil else {
print(error)
return
}
guard let data = data else {
print("Error with data")
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
let m = MeetupEvent()
if let name = json["name"] as? String {
m.name = name
}
if let link = json["link"] as? String {
m.link = link
}
if let interestName = group.name {
m.interestName = interestName
}
if let image = json["key_photo"]??["thumb_link"] as? String {
m.image = image
}
meetupEvents1.append(m)
ints.append("1")
if Int(ints.count) >= Int(groups.count) {
dispatch_async(dispatch_get_main_queue(), {
completionHandler(meetupEvents: meetupEvents1)
return
})
}
}catch {
print(error)
}
}).resume()
}
}
}
Any suggestions on how to get the events from the groups so that the app wont crash from meetup calls?

What could possibly cause a memory leak in this code?

I've been trying to find out what causes memory leaks, but in Instruments, I am being told that the memory leak happens at seriesDownloadingQueue.addOperation(downloadOperation) and in the class that calls the method getSeries(), which starts the updating process.
I'm completely new to asynchronous programming and memory leaks. I've read some posts on stack overflow about finding and fixing the leaks. I've also read an article from http://www.raywenderlich.com on how to use Instruments. This app is a database preloader. It downloads and processes information. The .sqlite file will be used in a mobile app.
Below is the code which allegedly causes the memory leak. If you need more information, I'll provide it.
import Foundation
import CoreData
class SerieFetcher: NSObject{
dynamic var didGetSeries: Bool = false
static var doneSeries: Int = 0
func getSeries(){
var seriesDownloadingQueue: NSOperationQueue{
let val = NSOperationQueue()
val.maxConcurrentOperationCount = 32
val.name = "Serie Downloading & Processing Queue"
return val
}
var defaultSessionConfiguration:NSURLSessionConfiguration{
let val = NSURLSessionConfiguration.defaultSessionConfiguration()
val.HTTPMaximumConnectionsPerHost = 20
return val
}
let defaultSession: NSURLSession = NSURLSession(configuration: defaultSessionConfiguration,delegate: nil, delegateQueue: seriesDownloadingQueue)
if let countries = fetchCountries(){
for country in countries{
if let url = NSURL(string:(BASE_URL + "series/"+CAT_STAMPS+"producer/\(country.0)")){
let downloadOperation = downloadSeriesOperation(downloadURL: url, countryObjectID: country.1, countryCount: countries.count, defaultSession: defaultSession , completionHandler: { [weak self](didGetSeries) in
if(didGetSeries == true){
self!.didGetSeries = didGetSeries
print("Finished Downloading Series")
}
})
downloadOperation.completionBlock = nil
seriesDownloadingQueue.addOperation(downloadOperation)
}
}
}
}
func fetchCountries() -> [Int: NSManagedObjectID]?{
let fetchRequest = NSFetchRequest(entityName: "Country")
fetchRequest.resultType = .DictionaryResultType
let objectIDDesc = NSExpressionDescription()
objectIDDesc.name = "objectID"
objectIDDesc.expression = NSExpression.expressionForEvaluatedObject()
objectIDDesc.expressionResultType = .ObjectIDAttributeType
fetchRequest.propertiesToFetch = ["countryID",objectIDDesc]
fetchRequest.returnsDistinctResults = true
do{
let results = try managedContext.executeFetchRequest(fetchRequest) as! [NSDictionary]
var countryIDs: [Int: NSManagedObjectID] = [:]
for result in results{
let countryID: Int = result.valueForKey("countryID") as! Int
let objectID: NSManagedObjectID = result.valueForKey("objectID") as! NSManagedObjectID
countryIDs.updateValue(objectID, forKey: countryID)
}
return countryIDs
}catch let error as NSError{
print(error.localizedDescription)
}
return nil
}
}
class downloadSeriesOperation: NSOperation{
let countryObjectID:NSManagedObjectID
let downloadURL:NSURL
let countryCount:Int
let defaultSession:NSURLSession
let completionHandler: (didGetSeries: Bool) -> Void
init(downloadURL:NSURL, countryObjectID: NSManagedObjectID,countryCount: Int, defaultSession:NSURLSession, completionHandler: (didGetSeries:Bool) -> Void){
self.downloadURL = downloadURL
self.countryObjectID = countryObjectID
self.countryCount = countryCount
self.defaultSession = defaultSession
self.completionHandler = completionHandler
}
override func main() {
let dataTask = defaultSession.dataTaskWithURL(downloadURL, completionHandler: { (data, response, error) in
let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateMOC.persistentStoreCoordinator = managedContext.persistentStoreCoordinator
privateMOC.undoManager = nil
var parsedData: NSArray?
do{
parsedData = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions()) as? NSArray
}catch let error as NSError{
print(error.localizedDescription)
}
for val in parsedData!{
if let serieID = Int(val[0] as! NSString as String){
if let serieName = val[1] as? NSString as? String{
if serieID == 0{
continue
}
let serie = NSEntityDescription.insertNewObjectForEntityForName("Serie", inManagedObjectContext: privateMOC) as! Serie
serie.country = privateMOC.objectWithID(self.countryObjectID) as? Country
serie.serieID = serieID
serie.serieName = serieName
}
}
}
privateMOC.performBlock({
do{
try privateMOC.save()
privateMOC.reset()
}catch let error as NSError{
print(error.localizedDescription)
}
})
SerieFetcher.doneSeries += 1
print(self.countryCount,"/",SerieFetcher.doneSeries)
if(SerieFetcher.doneSeries == self.countryCount){
self.completionHandler(didGetSeries: true)
}
})
dataTask.resume() //Start the Download
}
}

Extra argument 'error' in call in swift

I am new to swift so please treat me as beginner.
I am following tutorial, this is pretty old tutorial and it has used GoogleMap framework whereas I am doing it with pod. In func geocodeAddress in MapTasks.swift file I am getting error called
Extra argument 'error' in call
func geocodeAddress(address: String!, withCompletionHandler completionHandler: ((status: String, success: Bool) -> Void)) {
if let lookupAddress = address {
var geocodeURLString = baseURLGeocode + "address=" + lookupAddress
geocodeURLString = geocodeURLString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
let geocodeURL = NSURL(string: geocodeURLString)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let geocodingResultsData = NSData(contentsOfURL: geocodeURL!)
let request = NSMutableURLRequest(URL: geocodingResultsData)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
(let data, let response, let error) in
if let _ = response as? NSHTTPURLResponse {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if error != nil {
print("error=\(error!)")
return
}
if let parseJSON = json {
}
} catch {
print(error)
}
}
}
task.resume()
else {
// Get the response status.
let status = dictionary["status"] as! String
if status == "OK" {
let allResults = dictionary["results"] as! Array<Dictionary<NSObject, AnyObject>>
self.lookupAddressResults = allResults[0]
// Keep the most important values.
self.fetchedFormattedAddress = self.lookupAddressResults["formatted_address"] as! String
let geometry = self.lookupAddressResults["geometry"] as! Dictionary<NSObject, AnyObject>
self.fetchedAddressLongitude = ((geometry["location"] as! Dictionary<NSObject, AnyObject>)["lng"] as! NSNumber).doubleValue
self.fetchedAddressLatitude = ((geometry["location"] as! Dictionary<NSObject, AnyObject>)["lat"] as! NSNumber).doubleValue
completionHandler(status: status, success: true)
}
else {
completionHandler(status: status, success: false)
}
}
})
}
else {
completionHandler(status: "No valid address.", success: false)
}
}
So far I know is I am getting this error because of the diffrent version of swift. Tutorial I am following is written in old version of swift and I am doing it in new
In Swift 2.0, you cannot add 'error' argument in NSJSONSerialization method, you need to use try-catch statement as follows:
func geocodeAddress(address: String!, withCompletionHandler completionHandler: ((status: String, success: Bool) -> Void)) {
if let lookupAddress = address {
var geocodeURLString = baseURLGeocode + "address=" + lookupAddress
geocodeURLString = geocodeURLString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
let geocodeURL = NSURL(string: geocodeURLString)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let geocodingResultsData = NSData(contentsOfURL: geocodeURL!)
let request = NSMutableURLRequest(URL: geocodeURL!)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
(let data, let response, let error) in
if let _ = response as? NSHTTPURLResponse {
do {
let dictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if error != nil {
print("error=\(error!)")
return
}
if let parseJSON = dictionary {
let status = dictionary["status"] as! String
if status == "OK" {
let allResults = dictionary["results"] as! Array<Dictionary<NSObject, AnyObject>>
self.lookupAddressResults = allResults[0]
// Keep the most important values.
self.fetchedFormattedAddress = self.lookupAddressResults["formatted_address"] as! String
let geometry = self.lookupAddressResults["geometry"] as! Dictionary<NSObject, AnyObject>
self.fetchedAddressLongitude = ((geometry["location"] as! Dictionary<NSObject, AnyObject>)["lng"] as! NSNumber).doubleValue
self.fetchedAddressLatitude = ((geometry["location"] as! Dictionary<NSObject, AnyObject>)["lat"] as! NSNumber).doubleValue
completionHandler(status: status, success: true)
}
else {
completionHandler(status: status, success: false)
}
}
} catch {
print(error)
}
}
}
task.resume()
})
}
}