I've been following an guide in the hope of learning how to use MYSQL with IOS apps.
However the guide is a little bit outdated, and I'm using swift 3 and I been editing the code to fix a few bugs.
I have come down to a final problem, which is after I changed from using URL to NSURL, I can't use the "DataTask" anymore..
I have no idea how to replace this code of line.
import Foundation
protocol HomeModelProtocol: class {
func itemsDownloaded(items: NSArray)
}
class HomeModel: NSObject, NSURLSessionDataDelegate {
//properties
weak var delegate: HomeModelProtocol!
let urlPath = "http://iosquiz.com/service.php" //this will be changed to the path where service.php lives
func downloadItems() {
let url: NSURL = NSURL(string: urlPath)!
let defaultSession = Foundation.NSURLSessionConfiguration
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
do{
jsonResult = try NSJSONSerialization.jsonObject(with: data, options: NSJSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let locations = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let location = LocationModel()
//the following insures none of the JsonElement values are nil through optional binding
if let name = jsonElement["Name"] as? String,
let address = jsonElement["Address"] as? String,
let latitude = jsonElement["Latitude"] as? String,
let longitude = jsonElement["Longitude"] as? String
{
location.name = name
location.address = address
location.latitude = latitude
location.longitude = longitude
}
locations.addObject(location)
}
I have come down to a final problem, which is after I changed from using URL to NSURL, I can't use the "DataTask" anymore..
Why did you switch from URL to NSURL? That's moving in the wrong direction. URL is the Swift bridge for NSURL. It should replace NSURL in all new code.
Switch back to URL. If you must use NSURL, you'll have to add an as URL when you use it in dataTask(with:), since that method expects an URL.
There's a deeper problem here. You're using a configuration as though it were a session. Here's the code I believe you mean:
// vvv Changed NSURLSessionDataDelegate to URLSessionDataDelegate
class HomeModel: NSObject, URLSessionDataDelegate {
weak var delegate: HomeModelProtocol? // <-- Avoid ! for this
let urlPath = "http://iosquiz.com/service.php"
func downloadItems() {
let url = URL(string: urlPath)! // <-- Changed NSURL to URL
let defaultSession = URLSession.shared // <-- Use URLSession, not URLSessionConfiguration
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
}
Related
I was trying to learn the basics of networking with openweather api.
Implemented a very basic struct like this.
protocol WeatherManagerDelegate {
func didUpdateWeather(_ weatherManager : WeatherManager, weather : WeatherModel)
func didFailWithError(error: Error)
}
struct WeatherManager {
var delegate : WeatherManagerDelegate?
var temp : Double = 0.0
let weatherURL = "https://api.openweathermap.org/data/2.5/weather?appid=40ca58efce193db0fc801564afb08283&units=metric"
func fetchWheather(cityName : String){
let urlString = "\(weatherURL)&q=\(cityName)"
performRequest(with: urlString)
}
func performRequest(with urlString: String){
if let url = URL(string: urlString){
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url){ (data, response, error) in
if error != nil{
delegate?.didFailWithError(error: error!)
return
}
if let safedata = data {
if let weather = self.parseJSON(weatherData: safedata){
// let WeatherVC = WeatherViewController()
self.delegate!.didUpdateWeather(self, weather: weather)
}
print("Data is \(safedata)")
}
}
task.resume()
}
}
func parseJSON(weatherData:Data)-> WeatherModel?{
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
let id = decodedData.weather[0].id
let temp = decodedData.main.temp
let name = decodedData.name
let weather = WeatherModel(conditionID: id, cityName: name, temperature: temp)
return weather
} catch{
print("error is \(error)")
delegate?.didFailWithError(error: error)
return nil
}
}
}
But the issue is none of the print statements inside the requests are giving any outputs , nor i am able to update the UI. But the URL is giving the correct JSON Response when tried in browser
I am using the latest XCode on iOS 15 (iPhone 11 Device) with M1 Pro chip mac.
Found some threads which mentions to use "open with rosetta" but none of which worked.
also, not getting any errors on the console
Any solution?
Edit : Called in VC like this:
func textFieldDidEndEditing(_ textField: UITextField) {
if let city = searchTextField.text {
weatherManager.fetchWeather(cityName: city)
}
searchTextField.text = ""
}
Please try using:
let session = URLSession.shared
…instead of creating local session variable within the function scope
And if error != nil then don't return from that block. Simply use if-else for error handling.
I'm very new in programing, I have been learning swift5 for a few months now. I'm trying to make an APP that scan a 1D or 2D barcode, take the string and send it to an API endpoint which will give me back some info, for example, product number and batch number.
For the barcode part I'm using a really nice software from GitHub called BarcodeScanner. It is running without any issue and I'm able to get the string from the barcode it reads.
Once I have the string I'm able to send it to the API endpoint but then it gets stuck there.
If I run the same code in a playground it works without problems, it makes the request and I can see the answer in JSON from the server. If I run the code on the iPhone then it gets stuck. Of course I cannot use the scanning part when in playground, I use it to test the networking part and communication with the API.
Here is my Networking.swift file, it has some print() used for debug:
import Foundation
import UIKit
protocol NetworkManagerDelegate: class {
func didUpdatePharmo(pharmo: PharmoModel)
func didUpdateBarcode(barcode: BarcodeModel)
}
public struct NetworkManager {
var delegate: NetworkManagerDelegate?
let pharmoURL = "https://someurl.com/api"
let pharmoEndpoint = "https://someendpoint.com/api"
func fetchData(productNumber: String) {
let urlString = "\(pharmoURL)&number=\(productNumber)"
performRequestProductInfo(urlString: urlString)
print(urlString)
}
func fetchEndpoint(dataMatrix: String) {
let urlString = "\(pharmoEndpoint)&datamatrix=\(dataMatrix)"
performRequestEndpoint(urlString: urlString)
print(urlString)
}
func performRequestEndpoint(urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = session.dataTask(with: request) { (data, response, error) in
if error != nil {
print(error!)
return
}
if let response = response as? HTTPURLResponse {
print("EndPoint HTTP Status code: \(response.statusCode)")
}
if let safeData = data {
if let barcode = self.parseJSONEndpoint(endPointData: safeData) {
self.delegate?.didUpdateBarcode(barcode: barcode)
}
}
}
task.resume()
}
}
func parseJSONEndpoint(endPointData: Data) -> BarcodeModel? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(BarcodeData.self, from: endPointData)
let productNumber = decodedData.product_number
let batchNumber = decodedData.batchnumber
let barcode = BarcodeModel(productNumber: productNumber, batchNumber: batchNumber)
print(batchNumber)
return barcode
} catch {
print(error)
return nil
}
}
func performRequestProductInfo(urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = session.dataTask(with: request) { (data, response, error) in
if error != nil {
print(error!)
return
}
if let response = response as? HTTPURLResponse {
print("ProductInfo HTTP Status code: \(response.statusCode)")
}
if let safeData = data {
if let pharmo = self.parseJSONProductInfo(pharmoData: safeData) {
self.delegate?.didUpdatePharmo(pharmo: pharmo)
}
}
}
task.resume()
}
}
func parseJSONProductInfo(pharmoData: Data) -> PharmoModel? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(PharmoData.self, from: pharmoData)
let id = decodedData.id
let number = decodedData.number
let name = decodedData.name
let atcCode = decodedData.atc_code
let imagePath = decodedData.image_path
let displayImage = decodedData.display_image
let storageGroupId = decodedData.storage_group_id
let animalGroupId = decodedData.animal_group_id
let udlevbest = decodedData.udlevbest
let packageSizeText = decodedData.package_size_text
let packageSizeNum = decodedData.package_size_num
let unitCode = decodedData.unit_code
let strengthText = decodedData.strength_text
let prodPrice = decodedData.prod_price
let aupPrice = decodedData.aup_price
let aupInstPrice = decodedData.aup_inst_price
let animalGroups = decodedData.animal_groups
let udleveringsbestemmelse = decodedData.udleveringsbestemmelse
let animalGroup = decodedData.animal_group
let storageGroup = decodedData.storage_group
let species = decodedData.species
let indications = decodedData.indications
let substances = decodedData.substances
let manufacturer = decodedData.manufacturer
let pharmo = PharmoModel(id: id, number: number, name: name, atc_code: atcCode, image_path: imagePath, display_image: displayImage, storage_group_id: storageGroupId, animal_group_id: animalGroupId, udlevbest: udlevbest, package_size_text: packageSizeText, package_size_num: packageSizeNum, unit_code: unitCode, strength_text: strengthText, prod_price: prodPrice, aup_price: aupPrice, aup_inst_price: aupInstPrice, animal_groups: animalGroups, udleveringsbestemmelse: udleveringsbestemmelse, animal_group: animalGroup, storage_group: storageGroup, species: species, indications: indications, substances: substances, manufacturer: manufacturer)
print(name)
return pharmo
} catch {
print(error)
return nil
}
}
}
From the ViewController.swift running the barcode scanner I call the function fetchEndpoint(dataMatrix: String)
extension ViewController: BarcodeScannerCodeDelegate {
func scanner(_ controller: BarcodeScannerViewController, didCaptureCode code: String, type: String) {
print("Barcode Data: \(code)")
print("Symbology Type: \(type)")
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
networkManager.fetchEndpoint(dataMatrix: code)
}
}
}
From the console output I can see this 2 print() statements from ViewController.swift:
print("Barcode Data: \(code)")
print("Symbology Type: \(type)")
I can also see this print() statement from Networking.swift:
print(urlString)
But nothing happends after that. Again if I run the same code in a playground it works fine. I have also made requests using Postman, so I can see the JSON file and be sure the urlstring is working.
Anyone have some idea what am I doing wrong?
I was able to find the problem. The string being read from the scanner had an non ASCII character.
At any point XCode said anything about a non ASCII character, I had to copy the string into a playground, then I received this error:
Unprintable ASCII character found in source file
I copied the string into a terminal shell and I was able to see the character.
datamatrix=^]01036611030467831722113010RXT0711GC
I will try to use URLComponents or percent encoding
Im New to Swift and I'm Integrating PayUmoney IOS SDK in swift, Im getting trouble When I'm doing in live its showing hash mismatch (Hash mismatch1) If I'm doing in test its showing invalid merchant key (Invalid key) I struck here from 2 weeks Did so many things and didn't get any solution for this can any one help it would be awesome. Below is my code, Thank you in Advance.
var params : PUMRequestParams = PUMRequestParams.shared()
var utils : Utils = Utils()
params.environment = PUMEnvironment.test;
params.firstname = txtFldName.text;
params.key = "bZf4AOjj";
params.merchantid = "5745303";
params.logo_url = "";
params.productinfo = "Product Info";
params.email = txtFldEmail.text;
params.phone = "";
params.surl = "https://www.payumoney.com/mobileapp/payumoney/success.php";
params.furl = "https://www.payumoney.com/mobileapp/payumoney/failure.php";
if(params.environment == PUMEnvironment.test){
generateHashForProdAndNavigateToSDK()
}
else{
calculateHashFromServer()
}
// assign delegate for payment callback.
params.delegate = self;
}
func generateHashForProdAndNavigateToSDK() -> Void {
let txnid = params.txnid!
let hashSequence : NSString = "\(params.key)|\(txnid)|\(params.amount)|\(params.productinfo)|\(params.firstname)|\(params.email)|||||||||||2uIsGhXWVw" as NSString
let data :NSString = utils.createSHA512(hashSequence as String!) as NSString
params.hashValue = data as String!;
startPaymentFlow();
}
// MARK:HASH CALCULATION
func prepareHashBody()->NSString{
return "SHA-512key=\(params.key!)&amount=\(params.amount!)&txnid=\(params.txnid!)&productinfo=\(params.productinfo!)&email=\(params.email!)&firstname=\(params.firstname!)" as NSString;
}
func calculateHashFromServer(){
let config = URLSessionConfiguration.default // Session Configuration
let session = URLSession(configuration: config) // Load configuration into Session
let url = URL(string: "https://test.payumoney.com/payment/op/v1/calculateHashForTest")!
var request = URLRequest(url: url)
request.httpBody = prepareHashBody().data(using: String.Encoding.utf8.rawValue)
request.httpMethod = "POST"
let task = session.dataTask(with: request, completionHandler: {
(data, response, error) in
if error != nil {
print(error!.localizedDescription)
} else {
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]{
print(json)
let status : NSNumber = json["status"] as! NSNumber
if(status.intValue == 0)
{
self.params.hashValue = json["result"] as! String!
OperationQueue.main.addOperation {
self.startPaymentFlow()
}
}
else{
OperationQueue.main.addOperation {
self.showAlertViewWithTitle(title: "Message", message: json["message"] as! String)
}
}
}
} catch {
print("error in JSONSerialization")
}
}
})
task.resume()
}
Hello Vinny do with webview its working for me. Before I also used this PayUmoney IOS SDK but faced so many problems so based on objective-c I did this so I think its useful to you. create a weak var webview and create class UIwebviewdelegate
class PayumoneyViewController: UIViewController, UIWebViewDelegate, UIAlertViewDelegate {
#IBOutlet weak var Webview: UIWebView!
and for test use below credentials
//test
var merchantKey = "40747T"
var salt = "ur salt"
var PayUBaseUrl = "https://test.payu.in"
For live
//Production
var merchantKey = “xxxxxx”
var salt = “xxxxx”
var PayUBaseUrl = "https://secure.payu.in"
let productInfo = “Myapp” //It can be Project name or anything else
let firstName = “Santoshi” //Details of user whose is purchasing order
let email = “santoshi#app.com" //Details of user whose is purchasing order
let phone = "xxxxxxxxx" //Details of user whose is purchasing order
let sUrl = "www.google.com" //By this URL we match whether payment got success or failure
let fUrl = "www.google.com" //By this URL we match whether payment got success or failure
let service_provider = "payu_paisa"
var txnid1: String! = "" //Its an unique id which can give order a specific order number.
let totalPriceAmount = "1.0"
Above viewdidload do like this
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
initPayment()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
}
In viewdidload do like this
override func viewDidLoad() {
super.viewDidLoad()
Webview.delegate = self
// Do any additional setup after loading the view.
}
Create payment and Generate Hash key
func initPayment() {
txnid1 = “Myapp\(String(Int(NSDate().timeIntervalSince1970)))"
//Generating Hash Key
let hashValue = String.localizedStringWithFormat("%#|%#|%#|%#|%#|%#|||||||||||%#",merchantKey,txnid1,totalPriceAmount,productInfo,firstName,email,salt)
let hash = self.sha1(string: hashValue)
let postStr = "txnid="+txnid1+"&key="+merchantKey+"&amount="+totalPriceAmount+"&productinfo="+productInfo+"&firstname="+firstName+"&email="+email+"&phone="+phone+"&surl="+sUrl+"&furl="+fUrl+"&hash="+hash+"&service_provider="+service_provider
let url = NSURL(string: String.localizedStringWithFormat("%#/_payment", PayUBaseUrl))
let request = NSMutableURLRequest(url: url! as URL)
do {
let postLength = String.localizedStringWithFormat("%lu",postStr.characters.count)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Current-Type")
request.setValue(postLength, forHTTPHeaderField: "Content-Length")
request.httpBody = postStr.data(using: String.Encoding.utf8)
Webview.loadRequest(request as URLRequest)
}
catch let error as NSError
{
print(error)
}
}
Finally Do this
func sha1(string:String) -> String {
let cstr = string.cString(using: String.Encoding.utf8)
let data = NSData(bytes: cstr, length: string.characters.count)
var digest = [UInt8](repeating: 0, count:Int(CC_SHA512_DIGEST_LENGTH))
CC_SHA512(data.bytes, CC_LONG(data.length), &digest)
let hexBytes = digest.map { String(format: "%02x", $0) }
return hexBytes.joined(separator: "")
}
func webViewDidFinishLoad(_ webView: UIWebView) {
let requestURL = self.Webview.request?.url
let requestString:String = (requestURL?.absoluteString)!
if requestString.contains("https://www.payumoney.com/mobileapp/payumoney/success.php") {
print("success payment done")
}else if requestString.contains("https://www.payumoney.com/mobileapp/payumoney/failure.php") {
print("payment failure")
}
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
let requestURL = self.Webview.request?.url
print("WebView failed loading with requestURL: \(requestURL) with error: \(error.localizedDescription) & error code: \(error)")
if error._code == -1009 || error._code == -1003 {
showAlertView(userMessage: "Please check your internet connection!")
}else if error._code == -1001 {
showAlertView(userMessage: "The request timed out.")
}
}
func showAlertView(userMessage:String){
}
I have Faced Same problem and i have got solution of this problem.
In my code this line generate optional values --> let hashSequence : NSString = "(params.key!)|(txnid)|(params.amount!)|(params.productinfo!)|(params.firstname!)|(params.email!)|||||||||||(params.merchantid!)" as NSString
remove optional from the values.
I am trying to serialize a GET request then make a movie object, then appending that movie object to a movies array which I will use to show info on the UI.
I am new and have struggled with this problem for some time now :(
If you look at the self.movies?.append(movie) shouldnt that work? I dont see any reasons as to when i try to get the first item i get fatal error index out of bounds which means I the Array is not filled yet.... Dont know what i am doing wrong :(
import UIKit
class ViewController: UIViewController {
var movies:[Movie]? = []
#IBOutlet weak var uiMovieTitle: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
getMovieData()
print(self.movies?.count)
setUI()
}
#IBAction func yesBtn(_ sender: UIButton) {
print(movies?[5].title ?? String())
}
#IBAction func seenBtn(_ sender: UIButton) {
}
#IBAction func noBtn(_ sender: UIButton) {
}
#IBOutlet weak var moviePoster: UIImageView!
let urlString = "https://api.themoviedb.org/3/discover/movie?api_key=935f539acbfed4b9e5534ddeed3fb57e&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres=12"
func getMovieData(){
//Set up URL
let todoEndPoint: String = "https://api.themoviedb.org/3/discover/movie?api_key=935f539acbfed4b9e5534ddeed3fb57e&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres=12"
guard let url = URL(string: todoEndPoint) else {
print("Cant get URL")
return
}
let urlRequest = URLRequest(url: url)
//Setting up session
let config = URLSessionConfiguration.default
let session = URLSession.shared
//Task setup
let task = session.dataTask(with: urlRequest) { (data, URLResponse, error) in
//Checking for errors
guard error == nil else{
print("Error calling GET")
print(error)
return
}
//Checking if we got data
guard let responseData = data else{
print("Error: No data")
return
}
self.movies = [Movie]()
do{//If we got data, if not print error
guard let todo = try JSONSerialization.jsonObject(with: responseData, options:.mutableContainers) as? [String:AnyObject] else{
print("Error trying to convert data to JSON")
return
}//if data is Serializable, do this
if let movieResults = todo["results"] as? [[String: AnyObject]]{
//For each movieobject inside of movieresult try to make a movie object
for moviesFromJson in movieResults{
let movie = Movie()
//If all this works, set variables
if let title = moviesFromJson["title"] as? String, let movieRelease = moviesFromJson["release_date"] as? String, let posterPath = moviesFromJson["poster_path"] as? String, let movieId = moviesFromJson["id"] as? Int{
movie.title = title
movie.movieRelease = movieRelease
movie.posterPath = posterPath
movie.movieId = movieId
}
self.movies?.append(movie)
}
}
}//do end
catch{
print(error)
}
}
////Do Stuff
task.resume()
}
func setUI(){
//uiMovieTitle.text = self.movies![0].title
//print(self.movies?[0].title)
}
}
my Movie class:
import UIKit
class Movie: NSObject {
var title:String?
var movieRelease: String?
var posterPath:String?
var movieId:Int?
var movieGenre:[Int] = []
//public init(title:String, movieRelease:String, posterPath:String,movieId:Int) {
// self.movieId = movieId
//self.title = title
//self.movieRelease = movieRelease
//self.posterPath = posterPath
//self.movieGenre = [movieGenre]
//}
}
getMovieData calls the network asynchronously. Your viewDidLoad invokes this, then calls setUI() - but the networking is still ongoing when setUI is called.
Instead, call setUI when the networking is complete - after the self.movies?.append(movie) line. The UI code will need to happen on the main thread. So...
for moviesFromJson... // your existing code
...
self.movies?.append(movie)
}
// Refresh UI now movies have loaded.
DispatchQueue.main.async {
setUI()
}
import UIKit
class ViewController: UIViewController {
var movies:[Movie]? = []
#IBOutlet weak var uiMovieTitle: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
getMovieDataCall(completionHandler: {data, error in self. getMovieDataCallBack(data: data, error: error)})
}
func getMovieDataCallBack(data: Data?, error: Error?) {
if error == nil {
let dictionary = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! Dictionary<String, AnyObject>
//do your appending here and then call setUI()
print("dictionaryMovie \(dictionary)")
} else {
showAlertView("", error?.localizedDescription)
}
}
func getMovieDataCall(completionHandler: #escaping (Data?, Error?) -> Void)){
//Set up URL
let todoEndPoint: String = "https://api.themoviedb.org/3/discover/movie?api_key=935f539acbfed4b9e5534ddeed3fb57e&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1&with_genres=12"
guard let url = URL(string: todoEndPoint) else {
print("Cant get URL")
return
}
let urlRequest = URLRequest(url: url)
//Setting up session
let config = URLSessionConfiguration.default
let session = URLSession.shared
//Task setup
let task = session.dataTask(with: urlRequest) { (data, URLResponse, error) in
if error != nil {
NSLog("GET-ERROR", "=\(error)");
completionHandler(nil, error)
} else {
let dataString = String(data: data!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
print(dataString!)
completionHandler(data, nil)
}
task.resume()
}
func setUI(){
}
I am using following Class to receive data from an external database:
import Foundation
protocol HomeModelProtocal: class {
func itemsDownloaded(items: NSArray)
}
class HomeModel: NSObject, NSURLSessionDataDelegate {
//properties
weak var delegate: HomeModelProtocal!
var data : NSMutableData = NSMutableData()
var mi_movil: String = ""
let misDatos:NSUserDefaults = NSUserDefaults.standardUserDefaults()
var urlPath: String = "http:...hidden here.."
let parametros = "?id="
func downloadItems() {
mi_movil = misDatos.stringForKey("ID_IPHONE")!
print ("mi_movil en HOMEMODEL:",mi_movil)
urlPath = urlPath + parametros + mi_movil
let url: NSURL = NSURL(string: urlPath)!
var session: NSURLSession!
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
print ("LA URL ES: ",url)
session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let task = session.dataTaskWithURL(url)
task.resume()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
self.data.appendData(data);
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error != nil {
print("Failed to download data")
}else {
print("Data downloaded")
self.parseJSON()
}
}
func parseJSON() {
var jsonResult: NSMutableArray = NSMutableArray()
do{
jsonResult = try NSJSONSerialization.JSONObjectWithData(self.data, options:NSJSONReadingOptions.AllowFragments) as! NSMutableArray
} catch let error as NSError {
print(error)
}
var jsonElement: NSDictionary = NSDictionary()
let locations: NSMutableArray = NSMutableArray()
for(var i = 0; i < jsonResult.count; i++)
{
jsonElement = jsonResult[i] as! NSDictionary
print (jsonElement)
let location = MiAutoModel()
//the following insures none of the JsonElement values are nil through optional binding
if let id_mis_autos = jsonElement["id_mis_autos"] as? String,
let modelo = jsonElement["modelo"] as? String,
let ano = jsonElement["ano"] as? String,
let id_movil = jsonElement["id_movil"] as? String
{
location.id_mis_autos = id_mis_autos
location.modelo = modelo
location.ano = ano
location.id_movil = id_movil
}
locations.addObject(location)
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.delegate.itemsDownloaded(locations)
})
}
}
If there are received data, it works fine but if there are no data an exception is thrown:
Could not cast value of type '__NSArray0' (0x1a0dd2978) to 'NSMutableArray' (0x1a0dd3490)
What should I change to detect if there are no data to avoid the exception?
Since you don't seem to be modifying jsonResult anywhere, the obvious choice is to make it an NSArray instead of an NSMutableArray, and change the downcasting to match that.
I'm not sure why you're using NSDictionary and NSMutableArray but this is how I would do it:
for result in jsonResult {
guard let jsonElement = result as? [String:AnyObject] else { return }
let locations: [MiAutoModel] = []
let location = MiAutoModel()
//the following insures none of the JsonElement values are nil through optional binding
let id_mis_autos = jsonElement["id_mis_autos"] as? String ?? ""
let modelo = jsonElement["modelo"] as? String ?? ""
let ano = jsonElement["ano"] as? String ?? ""
let id_movil = jsonElement["id_movil"] as? String ?? ""
location.id_mis_autos = id_mis_autos
location.modelo = modelo
location.ano = ano
location.id_movil = id_movil
locations.append(location)
}
You might have to change some of the code depending on your situation.