swift do task after the preview task is finished - mysql

In my swift 2 app i would like to make an http-post-request to get data of my mysql database. After that I would like to write this data into my core data.
I have the code part for request and write.
How do I get the following structure.
Request Data
if request data complete write in into core data
Could this be the correct thing?
This is my SyncMYSQL function in my Sync.swift file.
class func SyncMYSQL() {
print("START SYNC MYSQL")
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
let managedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let defaults = NSUserDefaults.standardUserDefaults()
let request = NSMutableURLRequest(URL: NSURL(string: "https://xxx")!)
request.HTTPMethod = "POST"
let postString = "userid=12"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
// if no internet connection
guard error == nil && data != nil else {
print("error=\(error)")
return
}
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)!
let fetchRequest = NSFetchRequest(entityName: "ITEMS")
fetchRequest.returnsObjectsAsFaults = false
do {
let results = try managedObjectContext!.executeFetchRequest(fetchRequest)
for managedObject in results {
let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
managedObjectContext!.deleteObject(managedObjectData)
}
} catch let error as NSError {
print("Detele all data in ITEMS error : \(error) \(error.userInfo)")
}
var x = 0
while (x < responseString.count ) {
let newItem = NSEntityDescription.insertNewObjectForEntityForName("ITEMS", inManagedObjectContext: managedObjectContext!) as! CoreData_ITEMS
newItem.name = responseString[x]
x++
}
dispatch_sync(dispatch_get_main_queue(),{
print("FINISH MYSQL")
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
});
}
task.resume()
}
This function i call from my view controller like this way:
func RequestData() {
Sync.SyncMYSQL()
print ("Start Core Data")
let fetchRequest = NSFetchRequest(entityName: "ITEMS")
do {
try data = managedObjectContext!.executeFetchRequest(fetchRequest) as! [CoreData_ITEMS]
} catch { }
Table.reloadData()
}

You should use closure blocks as callback when the operation ends
class func SyncMYSQL(onSuccess: ()->()){
// your custom events
// your custom events
// your custom events
if MYSQLisSynced == true {
// when MYSQL is synced you can call the success block
onSuccess()
}
}
In other file when you call the function SyncMYSQL() you have to specify the on success block
SyncMYSQL { () -> () in
//custom callback actions
}

Related

Parsed JSON not updating on api call for a long time

For some reason the JSON object from parsing doesnt update after network calls to and api we built. I check the endpoint and now for a fact it updates right away. I have a timer being called every 10 sec to make the call but the parsed json doesnt update until after a minute or so. I have tried putting it on the main thread and that still doesnt work. Here is my code:
#objc func getLaunches() {
let simulator = UserDefaults.standard.string(forKey: self.launchSimulator)
if(simulator == self.password){
print("they are the same")
}
guard let launchUrl = URL(string: launchesURL) else {
return
}
let request = URLRequest(url: launchUrl)
DispatchQueue.main.async { [weak self] in
let task = URLSession.shared.dataTask(with: request, completionHandler: {
(data, response, error) -> Void in
if let error = error {
print(error)
return
}
// Parse JSON data
if let data = data {
self?.launches.removeAll()
self?.launches = (self!.parseJsonData(data: data))
let nextlaunch = self?.launches[0]
// Reload table view
self?.hours = nextlaunch?.time
self?.yearMonth = nextlaunch?.date
var fulltime = self?.yearMonth
fulltime!.insert("-", at: fulltime!.index(fulltime!.startIndex, offsetBy: 4))
fulltime!.insert("-", at: fulltime!.index(fulltime!.startIndex, offsetBy: 7))
fulltime = fulltime! + " "
fulltime = fulltime! + self!.hours
let fullFormatter = DateFormatter()
fullFormatter.dateFormat = "YYYY-MM-dd HH:mm"
fullFormatter.timeZone = TimeZone(abbreviation: "EST")
self?.launchDate = fullFormatter.date(from: fulltime!)
self?.getCountdown()
}
})
task.resume()
}
}
//parse launch info from json to dictionary into launches object
func parseJsonData(data: Data) -> [NextLaunch] {
var launches = [NextLaunch]()
do {
let jsonResult = try JSONSerialization.jsonObject(with: data, options:
JSONSerialization.ReadingOptions.allowFragments) as? NSDictionary
let jsonLaunches = jsonResult?["launches"] as! [NSDictionary]
for jsonLaunch in jsonLaunches {
let launch = NextLaunch()
launch.date = jsonLaunch["date"] as! String
launch.time = jsonLaunch["time"] as! String
if(launch.time == ""){
launch.time = "00:00"
}
launch.mission = jsonLaunch["mission"] as! String
launch.launchpad = jsonLaunch["launch_pad"] as! String
launch.image = jsonLaunch["image"] as! String
launch.delay = jsonLaunch["delayed"] as! String
//show delay image if it is delayed
if(launch.delay == "1"){
self.delayed()
}else{
self.notDelayed()
}
launches.append(launch)
}
} catch {
print(error)
}
return launches
}
You need
DispatchQueue.main.async {
self?.getCountdown()
}
As the response of URLSession.shared.dataTask(with: occurs in a background thread

Global Function to Return Parsed JSON?

I'm trying to make this method accessible throughout the app because there are many view controllers need JSON response depending on the path and the language parameters, but I'm not sure what pattern to use or how to structure the app.
func fetchJsonFor(path: String, langugae: String) -> AnyObject{
var components = URLComponents()
components.scheme = Constants.APIScheme
components.host = Constants.APIHost
components.path = Constants.APIPath
components.path.append(path)
components.path.append(langugae)
let request = URLRequest(url: components.url!)
var parsedJSON: AnyObject!
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil{
print(error?.localizedDescription ?? "Error")
return
}
guard let data = data else{
return
}
do{
parsedJSON = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as AnyObject
} catch{
print("Can't parse JSON: \(data)")
return
}
}
task.resume()
return parsedJSON
}
You can go for Single Tone Design pattern.
Also remember you can't return the URLRequest response as functions return. It is a asynchronous task which not works in main thread. So return will not work.
You need to make use of closure ----> a completion block will more suitable.
class WebService {
static let shared = WebService()
func fetchJsonFor(path: String, langugae: String,completion:((Any?) -> Void)){
var components = URLComponents()
components.scheme = Constants.APIScheme
components.host = Constants.APIHost
components.path = Constants.APIPath
components.path.append(path)
components.path.append(langugae)
let request = URLRequest(url: components.url!)
var parsedJSON: AnyObject!
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil{
print(error?.localizedDescription ?? "Error")
completion(nil)
}
guard let data = data else{
completion(nil)
}
do{
parsedJSON = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
completion(parsedJSON)
} catch{
print("Can't parse JSON: \(data)")
completion(nil)
}
}
task.resume()
}
}
How to use..
From your ViewController Class you can call web service like
WebService.shared.fetchJsonFor(path: "YOUR_PATH", langugae: "YOUR_LANGUAGE") { (response) in
if let response = response{
// Success response
}else{
//Failed response
}
}

Swift 3 GET request unable to display returned values

Trying to make a GET request with Swift 3 and Xcode8 but not having much luck outputting data I received back from my GET request to the Main.Storyboard either in a label or a text field all I get is all the returned JSON in the console in Xcode8.
There is a snippet of JSON that is returned with my request in Xcode8 which I have attached below for reference. I can access "#encoding" and "#version" but everything else is not able to be accessed and I am not able to figure out why. If this was a web based setup I could just declare a variable and then set it equal to someObject.petfinder[1].shelters etc...
This is my code that is making the request, taking a zipcode from an input field and then building the url and returning it which then is using NSDictionary.
The error I get back in the console is:
"fatal error: unexpectedly found nil while unwrapping an Optional value
2017-06-20 12:15:49.392688 PetFinder[47445:9486946] fatal error: unexpectedly found nil while unwrapping an Optional value"
// SEND HTTP GET REQUEST
// DEFINE SERVER SIDE SCRIPT URL
let scriptUrl = "https://api.petfinder.com/"
let methodType = "shelter.find"
let apiKey = "?key=0000000000000000000000000"
let urlWithParams = scriptUrl + methodType + apiKey + "&location=\(shelterZip)&format=json"
// CREATE NSURL Object
let myUrl = NSURL(string: urlWithParams)
// CREATE URL REQUEST
let request = NSMutableURLRequest(url:myUrl! as URL);
// REQUEST METHOD - GET / POST
request.httpMethod = "GET"
// RUN HTTP REQUEST
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
if error != nil {
print("error \(error!)")
return
}
// PRINT OUT RESPONSE STRING
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(String(describing: responseString))")
// CONVERT RECEIVED JSON TO NSDictionary
do {
if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
// Print out dictionary
print(convertedJsonIntoDict)
// Get value by key
let shelterName = convertedJsonIntoDict["shelters"] as? [String: Any]
for(key, pair) in convertedJsonIntoDict {
print("-->\(key) \(pair)")
}
print(shelterName!)
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
task.resume()
}
// SNIPPET OF RETURNED JSON FROM THE TOP
{
"#encoding" = "iso-8859-1";
"#version" = "1.0";
petfinder = {
"#xmlns:xsi" = "http://www.w3.org/2001/XMLSchema-instance";
"#xsi:noNamespaceSchemaLocation" = "http://api.petfinder.com/schemas/0.9/petfinder.xsd";
header = {
status = {
code = {
"$t" = 100;
};
message = {
};
};
timestamp = {
"$t" = "2017-06-20T16:15:49Z";
};
version = {
"$t" = "0.1";
};
};
lastOffset = {
"$t" = 25;
};
shelters = {
shelter = (
{
address1 = {
};
address2 = {
};
city = {
"$t" = Nebraska;
};
country = {
"$t" = US;
};
email = {
"$t" = "wooffun#woof.net";
};
fax = {
};
id = {
"$t" = NE117;
};
latitude = {
"$t" = "13.004";
};
longitude = {
"$t" = "-31.449";
};
name = {
"$t" = WOOF COMPANY;
};
phone = {
};
state = {
"$t" = NE;
};
zip = {
"$t" = 68001;
};
},
First of all – and as always
Do not use NSDictionary in Swift. You throw away the type information.
Do not use Foundation classes like NSURL, NS(Mutable)URLRequest if there is a native Swift counterpart.
A GET request does not require an URLRequest at all, it's the default.
Second of all lets use a type alias for convenience reasons.
typealias JSONDictionary = [String:Any]
This code is supposed to extract the keys and values you are looking for
let scriptUrl = "https://api.petfinder.com/"
let methodType = "shelter.find"
let apiKey = "?key=0000000000000000000000000"
let urlWithParams = scriptUrl + methodType + apiKey + "&location=\(shelterZip)&format=json"
// CREATE NSURL Object
let myUrl = URL(string: urlWithParams)!
// RUN HTTP REQUEST
let task = URLSession.shared.dataTask(with: myUrl) { data, response, error in
if error != nil {
print("error \(error!)")
return
}
// CONVERT RECEIVED JSON TO NSDictionary
do {
if let rootDictionary = try JSONSerialization.jsonObject(with: data!) as? JSONDictionary,
let petfinder = rootDictionary["petfinder"] as? JSONDictionary {
// Get value by key
if let shelters = petfinder["shelters"] as? JSONDictionary,
let shelter = shelters["shelter"] as? [JSONDictionary] {
for item in shelter {
for (key, value) in item {
print("-->\(key) \(value)")
}
}
}
}
} catch {
print(error.localizedDescription)
}
}
task.resume()

Return NSURLSession response to its calling function

I have written two following functions for using NSURLSession.
func getStringFromRequest(completionHandler:(success:Bool, data: NSData?) -> Void) {
let prefs = NSUserDefaults.standardUserDefaults()
var conn_timeout = prefs.stringForKey("conn_timeout")!
var IP = prefs.stringForKey("IP")!
var port = prefs.stringForKey("Port")!
prefs.synchronize()
var request = NSMutableURLRequest(URL: NSURL(string: "http://\(IP):\(port)/")!)
var response: NSURLResponse?
var error: NSError?
var jsonString = ["osname":"iOS","mobile_manufacturer" : "Apple","mobile_model" : "iPhone Simulator","osversion" : "8.4"] as Dictionary<String, String>
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(jsonString, options: nil, error: &error)
request.HTTPMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("gzip", forHTTPHeaderField: "Accept-encoding")
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) -> Void in
if let unwrappedError = error {
print("error=\(unwrappedError)")
}
else {
if let unwrappedData = data {
completionHandler(success: true, data: unwrappedData)
return
}
}
completionHandler(success: false, data: nil)
}
task.resume()
}
func performPost() -> NSDictionary {
var result = NSDictionary()
getStringFromRequest { (success, data) -> Void in
if (success) {
if let unwrappedData = data {
if let responseString = NSString(data: unwrappedData, encoding: NSUTF8StringEncoding) {
println("------------------>>>>>>NSURLSession>>>>>>>-------------------------->\n: \(responseString)")
result = (NSJSONSerialization.JSONObjectWithData(unwrappedData, options: NSJSONReadingOptions.allZeros, error: nil) as? NSDictionary)!
}
}
}
else {
print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Failed>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
}
}
}
I am calling the performPost function as follows:
self.connectionHelper.performPost()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), { ()->() in
println("self.connectionHelper.result>>>>>>========================================>>>>>>> : \(self.connectionHelper.result)!")
})
Output is as follow:
self.connectionHelper.result>>>>>>========================================>>>>>>> : {
}!
------------------>>>>>>NSURLSession>>>>>>>-------------------------->
After looking at the output of the performPost function I can say that the execution to the pritln function first but it is called later than performPost.
How can I set the value of result first in the performPost function then prints its value after completion of the performPost function.
Can it be possible?
Instead of calling dispatch_async to print the results, pass a completion handler block to your performPost method, and print the results in that completion handler block.

Swift: Return JSON string from NSURLSession task

I'd like to get token as String type, however the following code returns error as " "String" is not convertible to "Void" ".
Could you tell me what is the problem?
In order to parse JSON, I used SwiftyJSON
func authentication() -> String {
let request = NSMutableURLRequest(URL: NSURL(string: "https://~~~/v2/authenticate/api")!)
request.HTTPMethod = "POST"
var loginID = "my_ID"
var apiKey = "my_APIKEY"
var postString:NSString = "login_id=\(loginID)&api_key=\(apiKey)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
println("response = \(response)")
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("responseString = \(responseString)")
let json = JSON(data:data)
if let token = json["auth_token"].stringValue{
println("\(token)")
return token ///Error Here
}
}
task.resume()
}
※Edited Jan6th 7:50(GMP+9hr)
I edited as following, however I got error as ""Use of unresolved identifier "tokenString".
Please tell me how to solve the problem.
func authentication() -> String {
let request = NSMutableURLRequest(URL: NSURL(string: "https://~~~/v2/authenticate/api")!)
request.HTTPMethod = "POST"
var loginID = "my_ID"
var apiKey = "my_APIKEY"
var postString:NSString = "login_id=\(loginID)&api_key=\(apiKey)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
println("error=\(error)")
return
}
println("response = \(response)")
let responseString = NSString(data: data, encoding: NSUTF8StringEncoding)
println("responseString = \(responseString)")
let json = JSON(data:data)
if let token = json["auth_token"].stringValue{
println("\(token)")
tokenString = self.didReceiveAuthToken(token)///Edited
}
}
task.resume()
return tokenString
}
func didReceiveAuthToken(token : String) ->String{
return token
}
The dataTaskWithRequest closure takes a return type of void. Your method that returns a string ends immediately after task.resume() is executed and does not return anything.
Your basic problem is that you're applying synchronous thinking to an asynchronous task. One easy suggestion is to have authentication() return void (ie, nothing), and then make a separate method like didReceiveAuthToken(token : String) that is called by your completion handler when the token is received.