Swift Dispatch Groups with Network calls and Completion - ios

I have a a function where I need to get the difference of 2 arrays and use a completion to return the difference in dictionary form. It requires a network call to create an object from the TVDB api. I tried to implement dispatchGroups with .enter() and .leave() and everything seems to work in the right order (checking with breakpoints) until the last iteration it crashes on the line with "groupDispatch.leave()" with no error message in the console.
Here is the function in question:
func showsToWatch(idArray: [Int], completion:#escaping(_ dict: [Int:[Int]])->Void){
var toWatch:[Int:[Int]] = [:]
let groupDispatch = DispatchGroup()
for id in idArray {
groupDispatch.enter()
guard let watchedId = SeriesController.sharedController.watchedDict[id] else {return}
NetworkController.getEpisodes(id) { (episodes, error) in
if let episodes = episodes {
let episodesId = episodes.map({$0.id})
let difference = episodesId.filter { !watchedId.contains($0) }
toWatch[id] = difference
}
groupDispatch.leave()
}
}
groupDispatch.notify(queue: DispatchQueue.main, execute: { () -> Void in
completion(toWatch)
})
}
This is the NetworkController.getEpisodes function:
static func getEpisodes(_ id: Int, completion:#escaping (_ episode: [Episode]?, _ error: NSError?)->Void) {
NetworkController.getPageCount(id) { (pageCount) in
var allEpisodes = [Episode]()
for i in 1...pageCount {
let idString = String(id)
let searchUrl = baseUrl + "series/\(idString)/episodes?page=\(i)"
let searchParam = searchUrl
let myUrl = URL(string: searchParam)
var request = URLRequest(url:myUrl!)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Accept")
let headerString = "Bearer " + myToken
request.addValue(headerString, forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in
if error != nil {
print("error=\(error)")
completion(nil, error as NSError?)
return
}
do {
if let convertedJsonIntoDict = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
if let dataDict = convertedJsonIntoDict as? [String:AnyObject] {
if let dataArray = dataDict["data"] as? [[String:AnyObject]]{
for episodeDict in dataArray {
let episode = Episode(dict: episodeDict)
//print("S\(episode.airedSeason)E\(episode.airedEpisodeNumber)")
if episode.absoluteNumber < 0 {
if episode.airedSeason > 0 && episode.airedEpisodeNumber > 0 {
allEpisodes.append(episode)
}
} else {
allEpisodes.append(episode)
}
}
}
}
}
completion(allEpisodes, nil)
} catch let error as NSError {
print(error.localizedDescription)
completion(nil, error as NSError?)
}
}); task.resume()
}
}
}
I tried putting the groupDispatch.leave() in different places within the function/for loop but then it doesn't complete in the correct order (edit: it hits the completion before it sets the variable "difference" array to the correct key in "toWatch" dictionary variable). I am a bit confused as the how the .leave() works it seems.
Thanks!

Related

how make REST API Call with Model class in swift 3 ios

i want to make REST API call in swift 3.0 with model classes of API code . Can any one help me to solved my issue?
let USER_LIST_FIRMWISE_URL = "\(BASE_URL2)user_list_firm_wise.php"
func userListFirmwiseRequest(firmid:String) -> URLRequest {
let Url = URL(string: (utility?.USER_LIST_FIRMWISE_URL)!)
var request = URLRequest(url: Url!)
request.httpMethod = "POST"
request.cachePolicy = .reloadIgnoringCacheData
let paramString = "firm_id=\(firmid)"
request.httpBody = paramString.data(using: String.Encoding.utf8)
return request
}
func getuserList() -> Void {
var request = mainApp.reqRes?.userListFirmwiseRequest(firmid: firmID)
request?.httpMethod = "POST"
print("request")
EZLoadingActivity.show("", disableUI: true)
let task = URLSession.shared.dataTask(with: request!) { (data: Data?, response: URLResponse?, error: Error?) in
DispatchQueue.main.async
{
do {
guard let data = data, error == nil else {
print("Error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200{
print("Status code should be 200, but is \(httpStatus.statusCode)")
print("Response String:\(String(describing: response))")
}
let jsonString = try? JSONSerialization.jsonObject(with: data, options: [])
guard let JsonObject = try? jsonString as AnyObject else{
return
}
guard let Success = try? JsonObject["success"] as! Int else{
return
}
print("Succee Resul :\(Success)")
if Success > 0{
guard let Message = try? JsonObject["message"] as Any else{
return
}
guard let JsonObjectForUser = try? Message as? AnyObject else {
return
}
}
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary ?? nil
if let parseJSON = json {
let dataDic = parseJSON.value(forKey: "message") as! NSMutableArray
self.arrayUserNameList = dataDic.value(forKey: "user_name") as! [String]
self.arrayUserData = dataDic
print(self.arrayUserNameList)
self.picker.reloadAllComponents()
EZLoadingActivity.hide()
}
} catch{
print(error)
EZLoadingActivity.hide()
}
}
}
task.resume()
}
i have used general code of NSurlsession for API call but it's too much code i have to write every time in every call. so i want common class for API CAll. but how to make common class for API call in swift 3.0
Try something like that
import Foundation
struct modelApi {
var arrayUserData: NSMutableArray = []
var arrayUserNameList: [String] = []
init(data:Data)
{
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? NSDictionary ?? nil
if let parseJSON = json
{
let dataDic = parseJSON.value(forKey: "message") as! NSMutableArray
self.arrayUserNameList = dataDic.value(forKey: "user_name") as! [String]
self.arrayUserData = dataDic
}
}
catch
{
print("Error")
}
}
}
import Foundation
class HttpRequest{
static let TIME_OUT_FOR_RESOURCE = 60.0
static let TIME_OUT_FOR_REQUEST = 30
static func sendHttpGetRequest(endPoint:String,responseMsg:#escaping (_ responseString:String?,_ error:String?)->Void) {
// let JSON_CONTENT_TYPE = "application/json"
// let HTTP_OK = 200
//Content Types
//1 ""Content-Type" = "text/html; charset=UTF-8";"
//2 "Content-Type" = "application/json";
let url = URL.init(string: endPoint)
let session = URLSession.shared
session.configuration.timeoutIntervalForRequest = TimeInterval(TIME_OUT_FOR_REQUEST)
session.configuration.timeoutIntervalForResource = TimeInterval(TIME_OUT_FOR_RESOURCE)
let task = session.dataTask(with: url!) {
data,
response ,
error in
guard error == nil
else{
responseMsg(nil,error!.localizedDescription)
return }
let responseString = String.init(data: data!, encoding: String.Encoding.utf8)!
responseMsg(responseString,nil)
}
task.resume()
}
static func setHttpPostRequest(endPoint:String,param:[String:Any],responseMsg:#escaping (_ responseJson:[String:Any]?,_ error:String?)->Void){
let url = URL.init(string:endPoint)
let session = URLSession.shared
session.configuration.timeoutIntervalForRequest = TimeInterval(TIME_OUT_FOR_REQUEST)
session.configuration.timeoutIntervalForResource = TimeInterval(TIME_OUT_FOR_RESOURCE)
var request = URLRequest.init(url: url!)
request.httpMethod = "POST"
do{
request.httpBody = try JSONSerialization.data(withJSONObject: param, options: .prettyPrinted)
}catch let error{
print(error)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in
guard error == nil else {
responseMsg(nil,error?.localizedDescription)
return
}
guard let data = data else {
responseMsg(nil,"Something went wrong")
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
responseMsg(json,nil)
// print(json)
// handle json...
}
} catch let error {
responseMsg(nil,error.localizedDescription)
// print(error.localizedDescription)
}
})
task.resume()
}}
BASEWEBSERVICE_ClASS:
// where RTCommonResponse is common response Model class. generated by ahmad ali json exporter tool.
import UIKit
import KRProgressHUD
import Foundation
import SystemConfiguration
protocol BaseWebserviceDelegate {
func sucessful(data : RTCommonResponse)
func failedWithMessage(message : String)
}
class BaseWebservice: NSObject
{
var webData : NSMutableData!
var statusCode : Bool!
var appDelegate : AppDelegate!
var baseDelegate : BaseWebserviceDelegate!
let opQueue = OperationQueue()
func initWithDelegate(aDelegate : BaseWebserviceDelegate) {
baseDelegate = aDelegate
appDelegate = UIApplication.shared.delegate as! AppDelegate
//return self
}
func callWithBaseRequest(requestData : Dictionary<String, Any>, aURL : String, method : String, showHUD : Bool ) {
let hudShow = showHUD && BaseWebservice.isInternetAvailable()
let url4 = URL(string: aURL as String)!
//let session4 = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: self.opQueue)
//let session4 = URLSession.shared
let session4: URLSession = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 9999
configuration.timeoutIntervalForResource = 9999
return URLSession(configuration: configuration, delegate: nil, delegateQueue: nil)
}()
let request = NSMutableURLRequest(url: url4)
request.httpMethod = method
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
//let paramString = "data=Hello"
//request.httpBody = paramString.data(using: String.Encoding.utf8)
if method == Constants.POST {
let cookieHeader = (requestData.flatMap({ (key, value) -> String in
return "\(key)=\(value)"
}) as Array).joined(separator: "&")
let postData : Data = cookieHeader.data(using: .utf8)!
request.httpBody = postData
AppDelegate.printLog(log: "Request started for url : " + aURL + " Peram : " + cookieHeader)
}
//request.addValue("multipart/form-data", forHTTPHeaderField: "Content-Type")
let task = session4.dataTask(with: request as URLRequest) { (data, response, error) in
guard let _: Data = data, let _: URLResponse = response, error == nil else {
print("*****error " + (error?.localizedDescription)!)
DispatchQueue.main.async {
KRProgressHUD.dismiss()
self.baseDelegate.failedWithMessage(message: (error?.localizedDescription)!)
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
return
}
let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
// print("*****This is the data 4: \(String(describing: dataString))") //JSONSerialization
let dictionary: Dictionary? = self.convertToDictionary(text: dataString! as String)
//let content = Content.init(fromDictionary: dictionary!)
AppDelegate.printLog(log:"Responce recived for url : " + aURL)
if dictionary == nil {
DispatchQueue.main.async {
KRProgressHUD.dismiss()
self.baseDelegate.failedWithMessage(message: "Something went wrong, try after some time")
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
return
}
//self.baseDelegate.sucessful(data: commonResponse)
DispatchQueue.main.async {
let commonResponse : RTCommonResponse = RTCommonResponse.init(fromDictionary: dictionary!)
if commonResponse.status == "ok" {
self.baseDelegate.sucessful(data: commonResponse)
KRProgressHUD.dismiss()
}else{
let error : RTError = RTError.init(fromDictionary: commonResponse.data!)
KRProgressHUD.dismiss()
self.baseDelegate.failedWithMessage(message: error.error)
}
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
//let task = session4.dataTask(with: request as URLRequest)
if hudShow {
DispatchQueue.main.async {
KRProgressHUD.show()
}
}
DispatchQueue.main.async {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
// session4
task.resume()
}
func convertToDictionary(text: String) -> [String: Any]? {
if let data = text.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
static func isInternetAvailable() -> Bool
{
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
}
}
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
return false
}
let isReachable = flags.contains(.reachable)
let needsConnection = flags.contains(.connectionRequired)
return (isReachable && !needsConnection)
}
}
ForgotpasswordWS_Class:
// where RTForgotPasswordResponse is common response Model class. generated by ahamad ali json exporter tool.
import UIKit
protocol ForgotPasswordWebserviceDelegate {
func forgotPasswordSucessful(data : RTForgotPasswordResponse)
func forgotPasswordFailedWithMessage(message : String)
}
class ForgotPasswordWebservice: BaseWebservice {
var delegate : ForgotPasswordWebserviceDelegate!
init(aDelegate : ForgotPasswordWebserviceDelegate) {
super.init()
super.initWithDelegate(aDelegate: self as BaseWebserviceDelegate)
delegate = aDelegate
}
func initWithDelegate(aDelegate : ForgotPasswordWebserviceDelegate) {
super.initWithDelegate(aDelegate: self as BaseWebserviceDelegate)
delegate = aDelegate
//return self
}
func call(request : RTForgotPasswordRequest) {
let url = Constants.BASE_URL + "user/retrieve_password/"
self.callWithBaseRequest(requestData: request.toDictionary() , aURL: url, method: Constants.POST, showHUD: true)
}
}
extension ForgotPasswordWebservice : BaseWebserviceDelegate{
func sucessful(data : RTCommonResponse){
let content = RTForgotPasswordResponse.init(fromDictionary: data.data! )
//data.content = content
self.delegate.forgotPasswordSucessful(data: content)
}
func failedWithMessage(message : String){
self.delegate.forgotPasswordFailedWithMessage(message: message)
}
}
YourVIEWCONTROLLER_Class:
// just add extension to your view controller
extension yourViewController : ForgotPasswordWebserviceDelegate {
func forgotPasswordFailedWithMessage(message: String) {
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline:when){
self.showSnackBar(message: message)
}
}
func forgotPasswordSucessful(data: RTForgotPasswordResponse) {
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline:when) {
self.showSnackBar(message: data.msg)
//self.displayAlertMessage(messageToDisplay: "Reset Password Link Send")
}
}
}
// when you call API you have to write JUST line of CODE That's IT!!!
#IBAction func forgotbtntapped(_ sender: Any) {
let forgotws : ForgotPasswordWebservice = ForgotPasswordWebservice.init(aDelegate: self)
let forgotrequest : RTForgotPasswordRequest = RTForgotPasswordRequest();
forgotrequest.userLogin = forgotEmailTextField.text!
forgotws.call(request: forgotrequest)
}
Another simple way to call web API
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
cell.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: .greatestFiniteMagnitude)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : CCell = self.tblV.dequeueReusableCell(withIdentifier: "cell") as! CCell
cell.lblName?.text = "ABCD"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
func getClassList(completion: ((NSArray?, NSError?) -> Void)?) {
let myUrl = URL(string: "http://papili.us/studycentral/api/getClassList.php");
var request = URLRequest(url:myUrl!)
request.httpMethod = "POST"// Compose a query string
let postString = "";
request.httpBody = postString.data(using: String.Encoding.utf8);
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
if error != nil {
print("error=\(String(describing: error))")
completion?(nil, error as NSError?)
return
}
print("response = \(String(describing: response))")
//Convert response sent from a server side script to a NSDictionary object:
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if json != nil {
let newdata : NSDictionary = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
let datalist : KRootClass = KRootClass.init(fromDictionary: newdata as! [String : Any])
print(datalist.classID)
print(datalist.className)
print(datalist.teacherTitle)
print(datalist.teacherLastName)
print(datalist.teacherFirstName)
}
} catch {
print(error)
completion?(nil, error as NSError)
}
}
task.resume()
}

URLSession Cancellation in swift while auto search

My moto is Auto search, I have been trying with URLSession, When i am trying to search slowly the requests are handled as expected(when there is no text the response is empty i mean the placesarray) but when i am trying to clear the text or hit any searchtext speedily then the previous request response are being appended in the placesarray. I tried with cancelling the previous request yet i am not getting the result(i.e previous response not be appended)
func autoSearch(text:String){
let urlRequest = URLRequest(url: self.getQueryFormedBingURL()!)
let session = URLSession.shared
session.getTasksWithCompletionHandler
{
(dataTasks, uploadTasks, downloadTasks) -> Void in
// self.cancelTasksByUrl(tasks: dataTasks as [URLSessionTask])
self.cancelTasksByUrl(tasks: uploadTasks as [URLSessionTask])
self.cancelTasksByUrl(tasks: downloadTasks as [URLSessionTask])
}
let task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) -> Void in
print("response \(response)")
if let data = data {
let json = try? JSONSerialization.jsonObject(with: data, options: [])
if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
if let jsonDic = json as? NSDictionary {
let status = jsonDic.returnsObjectOrNone(forKey: "statusCode") as! Int
if status == 200 {
if let resourceSetsArr = jsonDic.returnsObjectOrNone(forKey: "resourceSets") as? NSArray {
if let placesDict = resourceSetsArr.object(at: 0) as? NSDictionary {
if let resourceArr = placesDict.object(forKey: "resources") as? NSArray, resourceArr.count > 0 {
if let _ = self.placesArray {
self.placesArray!.removeAll()
}
for loopCounter in 0...resourceArr.count - 1 {
let modalClass:BingAutoCompletePlace = BingAutoCompletePlace(responseDict: resourceArr[loopCounter] as! NSDictionary)
self.placesArray?.append(modalClass)
}
completion(self.placesArray!)
}
else { //URL Success, where there no places with the given search string
completion([])
}
}
}
}
}
}
else if let response = response as? HTTPURLResponse , 400...499 ~= response.statusCode {// When url fails
if let _ = error {
print("error=\(error!.localizedDescription)")
}
completion([])
}
else {
if let _ = error {
print("error=\(error!.localizedDescription)")
}
completion([])
}
}
})
task.resume()
}
//Request cancellation
private func cancelTasksByUrl(tasks: [URLSessionTask]) {
for task in tasks
{
task.cancel()
}
}
Unfortunately, the framework does not guarantee any order in which tasks finish -- because this depends on the running time. It could also be that you're in a completion handler of a currently cancelled task.
To circumvent this, you could do the following:
Create a private instance variable to store the most-recent task
Cancel everything else as before
In the completion handler
check if the task is still the most recent task (like if (task !== self.currentTask) {return})
create a local Array to store the data
Update the view controllers array in the main thread (DispatchQueue.main.async(...))
I cleaned up you code a litte (using guard statments to minimize the nesting). Maybe you should also
Empty the array in all the error / empty cases (instead of simple return from the guard statement)
hand-in the task to the completion call and check there again if the task is still the currentTask. This would also be a good way to reset currentTask to nil.
Just adopt it to your needs :-)
var currentTask:URLSessionDataTask?
func autoSearch(text:String){
let completion:(_ x:[AnyObject])->() = {_ in }
let urlRequest = URLRequest(url: self.getQueryFormedBingURL()!)
let session = URLSession.shared
session.getTasksWithCompletionHandler
{
(dataTasks, uploadTasks, downloadTasks) -> Void in
// self.cancelTasksByUrl(tasks: dataTasks as [URLSessionTask])
self.cancelTasksByUrl(tasks: uploadTasks as [URLSessionTask])
self.cancelTasksByUrl(tasks: downloadTasks as [URLSessionTask])
}
var task:URLSessionDataTask!
task = session.dataTask(with: urlRequest, completionHandler: { (data, response, error) -> Void in
print("response \(response)")
if (task !== self.currentTask) {
print("Ignore this task")
return
}
if let error = error {
print("response error \(error)")
}
guard let data = data else { return }
let json = try? JSONSerialization.jsonObject(with: data, options: [])
var newPlacesArray = [AnyObject]() // Empty array of whichever type you want
if let response = response as? HTTPURLResponse , 200...299 ~= response.statusCode {
guard let jsonDic = json as? NSDictionary else { return }
let status = jsonDic.returnsObjectOrNone(forKey: "statusCode") as! Int
if status == 200 {
guard let resourceSetsArr = jsonDic.returnsObjectOrNone(forKey: "resourceSets") as? NSArray else { return }
guard let placesDict = resourceSetsArr.object(at: 0) as? NSDictionary else { return }
guard let resourceArr = placesDict.object(forKey: "resources") as? NSArray, resourceArr.count > 0 else {
//URL Success, where there no places with the given search string
DispatchQueue.main.async {completion(newPlacesArray)}
return
}
for loopCounter in 0...resourceArr.count - 1 {
let modalClass:BingAutoCompletePlace = BingAutoCompletePlace(responseDict: resourceArr[loopCounter] as! NSDictionary)
newPlacesArray.append(modalClass)
}
DispatchQueue.main.async {completion(newPlacesArray)}
}
}
else if let response = response as? HTTPURLResponse , 400...499 ~= response.statusCode {// When url fails
if let _ = error {
print("error=\(error!.localizedDescription)")
}
DispatchQueue.main.async {completion(newPlacesArray)}
}
else {
if let _ = error {
print("error=\(error!.localizedDescription)")
}
DispatchQueue.main.async {completion(newPlacesArray)}
}
})
self.currentTask = task
task.resume()
}

NSURL Request is not working

I have a request, after it I need a full Dictionary. But when I checked my request with breakpoints, I saw that it jump over my request... What is wrong in it?
func downloadPackages() {
let url = "\(URL_BASE)package/list?id=666"
let dataURL = NSURL(string: url)
let dataRequest = NSURLRequest(URL: dataURL!)
let dataSession = NSURLSession.sharedSession()
print("QQ")
let dataTask = dataSession.dataTaskWithRequest(dataRequest) { (data, response, error) -> Void in
print("QQ2")
if error != nil {
print(error.debugDescription)
} else {
do {
let packageDict = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as? Dictionary<String, AnyObject>
if let results = packageDict!["data"] as? [Dictionary<String, AnyObject>] {
for obj in results {
let package = Package(packageDict: obj)
print(self.monsters.count)
self.monsters.append(package)
}
}
//Main UI thread
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
catch {
}
}
}
dataTask.resume()
}
It doesn't print ("QQ2"), but it prints ("QQ").
I think that you didn't add HTTP Request methods and values. So try like this :-
func downloadPackages() {
let url = "\(URL_BASE)package/list?id=666"
let dataURL = NSURL(string: url)
let dataRequest: NSMutableURLRequest = NSMutableURLRequest(URL: dataURL!)
dataRequest.HTTPMethod = "POST"
dataRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
dataRequest.setValue("*/*", forHTTPHeaderField: "Accept")
let dataSession = NSURLSession.sharedSession()
print("QQ")
let dataTask = dataSession.dataTaskWithRequest(dataRequest) { (data, response, error) -> Void in
print("QQ2")
if error != nil {
print(error.debugDescription)
} else {
do {
let packageDict = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as? Dictionary<String, AnyObject>
if let results = packageDict!["data"] as? [Dictionary<String, AnyObject>] {
for obj in results {
let package = Package(packageDict: obj)
print(self.monsters.count)
self.monsters.append(package)
}
}
//Main UI thread
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
catch {
}
}
}
dataTask.resume()
}
i think you made a syntax mistake:-
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
and yes wait for a sec for uitableview to be populated.
Following would be better way:-
dispatch_async(dispatch_get_main_queue(), {
for obj in results {
let package = Package(packageDict: obj)
print(self.monsters.count)
self.monsters.append(package)
}
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
})
rest seems to be fine.

Can't get value from Google-Books JSON API

I'm using a bar code scanner to get data on a scanned book using the google books api. I successfully call the API and get a JSON object back.
I'm trying to get the book title which follows the path items.volumeInfo.title.
When I call valueForPath on the JSON object returned by the API and attempt to print it (the title), I end up printing:
Optional((
"A Dance with Dragons"
))
I can't seem to figure out how to actually get the string out of the printed optional. I tried as! String and jsonResult.valueForKeyPath("items.volumeInfo.title")!, but the first simply complained to me and the second only removed the optional and outside set of parentheses.
func getBookInfo(isbn: String) {
var url: String = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn;
var request: NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
if (jsonResult != nil) {
println(jsonResult.valueForKeyPath("items.volumeInfo.title"))
//self.json.setValue(jsonResult.valueForKeyPath("items.volumeInfo.title")!, forKey: "title")
} else {
GlobalConstants.AlertMessage.displayAlertMessage("Error fetching data from barcode, please try again.", view: self)
}
})
}
The response you get from the API is an array of titles.
I suggest using if let to unwrap the Optional value you get from KVC, and typecasting the result as a Swift array of Strings.
Swift 1
func getBookInfo(isbn: String) {
var url: String = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn
var request: NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
if let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: error) as? NSDictionary {
if let arrayOfTitles = jsonResult.valueForKeyPath("items.volumeInfo.title") as? [String] {
let titles = ", ".join(arrayOfTitles)
println(titles)
} else {
// error: no title found
}
} else {
GlobalConstants.AlertMessage.displayAlertMessage("Error fetching data from barcode, please try again.", view: self)
}
})
}
getBookInfo("0553283685") // prints "Hyperion"
Swift 2
For this version we're using NSURLSession because NSURLConnection is now deprecated.
func getBookInfo(isbn: String) {
let urlString = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbn
if let url = NSURL(string: urlString) {
NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: {data, _, error -> Void in
if let error = error {
print(error.localizedDescription)
} else {
if let data = data,
jsonResult = try? NSJSONSerialization.JSONObjectWithData(data, options: []),
arrayOfTitles = jsonResult.valueForKeyPath("items.volumeInfo.title") as? [String] {
let titles = arrayOfTitles.joinWithSeparator(", ")
print(titles)
} else {
GlobalConstants.AlertMessage.displayAlertMessage("Error fetching data from barcode, please try again.", view: self)
}
}
}).resume()
}
}
getBookInfo("0553283685") // prints "Hyperion"
Swift 3
Same as Swift 2 with some syntax changes. I've also added the "authors" example, and I'm now using guard. Just for the sake of showing something different from the previous example.
func getBookInfo(isbn: String) {
guard let url = URL(string: "https://www.googleapis.com/books/v1/volumes?q=isbn:\(isbn)") else {
print("the url is not valid")
return
}
URLSession.shared().dataTask(with: url, completionHandler: {data, response, error -> Void in
guard error == nil else {
print(response)
print(error!.localizedDescription)
return
}
guard let data = data else {
print("no error but no data")
print(response)
return
}
guard let jsonResult = try? JSONSerialization.jsonObject(with: data, options: []) else {
print("the JSON is not valid")
return
}
if let arrayOfTitles = jsonResult.value(forKeyPath: "items.volumeInfo.title") as? [String] {
print(arrayOfTitles)
}
if let arrayOfAuthors = jsonResult.value(forKeyPath: "items.volumeInfo.authors") as? [[String]] {
print(arrayOfAuthors)
}
}).resume()
}
getBookInfo(isbn: "0553283685")

Make REST API call in Swift

I'm trying to use Swift to make a GET call to a REST API, and have tried to follow numerous tutorials, but can't figure it out. Either because I cannot figure out how to translate all the Obj-C to Swift, or because half of the methods n' such are deprecated. Does anyone know how to make the call, and parse returned JSON data?
Swift 5 & 4
let params = ["username":"john", "password":"123456"] as Dictionary<String, String>
var request = URLRequest(url: URL(string: "http://localhost:8080/api/1/login")!)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: params, options: [])
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let session = URLSession.shared
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
print(response!)
do {
let json = try JSONSerialization.jsonObject(with: data!) as! Dictionary<String, AnyObject>
print(json)
} catch {
print("error")
}
})
task.resume()
You can do like this :
var url : String = "http://google.com?test=toto&test2=titi"
var request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: url)
request.HTTPMethod = "GET"
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary
if (jsonResult != nil) {
// process jsonResult
} else {
// couldn't load JSON, look at error
}
})
EDIT : For people have problem with this maybe your JSON stream is an
array [] and not an object {} so you have to change jsonResult to
NSArray instead of NSDictionary
I think the NSURLSession api fits better in this situation. Because if you write swift code your project target is at least iOS 7 and iOS 7 supports NSURLSession api. Anyway here is the code
let url = "YOUR_URL"
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)) { data, response, error in
// Handle result
}.resume()
Here is the complete code for REST API requests using NSURLSession in swift
For GET Request
let configuration = NSURLSessionConfiguration .defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration)
let urlString = NSString(format: "your URL here")
print("get wallet balance url string is \(urlString)")
//let url = NSURL(string: urlString as String)
let request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: NSString(format: "%#", urlString) as String)
request.HTTPMethod = "GET"
request.timeoutInterval = 30
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let dataTask = session.dataTaskWithRequest(request) {
(let data: NSData?, let response: NSURLResponse?, let error: NSError?) -> Void in
// 1: Check HTTP Response for successful GET request
guard let httpResponse = response as? NSHTTPURLResponse, receivedData = data
else {
print("error: not a valid http response")
return
}
switch (httpResponse.statusCode)
{
case 200:
let response = NSString (data: receivedData, encoding: NSUTF8StringEncoding)
print("response is \(response)")
do {
let getResponse = try NSJSONSerialization.JSONObjectWithData(receivedData, options: .AllowFragments)
EZLoadingActivity .hide()
// }
} catch {
print("error serializing JSON: \(error)")
}
break
case 400:
break
default:
print("wallet GET request got response \(httpResponse.statusCode)")
}
}
dataTask.resume()
For POST request ...
let configuration = NSURLSessionConfiguration .defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration)
let params = ["username":bindings .objectForKey("username"), "provider":"walkingcoin", "securityQuestion":securityQuestionField.text!, "securityAnswer":securityAnswerField.text!] as Dictionary<String, AnyObject>
let urlString = NSString(format: “your URL”);
print("url string is \(urlString)")
let request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: NSString(format: "%#", urlString)as String)
request.HTTPMethod = "POST"
request.timeoutInterval = 30
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(params, options: [])
let dataTask = session.dataTaskWithRequest(request)
{
(let data: NSData?, let response: NSURLResponse?, let error: NSError?) -> Void in
// 1: Check HTTP Response for successful GET request
guard let httpResponse = response as? NSHTTPURLResponse, receivedData = data
else {
print("error: not a valid http response")
return
}
switch (httpResponse.statusCode)
{
case 200:
let response = NSString (data: receivedData, encoding: NSUTF8StringEncoding)
if response == "SUCCESS"
{
}
default:
print("save profile POST request got response \(httpResponse.statusCode)")
}
}
dataTask.resume()
I hope it works.
edited for swift 2
let url = NSURL(string: "http://www.test.com")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
print(NSString(data: data!, encoding: NSUTF8StringEncoding))
}
task.resume()
Swift 4 - GET request
var request = URLRequest(url: URL(string: "http://example.com/api/v1/example")!)
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request, completionHandler: { data, response, error -> Void in
do {
let jsonDecoder = JSONDecoder()
let responseModel = try jsonDecoder.decode(CustomDtoClass.self, from: data!)
print(responseModel)
} catch {
print("JSON Serialization error")
}
}).resume()
Don't forget to configure App Transport Security Settings to add your domain to the exceptions and allow insecure http requests if you're hitting endpoints without using HTTPS.
You can use a tool like http://www.json4swift.com/ to autogenerate your Codeable Mappings from your JSON responses.
In swift 3.3 and 4. I crated APIManager class with two public methods. Just pass required parameter, api name and request type. You will get response then pass it to the closure.
import UIKit
struct RequestType {
static let POST = "POST"
static let GET = "GET"
}
enum HtttpType: String {
case POST = "POST"
case GET = "GET"
}
class APIManager: NSObject {
static let sharedInstance: APIManager = {
let instance = APIManager()
return instance
}()
private init() {}
// First Method
public func requestApiWithDictParam(dictParam: Dictionary<String,Any>, apiName: String,requestType: String, isAddCookie: Bool, completionHendler:#escaping (_ response:Dictionary<String,AnyObject>?, _ error: NSError?, _ success: Bool)-> Void) {
var apiUrl = “” // Your api url
apiUrl = apiUrl.appendingFormat("%#", apiName)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let url = URL(string: apiUrl)!
let HTTPHeaderField_ContentType = "Content-Type"
let ContentType_ApplicationJson = "application/json"
var request = URLRequest.init(url: url)
request.timeoutInterval = 60.0
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
request.addValue(ContentType_ApplicationJson, forHTTPHeaderField: HTTPHeaderField_ContentType)
request.httpMethod = requestType
print(apiUrl)
print(dictParam)
let dataTask = session.dataTask(with: request) { (data, response, error) in
if error != nil {
completionHendler(nil, error as NSError?, false)
} do {
let resultJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
print("Request API = ", apiUrl)
print("API Response = ",resultJson ?? "")
completionHendler(resultJson, nil, true)
} catch {
completionHendler(nil, error as NSError?, false)
}
}
dataTask.resume()
}
// Second Method
public func requestApiWithUrlString(param: String, apiName: String,requestType: String, isAddCookie: Bool, completionHendler:#escaping (_ response:Dictionary<String,AnyObject>?, _ error: NSError?, _ success: Bool)-> Void ) {
var apiUrl = "" // Your api url
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
var request: URLRequest?
if requestType == "GET" {
apiUrl = String(format: "%#%#&%#", YourAppBaseUrl,apiName,param)
apiUrl = apiUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
print("URL=",apiUrl)
let url = URL(string: apiUrl)!
request = URLRequest.init(url: url)
request?.httpMethod = "GET"
} else {
apiUrl = String(format: "%#%#", YourAppBaseUrl,apiName)
apiUrl = apiUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
print("URL=",apiUrl)
let bodyParameterData = param.data(using: .utf8)
let url = URL(string: apiUrl)!
request = URLRequest(url: url)
request?.httpBody = bodyParameterData
request?.httpMethod = "POST"
}
request?.timeoutInterval = 60.0
request?.cachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData
request?.httpShouldHandleCookies = true
let dataTask = session.dataTask(with: request!) { (data, response, error) in
if error != nil {
completionHendler(nil, error as NSError?, false)
} do {
if data != nil {
let resultJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
print("Request API = ", apiUrl)
print("API Response = ",resultJson ?? "")
completionHendler(resultJson, nil, true)
} else {
completionHendler(nil, error as NSError?, false)
}
} catch {
completionHendler(nil, error as NSError?, false)
}
}
dataTask.resume()
}
}
// Here is example of calling Post API from any class
let bodyParameters = String(format: "appid=%#&appversion=%#","1","1")
APIManager.sharedInstance.requestApiWithUrlString(param: bodyParameters, apiName: "PASS_API_NAME", requestType: HtttpType.POST.rawValue, isAddCookie: false) { (dictResponse, error, success) in
if success {
if let dictMessage = dictResponse?["message"] as? Dictionary<String, AnyObject> {
// do you work
}
} else {
print("Something went wrong...")
}
}
}
/// Or just use simple function
func dataRequest() {
let urlToRequest = "" // Your API url
let url = URL(string: urlToRequest)!
let session4 = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let paramString = "data=Hello"
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session4.dataTask(with: request as URLRequest) { (data, response, error) in
guard let _: Data = data, let _: URLResponse = response, error == nil else {
print("*****error")
return
}
if let dataString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue) {
print("****Data: \(dataString)") //JSONSerialization
}
}
task.resume()
}
Swift 3.0
let request = NSMutableURLRequest(url: NSURL(string: "http://httpstat.us/200")! as URL)
let session = URLSession.shared
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request as URLRequest, completionHandler: {data, response, error -> Void in
if error != nil {
print("Error: \(String(describing: error))")
} else {
print("Response: \(String(describing: response))")
}
})
task.resume()
Swift 4
Create an app using Alamofire with Api Post method
Install pod file -pod 'Alamofire', '~> 4.0' for Swift 3 with Xcode 9
Create Webservices.swift class, import Alamofire
Design storyBoard ,Login View
insert following Code for the ViewControllerClass
import UIKit
class ViewController: UIViewController {
#IBOutlet var usernameTextField: UITextField!
#IBOutlet var passwordTextField: UITextField!
var usertypeStr :String = "-----------"
var loginDictionary : NSDictionary?
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 loginButtonClicked(_ sender: Any) {
WebServices.userLogin(userName: usernameTextField.text!, password: passwordTextField.text!,userType: usertypeStr) {(result, message, status )in
if status {
let loginDetails = result as? WebServices
self.loginDictionary = loginDetails?.loginData
if self.loginDictionary?["status"] as? String == "error"
{
self.alertMessage(alerttitle: "Login Error", (self.loginDictionary?["message"] as? String)!)
} else if self.loginDictionary?["status"] as? String == "ok" {
self.alertMessage(alerttitle: "", "Success")
}else {
self.alertMessage(alerttitle: "", (self.loginDictionary?["message"] as? String)!)
}
} else {
self.alertMessage(alerttitle: "", "Sorry")
}
}
}
func alertMessage(alerttitle:String,_ message : String){
let alertViewController = UIAlertController(title:alerttitle, message:message, preferredStyle: .alert)
alertViewController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alertViewController, animated: true, completion: nil)
}
}
Insert Following Code For WebserviceClass
import Foundation
import Alamofire
class WebServices: NSObject {
enum WebServiceNames: String {
case baseUrl = "https://---------------"
case UserLogin = "------------"
}
// MARK: - Login Variables
var loginData : NSDictionary?
class func userLogin(userName: String,password : String,userType : String, completion : #escaping (_ response : AnyObject?, _ message: String?, _ success : Bool)-> ()) {
let url = WebServiceNames.baseUrl.rawValue + WebServiceNames.UserLogin.rawValue
let params = ["USER": userName,"PASS":password,"API_Key" : userType]
WebServices.postWebService(urlString: url, params: params as [String : AnyObject]) { (response, message, status) in
print(response ?? "Error")
let result = WebServices()
if let data = response as? NSDictionary {
print(data)
result.loginData = data
completion(result, "Success", true)
}else {
completion("" as AnyObject?, "Failed", false)
}
}
}
//MARK :- Post
class func postWebService(urlString: String, params: [String : AnyObject], completion : #escaping (_ response : AnyObject?, _ message: String?, _ success : Bool)-> Void) {
alamofireFunction(urlString: urlString, method: .post, paramters: params) { (response, message, success) in
if response != nil {
completion(response as AnyObject?, "", true)
}else{
completion(nil, "", false)
}
}
}
class func alamofireFunction(urlString : String, method : Alamofire.HTTPMethod, paramters : [String : AnyObject], completion : #escaping (_ response : AnyObject?, _ message: String?, _ success : Bool)-> Void){
if method == Alamofire.HTTPMethod.post {
Alamofire.request(urlString, method: .post, parameters: paramters, encoding: URLEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
print(urlString)
if response.result.isSuccess{
completion(response.result.value as AnyObject?, "", true)
}else{
completion(nil, "", false)
}
}
}else {
Alamofire.request(urlString).responseJSON { (response) in
if response.result.isSuccess{
completion(response.result.value as AnyObject?, "", true)
}else{
completion(nil, "", false)
}
}
}
}
//Mark:-Cancel
class func cancelAllRequests()
{
Alamofire.SessionManager.default.session.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in
dataTasks.forEach { $0.cancel() }
uploadTasks.forEach { $0.cancel() }
downloadTasks.forEach { $0.cancel() }
}
}
}
swift 4
USE ALAMOFIRE in our App plz install pod file
pod 'Alamofire', '~> 4.0'
We can Use API for Json Data -https://swapi.co/api/people/
Then We can create A networking class for Our project- networkingService.swift
import Foundation
import Alamofire
typealias JSON = [String:Any]
class networkingService{
static let shared = networkingService()
private init() {}
func getPeople(success successblock: #escaping (GetPeopleResponse) -> Void)
{
Alamofire.request("https://swapi.co/api/people/").responseJSON { response in
guard let json = response.result.value as? JSON else {return}
// print(json)
do {
let getPeopleResponse = try GetPeopleResponse(json: json)
successblock(getPeopleResponse)
}catch{}
}
}
func getHomeWorld(homeWorldLink:String,completion: #escaping(String) ->Void){
Alamofire.request(homeWorldLink).responseJSON {(response) in
guard let json = response.result.value as? JSON,
let name = json["name"] as? String
else{return}
completion(name)
}
}
}
Then Create NetworkingError.swift class
import Foundation
enum networkingError : Error{
case badNetworkigStuff
}
Then create Person.swift class
import Foundation
struct Person {
private let homeWorldLink : String
let birthyear : String
let gender : String
let haircolor : String
let eyecolor : String
let height : String
let mass : String
let name : String
let skincolor : String
init?(json : JSON) {
guard let birthyear = json["birth_year"] as? String,
let eyecolor = json["eye_color"] as? String,
let gender = json["gender"] as? String,
let haircolor = json["hair_color"] as? String,
let height = json["height"] as? String,
let homeWorldLink = json["homeworld"] as? String,
let mass = json["mass"] as? String,
let name = json["name"] as? String,
let skincolor = json["skin_color"] as? String
else { return nil }
self.homeWorldLink = homeWorldLink
self.birthyear = birthyear
self.gender = gender
self.haircolor = haircolor
self.eyecolor = eyecolor
self.height = height
self.mass = mass
self.name = name
self.skincolor = skincolor
}
func homeWorld(_ completion: #escaping (String) -> Void) {
networkingService.shared.getHomeWorld(homeWorldLink: homeWorldLink){ (homeWorld) in
completion(homeWorld)
}
}
}
Then create DetailVC.swift
import UIKit
class DetailVC: UIViewController {
var person :Person!
#IBOutlet var name: UILabel!
#IBOutlet var birthyear: UILabel!
#IBOutlet var homeworld: UILabel!
#IBOutlet var eyeColor: UILabel!
#IBOutlet var skinColor: UILabel!
#IBOutlet var gender: UILabel!
#IBOutlet var hairColor: UILabel!
#IBOutlet var mass: UILabel!
#IBOutlet var height: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
print(person)
name.text = person.name
birthyear.text = person.birthyear
eyeColor.text = person.eyecolor
gender.text = person.gender
hairColor.text = person.haircolor
mass.text = person.mass
height.text = person.height
skinColor.text = person.skincolor
person.homeWorld{(homeWorld) in
self.homeworld.text = homeWorld
}
}
}
Then Create GetPeopleResponse.swift class
import Foundation
struct GetPeopleResponse {
let people : [Person]
init(json :JSON) throws {
guard let results = json["results"] as? [JSON] else { throw networkingError.badNetworkigStuff}
let people = results.map{Person(json: $0)}.flatMap{ $0 }
self.people = people
}
}
Then Our View controller class
import UIKit
class ViewController: UIViewController {
#IBOutlet var tableVieww: UITableView!
var people = [Person]()
#IBAction func getAction(_ sender: Any)
{
print("GET")
networkingService.shared.getPeople{ response in
self.people = response.people
self.tableVieww.reloadData()
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
guard segue.identifier == "peopleToDetails",
let detailVC = segue.destination as? DetailVC,
let person = sender as AnyObject as? Person
else {return}
detailVC.person = person
}
}
extension ViewController:UITableViewDataSource{
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return people.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = people[indexPath.row].name
return cell
}
}
extension ViewController:UITableViewDelegate{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "peopleToDetails", sender: people[indexPath.row])
}
}
In our StoryBoard
plz Connect with our View with another one using segue with identifier -peopleToDetails
Use UITableView In our First View
Use UIButton For get the Data
Use 9 Labels in our DetailVc
Very simple 100% working , tested
var url : String = "https://restcountries.eu/rest/v2/all"
URLSession.shared.dataTask(with: NSURL(string: url) as! URL) { data, response, error in
// Handle result
let response = String (data: data!, encoding: String.Encoding.utf8)
print("response is \(response)")
do {
let getResponse = try JSONSerialization.jsonObject(with: data!, options: .allowFragments)
print(getResponse)
let countryArray = getResponse as! NSArray
print(countryArray)
let country1 = countryArray[0] as! [String:Any]
let name = country1["name"] as! String
print(name)
} catch {
print("error serializing JSON: \(error)")
}
}.resume()
}
If you're working in Swift 3, the syntax changes. The example here worked for me and has a good explanation of the steps: https://grokswift.com/simple-rest-with-swift/
This is the code from that tutorial:
let todoEndpoint: String = "https://jsonplaceholder.typicode.com/todos/1"
guard let url = URL(string: todoEndpoint) else {
print("Error: cannot create URL")
return
}
let urlRequest = URLRequest(url: url)
let task = session.dataTask(with: urlRequest) {
(data, response, error) in
// check for any errors
guard error == nil else {
print("error calling GET on /todos/1")
print(error!)
return
}
// make sure we got data
guard let responseData = data else {
print("Error: did not receive data")
return
}
// parse the result as JSON, since that's what the API provides
do {
guard let todo = try JSONSerialization.jsonObject(with: responseData, options: [])
as? [String: Any] else {
print("error trying to convert data to JSON")
return
}
// now we have the todo
// let's just print it to prove we can access it
print("The todo is: " + todo.description)
// the todo object is a dictionary
// so we just access the title using the "title" key
// so check for a title and print it if we have one
guard let todoTitle = todo["title"] as? String else {
print("Could not get todo title from JSON")
return
}
print("The title is: " + todoTitle)
} catch {
print("error trying to convert data to JSON")
return
}
}
task.resume()
Swift 5
API call method
//Send Request with ResultType<Success, Error>
func fetch(requestURL:URL,requestType:String,parameter:[String:AnyObject]?,completion:#escaping (Result<Any>) -> () ){
//Check internet connection as per your convenience
//Check URL whitespace validation as per your convenience
//Show Hud
var urlRequest = URLRequest.init(url: requestURL)
urlRequest.cachePolicy = .reloadIgnoringLocalCacheData
urlRequest.timeoutInterval = 60
urlRequest.httpMethod = String(describing: requestType)
urlRequest.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
urlRequest.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
//Post URL parameters set as URL body
if let params = parameter{
do{
let parameterData = try JSONSerialization.data(withJSONObject:params, options:.prettyPrinted)
urlRequest.httpBody = parameterData
}catch{
//Hide hude and return error
completion(.failure(error))
}
}
//URL Task to get data
URLSession.shared.dataTask(with: requestURL) { (data, response, error) in
//Hide Hud
//fail completion for Error
if let objError = error{
completion(.failure(objError))
}
//Validate for blank data and URL response status code
if let objData = data,let objURLResponse = response as? HTTPURLResponse{
//We have data validate for JSON and convert in JSON
do{
let objResposeJSON = try JSONSerialization.jsonObject(with: objData, options: .mutableContainers)
//Check for valid status code 200 else fail with error
if objURLResponse.statusCode == 200{
completion(.success(objResposeJSON))
}
}catch{
completion(.failure(error))
}
}
}.resume()
}
Use of API call method
func useOfAPIRequest(){
if let baseGETURL = URL(string:"https://postman-echo.com/get?foo1=bar1&foo2=bar2"){
self.fetch(requestURL: baseGETURL, requestType: "GET", parameter: nil) { (result) in
switch result{
case .success(let response) :
print("Hello World \(response)")
case .failure(let error) :
print("Hello World \(error)")
}
}
}
}
Api Call using Model Class
let urlString = "http://--.154.--.78/------/index.php?route=api/coupon/all"
let url = URL(string: urlString)
var request = URLRequest(url: url!)
request.httpMethod = "GET"
URLSession.shared.dataTask(with:request) { (data, response, error) in
if error != nil {
print(error)
} else {
do {
let parsedDictionaryArray = try JSONSerialization.jsonObject(with: data!) as! [String:AnyObject]
print(parsedDictionaryArray)
if let arry = parsedDictionaryArray["data"] as? [[String:AnyObject]] {
for dic in arry {
let name = dic["name"]
let descriptionData = dic["description"]
self.modelReference.append(model(name: name as! String, descriptionStr: descriptionData as! String))
print(name!)
}
}
} catch let error as NSError {
print(error)
}
}
}.resume()
create a variable and connect with model class
var modelReference = [model]()
create a model class New -> swift class
import Foundation
class model : NSObject{
var name : String
var descriptionStr: String
init(name : String, descriptionStr: String)
{
self.name = name
self.descriptionStr = descriptionStr
}
}
then we can connect with our table view objects
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCellID")as! TableViewCell
cell.listName.text = modelReference[indexPath.row].name
let headers = [
"cache-control": "no-cache",
"postman-token": "6f8a-12c6-87a1-ac0f25d6385a"
]
let request = NSMutableURLRequest(url: NSURL(string: "Your url string")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if error == nil && data != nil {
do {
// Convert NSData to Dictionary where keys are of type String, and values are of any type
let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String:AnyObject]
print(json)
//do your stuff
// completionHandler(true)
} catch {
// completionHandler(false)
}
}
else if error != nil
{
//completionHandler(false)
}
}).resume()
}
func getAPICalling(mainUrl:String) {
//create URL
guard let url = URL(string: mainUrl) else {
print("Error: cannot create URL")
return
}
//create request
let urlRequest = URLRequest(url: url)
// create the session
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
// make the request
let task = session.dataTask(with: urlRequest) {
(data, response, error) in
// check for any errors
guard error == nil else {
print("error calling GET")
print(error!.localizedDescription)
return
}
// make sure we got data
guard let responseData = data else {
print("error: did not receive data")
return
}
// convert Data in JSON && parse the result as JSON, since that's what the API provides
do {
guard let object = try JSONSerialization.jsonObject(with: responseData, options: [])
as? [String: Any] else {
print("error trying to convert data to JSON")
return
}
//JSON Response
guard let todoTitle = object["response"] as? NSDictionary else {
print("Could not get todo title from JSON")
return
}
//Get array in response
let responseList = todoTitle.value(forKey: "radioList") as! NSArray
for item in responseList {
let dic = item as! NSDictionary
let str = dic.value(forKey: "radio_des") as! String
self.arrName.append(str)
print(item)
}
DispatchQueue.main.async {
self.tblView.reloadData()
}
} catch {
print("error trying to convert data to JSON")
return
}
}
task.resume()
}
Usage:
getAPICalling(mainUrl:"https://dousic.com/api/radiolist?user_id=16")
class ApiManager: NSObject {
static func callGetDataApi(url: String,completion: #escaping([[String: Any]])-> Void) {
guard let url = URL(string: ApiName.baseUrl+url ) else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"
URLSession.shared.dataTask(with:request) { (data, response, error) in
if error != nil {
print(error ?? "")
} else {
do {
let arry = try JSONSerialization.jsonObject(with: data!) as! [[String:AnyObject]]
print(arry)
DispatchQueue.main.async {
completion(arry)
}
} catch let error as NSError {
print(error)
}
}
}.resume()
}
}

Resources