JSONService
During the http request process, completion nil is returned. completion does not work.. but print function is working. how can i fix this problem. I am using http request for the first time. my English is bad. I'm sorry for that.
class JSONService {
let parameters = ["index": "articles"]
func getNews(completion: #escaping (NewsRoot) -> ()) {
guard let url = URL(string: "http://yazar.io/api/v2/search/") else { return }
let session = URLSession.shared
var request = URLRequest(url: url)
request.httpMethod = "POST"
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request as URLRequest) { (data, response, error) in
guard error == nil else { return }
guard let data = data else { return }
do {
let news = try JSONDecoder().decode(NewsRoot.self, from: data)
DispatchQueue.main.async {
completion(news) //does not work
print(news) //works
}
} catch let error {
print(error.localizedDescription)
}
}
task.resume()
}
}
DataStore
class DataStore: ObservableObject {
#Published var news: [News] = []
init() {
getNews()
}
func getNews() {
JSONService().getNews { (news) in
self.news = news.articles
}
}
}
ContentView
#ObservedObject var news = DataStore()
I am working on implementing human face recognition into an iOS application. I receive back many tags like 'glasses' or 'smiling' but don't see an actual variable that tells me it is a human face (and with what degree of confidence).
What variable am I missing and how can we use that functionality?
I think that you may not using the correct feature type as it is seems that you are getting labels instead of facial attributes.
I recommend you to check the Detecting Faces and Face Detection Tutorial documentation where you can find detailed information and some useful examples that you can use as a reference to know more about the process of detecting faces with Vision API.
You can follow few steps to detect faces from an image.
Create your URLRequest
func createRequest() -> URLRequest? {
// Create your request URL
if let url = URL(string: "YOUR_API_KEY") {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue(Bundle.main.bundleIdentifier ?? "", forHTTPHeaderField: "X- Ios-Bundle-Identifier")
let jsonRequest = [
"requests": [
"features": [
[
"type": "FACE_DETECTION",
"maxResults": 10 //change as per your requirement
]
]
]
]
let jsonData = try? JSONSerialization.data(withJSONObject: jsonRequest)
request.httpBody = jsonData
return request
}
return nil
}
Run the request in background thread
let task: URLSessionDataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "")
return
}
print(data)// Analyze with this data
}
task.resume()
Analyze data (on main thread if you want to update any UI component)
DispatchQueue.main.async(execute: {
do {
guard let json =
try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { return }
guard let responses = json["responses"] as? NSArray else { return }
if responses.count > 0 {
guard let response = responses.firstObject as? [String: Any] else { return }
guard let faceAnnotations = response["faceAnnotations"] as? NSArray else {
print(false, "No face detected, please try another photo.")
return
}
if faceAnnotations.count > 0 {
print("Face successfully detected: \(faceAnnotations.count)")
} else {
print("No face detected, please try another photo.")
}
} else {
print("Error while face detection process, please try again.")
}
} catch {
print("Error while face detection process, please try again.")
}
})
I am trying to upload images to Firebase like this:
let storageRef = Storage().reference()
if let uploadData = self.profileImageView.image!.pngData() {
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil {
print(error as Any)
return
}
print(metadata as Any)
})
}
and it's redirecting me to this code here:
- (void)dispatchAsync:(void (^)(void))block {
dispatch_async(self.dispatchQueue, block);
}
It does not get past the if let statement. (if let uploadData = self.profileImageView.image!.pngData())
I have no idea why. It does not give me any additional error messages in the console.
The answer by king_T did not work for me. The issue is related to this line
Storage().reference()
As noted in this post you should use
Storage.storage().reference()
It's very unintuitive.
I just had similar issues, and I solved it by compressing my image.
let scaledimage = self.profileImageView.image!.jpegData(compressionQuality: 0.5)
let storageRef = Storage().reference()
if let uploadData = scaledimage {
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil {
print(error as Any)
return
}
print(metadata as Any)
})
}
that solved it for me.
I have this code which- as far as I understand- is async:
func testConnection() -> Bool {
let url = URL(string: uri)!
let task = URLSession.shared.dataTask(with: url) {
(data, response, error) in
guard let data = data, let _:URLResponse = response , error == nil else {
print("error")
return
}
let dataString = String(data: data, encoding: String.Encoding.utf8)
}
task.resume()
}
How would a synchronous version look that allows to return the testConnection result to the sender?
You could use a semaphore to wait for the async call to finish:
func testConnection() -> Bool {
let url = URL(string: uri)!
var dataStringOrNil: String?
let semaphore = DispatchSemaphore(value: 0)
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
defer {
semaphore.signal()
}
guard let data = data, error == nil else {
print("error")
return
}
dataStringOrNil = String(data: data, encoding: .utf8)
}
task.resume()
semaphore.wait()
guard let dataString = dataStringOrNil else {
return false
}
// some substring checking
return dataString.contains("href")
}
I wouldn't recommend it, but there can be reasons for sync calls. We use them sometimes in command-line tools.
I'm new here, and this is my first question...
I try to write an App in Swift 2 that makes an HTTP POST request but I can't figure out how to use the new error handling of Swift 2. Can anyone tell me please how to implement the "do-try-catch" error handling of Swift 2 to the code snippet below?
(This code snippet uses the old error handling of swift 1.2)
func post(params : Dictionary<String, String>, url : String) {
var request = NSMutableURLRequest(URL: NSURL(string: url)!)
var session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil/*, error: &err*/)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
print("Response: \(response)")
var strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Body: \(strData)")
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves/*, error: &err*/) as? NSDictionary
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
print(err!.localizedDescription)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
}
else {
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
var success = parseJSON["success"] as? Int
print("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
}
}
})
task!.resume()
}
You presumably want to wrap your NSJSONSerialization calls in do/try/catch logic as shown below.
In Swift 3:
var request = URLRequest(url: URL(string: urlString)!)
let session = URLSession.shared
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.httpBody = try! JSONSerialization.data(withJSONObject: parameters)
// or if you think the conversion might actually fail (which is unlikely if you built `parameters` yourself)
//
// do {
// request.httpBody = try JSONSerialization.data(withJSONObject: parameters)
// } catch {
// print(error)
// }
let task = session.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("error: \(error)")
return
}
// this, on the other hand, can quite easily fail if there's a server error, so you definitely
// want to wrap this in `do`-`try`-`catch`:
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
let success = json["success"] as? Int // Okay, the `json` is here, let's get the value for 'success' out of it
print("Success: \(success)")
} else {
let jsonStr = String(data: data, encoding: .utf8) // No error thrown, but not dictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError) // Log the error thrown by `JSONObjectWithData`
let jsonStr = String(data: data, encoding: .utf8)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
Or, in Swift 2
let request = NSMutableURLRequest(URL: NSURL(string: urlString)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(parameters, options: [])
// or if you think the conversion might actually fail (which is unlikely if you built `parameters` yourself)
//
// do {
// request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: [])
// } catch {
// print(error)
// }
let task = session.dataTaskWithRequest(request) { data, response, error in
guard let data = data where error == nil else {
print("error: \(error)")
return
}
// this, on the other hand, can quite easily fail if there's a server error, so you definitely
// want to wrap this in `do`-`try`-`catch`:
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary {
let success = json["success"] as? Int // Okay, the `json` is here, let's get the value for 'success' out of it
print("Success: \(success)")
} else {
let jsonStr = String(data: data, encoding: NSUTF8StringEncoding) // No error thrown, but not NSDictionary
print("Error could not parse JSON: \(jsonStr)")
}
} catch let parseError {
print(parseError) // Log the error thrown by `JSONObjectWithData`
let jsonStr = String(data: data, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
}
}
task.resume()
I'd also suggest being a little more careful about forced unwrapping of data, because you want to detect/handle the errors, not crash. For example, above I use a guard statement to unwrap it.
In general if a function throws you have to write it inside a do catch block or just mark the outer scope function (in this case post) as throws:
func post(params : Dictionary<String, String>, url : String) {
let request = NSMutableURLRequest(URL: NSURL(string: url)!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
do {
request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: .PrettyPrinted)
} catch {
//handle error. Probably return or mark function as throws
print(error)
return
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
// handle error
guard error == nil else { return }
print("Response: \(response)")
let strData = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Body: \(strData)")
let json: NSDictionary?
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
} catch let dataError {
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
print(dataError)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
// return or throw?
return
}
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
let success = parseJSON["success"] as? Int
print("Succes: \(success)")
}
else {
// Woa, okay the json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: \(jsonStr)")
}
})
task!.resume()
}
If you don't want to handle these errors right in your post function you can just declare it as throws than you don't have to use do catch at all