Adapting Swift code to work with Swift 3 - swift

I am new to Swift and XCode but just giving it a go at the moment to see how I get on.
Anyway, I have taken a look at some code by Belal Khan from this post to connect a phone app to a MySQL database. It seems it needs updating to work with the latest version of Swift though.
I've got through most of it I think, but I've got stuck updating one particular part.
//
// ViewController.swift
// SwiftPHPMySQL
//
// Created by Belal Khan on 12/08/16.
// Copyright © 2016 Belal Khan. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
//URL to our web service
let URL_SAVE_TEAM = "http://www.example.com/api/createteam.php"
//TextFields declarations
#IBOutlet weak var textFieldName: UITextField!
#IBOutlet weak var textFieldMember: UITextField!
//Button action method
#IBAction func buttonSave(sender: UIButton) {
//created NSURL
let requestURL = NSURL(string: URL_SAVE_TEAM)
//creating NSMutableURLRequest
let request = NSMutableURLRequest(URL: requestURL!)
//setting the method to post
request.HTTPMethod = "POST"
//getting values from text fields
let teamName=textFieldName.text
let memberCount = textFieldMember.text
//creating the post parameter by concatenating the keys and values from text field
let postParameters = "name="+teamName!+"&member="+memberCount!;
//adding the parameters to request body
request.HTTPBody = postParameters.dataUsingEncoding(NSUTF8StringEncoding)
//creating a task to send the post request
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){
data, response, error in
if error != nil{
print("error is \(error)")
return;
}
//parsing the response
do {
//converting resonse to NSDictionary
let myJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
//parsing the json
if let parseJSON = myJSON {
//creating a string
var msg : String!
//getting the json response
msg = parseJSON["message"] as! String?
//printing the response
print(msg)
}
} catch {
print(error)
}
}
//executing the task
task.resume()
}
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.
}
}
And here's what I've got so far with updating it...
//
// ViewController.swift
// SwiftPHPMySQL
//
// Created by Belal Khan on 12/08/16.
// Copyright © 2016 Belal Khan. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
//URL to our web service
let URL_SAVE_TEAM = "http://www.example.com/api/createteam.php"
//TextFields declarations
#IBOutlet weak var textFieldName: UITextField!
#IBOutlet weak var textFieldMember: UITextField!
//Button action method
#IBAction func buttonSave(sender: UIButton) {
//created NSURL
let requestURL = URL(string: URL_SAVE_TEAM)
//creating NSMutableURLRequest
let request = NSMutableURLRequest(url: requestURL!)
//setting the method to post
request.httpMethod = "POST"
//getting values from text fields
let teamName=textFieldName.text
let memberCount = textFieldMember.text
//creating the post parameter by concatenating the keys and values from text field
let postParameters = "name="+teamName!+"&member="+memberCount!;
//adding the parameters to request body
request.httpBody = postParameters.data(using: .utf8)
//creating a task to send the post request
let task = URLSession.sharedSession().dataTaskWithRequest(request){
data, response, error in
if error != nil{
print("error is \(error)")
return;
}
//parsing the response
do {
//converting resonse to NSDictionary
let myJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
//parsing the json
if let parseJSON = myJSON {
//creating a string
var msg : String!
//getting the json response
msg = parseJSON["message"] as! String?
//printing the response
print(msg)
}
} catch {
print(error)
}
}
//executing the task
task.resume()
}
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.
}
}
The error is on the line:
let task = URLSession.sharedSession().dataTaskWithRequest(request){
The error I get is Cannot call value of non-function type 'URLSession'

change it to this
URLSession.shared.dataTask(with: request, completionHandler: {data, response, error in
...
})

You are creating request as NSMutableURLRequest but, URLSession needs URLRequest
let request = URLRequest(url: NSURL(string: "") as! URL)
URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error == nil {
print("Seccess")
} else {
print("Error")
}
}
Thanks:)

Related

How to add the response from a GET request to an Array in SWIFT (Xcode)

I'm coming from a javascript background and am finding it difficult to understand how to store the response from a simple GET request in SWIFT.
I have an empty array named plants declared in my View Controller. The response from my GET request returns an array of plant names (strings). How can I assign the response array to the array plants?
The setup of my code looks like this:
class MyPlantsViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var addPlantTextField: UITextField!
var plants: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView(frame: CGRect.zero)
getAllPlants()
}
func getAllPlants() {
// Create URL
let url = URL(string: ".....com/api/plants")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print("error: \(error)")
} else {
if let response = response as? HTTPURLResponse {
print("statusCode: \(response.statusCode)")
}
if let data = data {
<<..... I have tried lots of things here......>>
}
}
}
task.resume()
}
......
You can use JSONDecoder to decode list of string as below,
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print("error: \(error)")
} else {
do {
self.plants = try JSONDecoder().decode([String].self, from: data!)
} catch {
print(error)
}
}
}

How to pass data from view controller to data model in swift

I am building a simple app that talks to a web service.
I have used the delegates method to communicate data (from my model to view controller).
But I am not sure how to read the data from view controller (text_field.text) in my model. I need to do that so that I can pass the right parameter to my webservice
my view controller is:
import UIKit
class ViewController: UIViewController,HomeModelDelegate {
var homeModel = HomeModel()
#IBOutlet weak var loginid: UITextField!
#IBOutlet weak var pwd: UITextField!
#IBAction func submit(_ sender: UIButton) {
homeModel.chkpwd()
//Here viewcontroller is assigning itself to the homemodel's delegate property
homeModel.delegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
loginid.layer.cornerRadius=10
pwd.layer.cornerRadius = 10
}
func itemsDownloaded(locations: [Location]) {
loginid.text = locations[0].pwd
}
}
My model code is:
import UIKit
protocol HomeModelDelegate{
func itemsDownloaded(locations:[Location])
}
class HomeModel: NSObject
{
var delegate:HomeModelDelegate?
func chkpwd()
{
//Hit the webservice url
let x = ViewController()
let z = x.loginid
let serviceUrl = "http://www.xyz.in/webservice.php?loginid=(loginid.text)"
//download the json data
let url = URL(string: serviceUrl)
if let url = url {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url, completionHandler:
{ (data, response, error) in
if error == nil {
//succeeded
self.parseJson(data!)
}
else {
//failed
}
})
task.resume()
}
}
func parseJson(_ data:Data){
var locArray = [Location]()
do{
let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as! [Any]
for jsonResult in jsonArray{
let jsonDict = jsonResult as! [String:String]
let loc = Location(pwd: jsonDict["loginid"]!, loginid: jsonDict["pwd"]!)
locArray.append(loc)
//pass the location back to the delegate
delegate?.itemsDownloaded(locations: locArray)
}
}
catch{
print("An error occured")
}
}
}
Please try this :
import UIKit
class ViewController: UIViewController,HomeModelDelegate {
var homeModel = HomeModel()
#IBOutlet weak var loginid: UITextField!
#IBOutlet weak var pwd: UITextField!
#IBAction func submit(_ sender: UIButton) {
homeModel.z = loginid.text! // ASSIGNING z here
homeModel.chkpwd()
//Here viewcontroller is assigning itself to the homemodel's delegate property
homeModel.delegate = self
}
override func viewDidLoad() {
super.viewDidLoad()
loginid.layer.cornerRadius=10
pwd.layer.cornerRadius = 10
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func itemsDownloaded(locations: [Location]) {
loginid.text = locations[0].pwd
}
}
Model :
import UIKit
protocol HomeModelDelegate{
func itemsDownloaded(locations:[Location])
}
class HomeModel: NSObject
{
var z:String = "" // INITIALIZING z
var delegate:HomeModelDelegate?
func chkpwd()
{
print(z) // CALLING z
//Hit the webservice url
let serviceUrl = "http://www.xyz.in/webservice.php?loginid=(loginid.text)"
//download the json data
let url = URL(string: serviceUrl)
if let url = url {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url, completionHandler:
{ (data, response, error) in
if error == nil {
//succeeded
self.parseJson(data!)
} else {
//failed
}
})
task.resume()
}
}
func parseJson(_ data:Data){
var locArray = [Location]()
do{
let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as! [Any]
for jsonResult in jsonArray{
let jsonDict = jsonResult as! [String:String]
let loc = Location(pwd: jsonDict["loginid"]!, loginid: jsonDict["pwd"]!)
locArray.append(loc)
//pass the location back to the delegate
delegate?.itemsDownloaded(locations: locArray)
}
} catch {
print("An error occured")
}
}
}

Works on one machine but unexpectedly found nil while unwrapping an Optional value on another

My friend and I are working on an app using git. We've encountered a strange problem, when the code runs on my computer but doesn't on hers. Here's the code:
import UIKit
class SelectionViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//adding table
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
// HTTP POST
let myURL = NSURL(string: "http://.../drinks.php")
let request = NSMutableURLRequest(URL:myURL!)
request.HTTPMethod = "POST"
let postString = ""
print(postString)
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {
(data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
dispatch_async(dispatch_get_main_queue())
{
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if let parseJSON = json {
// Store the variables locally
NSUserDefaults.standardUserDefaults().setObject(parseJSON["Selection"], forKey: "items")
NSUserDefaults.standardUserDefaults().setObject(parseJSON["Details"], forKey: "details")
//NSUserDefaults.standardUserDefaults().synchronize()
}
} catch
{
print(error)
}
}
}).resume()
}
// Grab the values from the local storage and declare them locally
var details = (NSUserDefaults.standardUserDefaults().stringArrayForKey("details"))!
var items = (NSUserDefaults.standardUserDefaults().stringArrayForKey("items"))!
It breaks on the last two lines saying: fatal error: unexpectedly found nil while unwrapping an Optional value:
var details = (NSUserDefaults.standardUserDefaults().stringArrayForKey("details"))!
var items = (NSUserDefaults.standardUserDefaults().stringArrayForKey("items"))!
Any help will be highly appreciated!

Swift and SwiftyJSON - dump() not work

try to use dump method on variable filled with JSON. But it doesnt work and i dont understand why
import UIKit
class ViewController: UIViewController {
var hoge: JSON?
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "https://api.whitehouse.gov/v1/petitions.json")
var request = NSURLRequest(URL: url!)
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
if data != nil {
hoge = JSON(data: data!)
let count = hoge!["results"][0]["body"].stringValue
println(count)
}
}
func res() {
dump(self.hoge)
}
}
can you please help me show what am i doing wrong ?

How to get data to return from NSURLSessionDataTask in Swift

I have this same question as was asked and answered here: How to get data to return from NSURLSessionDataTask
The difference: How can I do this in Swift? I do not know Objective C at all so trying to interpret that answer is proving a bit futile for me..
So given the code below I have a FirstViewController which will call my HomeModel class to go and get the data using a NSURLSession call. Once the call is complete I want return the data to the FirstViewController so that I may go and set it in the view.
FirstViewController class looks like:
import UIKit
class FirstViewController: UIViewController
{
let homeModel = HomeModel()
override func viewDidLoad()
{
super.viewDidLoad()
// Go load the home page content
SetHomeContent()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
/*Call to go get home page content*/
func SetHomeContent()
{
homeModel.GetHomeData();
//TODO find a way to get result here... and set it to the textView
}
}
HomeModel class looks like:
import Foundation
class HomeModel
{
private let siteContent:String = "http://www.imoc.co.nz/MobileApp/HomeContent"
func GetHomeData()
{
var url : NSURL! = NSURL(string:siteContent)
var request: NSURLRequest = NSURLRequest(URL:url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: error) as? NSDictionary!
// At this stage I want the jsonResult to be returned to the FirstViewController
});
// do whatever you need with the task
task.resume()
}
I guess I want either a way to pass in a completion handler from the original all or something similar to C# 5 using async tasks to await the result..
Any help appreciated..
With the help and suggestion taken from Abizern I finally managed how to write up this block or closure if you want.
So what worked for me in the end:
The GetHomeData function I changed as follows:
private let siteContent:String = "http://www.imoc.co.nz/MobileApp/HomeContent"
// I changed the signiture from my original question
func GetHomeData(completionHandler: ((NSDictionary!) -> Void)?)
{
var url : NSURL! = NSURL(string:siteContent)
var request: NSURLRequest = NSURLRequest(URL:url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: error) as? NSDictionary!
// then on complete I call the completionHandler...
completionHandler?(jsonResult?);
});
task.resume()
}
Then I call the function like this:
/*Call to go get home page content*/
func SetHomeContent()
{
homeModel.GetHomeData(self.resultHandler)
}
func resultHandler(jsonResult:NSDictionary!)
{
let siteContent = jsonResult.objectForKey("SiteContent") as NSDictionary
let paraOne = siteContent.objectForKey("HomePageParagraphOne") as String
}
Change your GetHomeData() method so that it takes a block. When you call the method pass it the block that does what you want to with the data. In the completion block of the data task, call this passed in block.
You can use this framework for Swift coroutines - https://github.com/belozierov/SwiftCoroutine
DispatchQueue.main.startCoroutine {
let dataFuture = URLSession.shared.dataTaskFuture(for: url)
let data = try dataFuture.await().data
. . . parse data ...
}