Updating an URLSession to swift 3 throwing error - swift3

I updated my code to Swift 3 and most of it converted over fine except from the URLSession and I cant find a solution to this error:
Cannot invoke 'dataTask' with an argument list of type '(with: NSMutableURLRequest, completionHandler: (Data?, URLResponse?, NSError?) -> Void)'
This is my code:
let post:NSString = "username=\(username)&userPassword=\(password)&userEmail=\(email)" as NSString
let url:URL = URL(string: "http://ec2-54-201-55-114.us-west-2.compute.amazonaws.com/wickizerApp/ApplicationDB/scripts/registerUser.php")!
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = post.data(using: String.Encoding.utf8.rawValue)
URLSession.shared.dataTask(with: request, completionHandler: { (data:Data?, response:URLResponse?, error:NSError?) -> Void in
DispatchQueue.main.async
{
if error != nil {
self.displayAlertMessage(error!.localizedDescription)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parseJSON = json {
let status = parseJSON["status"] as? String
if( status! == "200")
{
let myAlert = UIAlertController(title: "Alert", message: "Registration successful", preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default){(action) in
self.dismiss(animated: true, completion: nil)
}
myAlert.addAction(okAction);
self.present(myAlert, animated: true, completion: nil)
} else {
let errorMessage = parseJSON["message"] as? String
if(errorMessage != nil)
{
self.displayAlertMessage(errorMessage!)
}
}
}
} catch{
print(error)
}
}
}).resume()
Is there a different way to do requests in swift 3 or did they just change the way to do them?

The compiler wants URLRequest and Error
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = post.data(using: .utf8)
URLSession.shared.dataTask(with: request, completionHandler: { (data:Data?, response:URLResponse?, error:Error?) -> Void in
})
or still shorter
URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
})
or still shorter
URLSession.shared.dataTask(with: request) { (data, response, error) in
}

Related

waiting until URLSession.shared.dataTask ends

I have the below code. I got print "OK Call" before to print (finalData). I know the reason is URLSession goes in parallel, but my question is: How could avoid the parallel task and wait until URLSession ends ? THANKS
import SwiftUI
struct ContentView: View {
var body: some View {
Button ("Action", action: {
self.checkLogin(username:"test", password:"123456")
print ("OK Call")
} ) }
func checkLogin (username: String, password: String) {
var body: [String:String] = [:]
guard let url = URL(string: "http://test/apple/login.php") else { return }
body = ["user": username, "password": password]
let finalBody = try! JSONEncoder().encode (body)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = finalBody
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
URLSession.shared.dataTask(with: request) { (data,response,error) in
if let error = error { print ("Error: \(error)")
return
}
if let data = data {
let finalData = try! JSONDecoder().decode(ServerMessage.self, from: data)
print (finalData)
return
}
}.resume()
}
}
struct ServerMessage: Decodable {
let result: String
let nuser: String
}

I Found Error of Could Not Cast Value of Type when i load my json in Tableview

This is my code , could not append array type to UIImage , api is successfully loaded , i have problem in appending data
var images = UIImage
func downloadJsonWithURL() {
let url = NSURL(string: urlString)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSObject {
print(jsonObj!.value(forKey: "guid"))
if let actorArray = jsonObj!.value(forKey: "guid") as? [NSObject] {
if let actorDict = actorArray as? NSObject
{
if let name = actorDict.value(forKey: "rendered") {
**self.images.append(name as! UIImage)**
print("\(name)")
}
}
}
OperationQueue.main.addOperation({
self.tableView.reloadData()
})
}
}).resume()
}
this is my rest api
guid {1}
rendered : http://thenewschef.com/wp-content/uploads/2018/02/startup.jpeg
So, You Can Do This
var images = [[String:AnyObject]]()
override func viewDidLoad() {
super.viewDidLoad()
downloadJsonWithURL()
}
//Tableview methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return images.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 135
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DemoTableCell", for: indexPath) as! DemoTableCell
let dict = images[indexPath.row]
URLSession.shared.dataTask(with: NSURL(string: dict["rendered"] as! String)! as URL, completionHandler: { (data, response, error) -> Void in
if error != nil {
print(error as Any)
return
}
DispatchQueue.main.async(execute: { () -> Void in
let image = UIImage(data: data!)
cell.imgView?.image = image
})
}).resume()
return cell
}
//your api call
func downloadJsonWithURL() {
let urlString = "https://thenewschef.com/wp-json/wp/v2/media"
let url = NSURL(string: urlString)
print(url as Any)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) {
print((jsonObj as AnyObject).value(forKey: "guid") as Any)
let responseJSON = (jsonObj as AnyObject).value(forKey: "guid") as Any
let json = (responseJSON as AnyObject) as? NSArray
self.images = json as! [[String:AnyObject]]
print(self.images)
OperationQueue.main.addOperation({
self.demoTable.reloadData()
})
}
}).resume()
}
That's it you got your UIImage.
Enhanced implementation of above solution using Higher order function to avoid all the cast dance.
Use the below code to fetch the response form Server & filter the required imageUrl's in a single array.
func downloadJsonWithURL() {
let urlString = "https://thenewschef.com/wp-json/wp/v2/media"
let url = NSURL(string: urlString)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {[weak self] (data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) {
let guids = (jsonObj as? [[String: Any]])?.map { $0["guid"] }
let imagesArray = (guids as? [[String: Any]])?.map {$0["rendered"]} as? [String]
OperationQueue.main.addOperation({
//Reload Table here...
})
}
}).resume()
}

Profile Image does not appear when I run the app.

Theres no error in my code but ImagevIew image doesn't show
let imageCache = NSCache()
extension UIImageView {
func loadImageUsingCacheWithUrlString(urlString: String) {
//self.image = nil
if let cachedImage = imageCache.object(forKey: urlString as AnyObject) as? UIImage {
self.image = cachedImage
return
}
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async(execute: {
if let currImage = UIImage(data: data!) {
imageCache.setObject(currImage, forKey: urlString as AnyObject)
self.image = currImage
}
})
}).resume()
}
}

Swift 3 JsonSerialization

Code
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnGirisYap(_ sender: Any) {
let url = NSURL(string: "http://www.kerimcaglar.com/yemek-tarifi")!
let task = URLSession.shared.dataTask(with: url as URL) { (data, response, error) -> Void in
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String:AnyObject]
//print (jsonResult)
self.txtGirisKullaniciAdi.text = jsonResult["malzemeler"] as! NSString as String
} catch {
print("JSON serialization failed")
}
} else {
print("ERROR FOUND HERE")
}
}
task.resume()
}
}
Can you help with this?
The error message tells you clearly that the deserialized object is an array rather than a dictionary.
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: []) as! [[String:Any]]
for item in jsonResult {
print(item["malzemeler"] as! String) // cast directly to String
}
Notes:
The unspecified JSON dictionary type in Swift 3 is [String:Any].
The mutableContainers option is useless in Swift.

How to go to other view controller when signed in from a google account ? (swift 3) if possible

I did this: "SecondViewController" is the view controller I want to go to:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "idSegueContent" {
secondViewController = segue.destinationViewController as! SecondViewController //Error is here
}
}
public func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if (error) != nil {
print(error)
}
else {
performSegue(withIdentifier: "idSegueContent", sender: self)
}
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
if let err = error {
print(error)
}
SecondViewController.dismissViewControllerAnimated(true, completion: nil)
//Error is here too
}
I am trying to login using Gmail account and show the user information in another page when the user is logged in.
You can add this code that will help you navigate to other ViewControllers:
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if error != nil
{
print(error ?? "google error")
return
}
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "navigation") as! NavigationController
self.present(newViewController, animated: false, completion: nil)
// lblUserName.text = user.profile.email
}