Swift 3 Passing Data between view Controllers - uiviewcontroller

I am attempting to pass data from one controller to the next. The code is as follows
First view controller:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let parameters: Parameters = [
"x": 2,
"y": 2
]
Alamofire.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default).responseJSON { response in
if((response.result.value) != nil) {
let jsonVar: JSON = JSON(response.result.value ?? "success")
let destViewController : JSONResult = segue.destination as! JSONResult
let result = "\(jsonVar)"
destViewController.textLabel = result
print(result)
//self.jsonDisplayError.text = "\(jsonVar)"
} else {
self.jsonDisplayError.text = "no response"
}
}
}
Second view controller:
#IBOutlet var jsonResult: UILabel!
var textLabel = String()
override func viewDidLoad() {
jsonResult.text = textLabel
}
The result is being printed to the console correctly but it is not displaying in the label on the second view controller page.

I think the problem is sending data in async callback, you've two options here,
First Solution
Pass parameters to secondviewcontroller and make your API request on secondviewcontroller's viewdidload event.
class FirstViewController: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let parameters: Parameters = [
"x": 2,
"y": 2
]
destViewController.parametrs = parameters
}
}
And secondviewcontroller,
class SecondViewController: UIViewController {
#IBOutlet var jsonResult: UILabel!
var parameters: Parameters
override func viewDidLoad() {
Alamofire.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default).responseJSON { response in
if((response.result.value) != nil) {
let jsonVar: JSON = JSON(response.result.value ?? "success")
jsonResult.text = result
} else {
self.jsonDisplayError.text = "no response"
}
}
}
}
Second Solution
Create a seque between two viewcontroller (not button click etc.), and performSegue manually when your async callback completed,
class FirstViewController: UIViewController {
var result = ""
#IBAction func buttonClick(sender: UIButton) {
let parameters: Parameters = [
"x": 2,
"y": 2
]
Alamofire.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default).responseJSON { response in
if((response.result.value) != nil) {
let jsonVar: JSON = JSON(response.result.value ?? "success")
self.result = "\(jsonVar)"
self.performSegue(withIdentifier: "yourSegueIdentifier", sender: nil)
} else {
self.jsonDisplayError.text = "no response"
}
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destViewController : JSONResult = segue.destination as! JSONResult
destViewController.textLabel = self.result
}
}
Second view controller:
class SecondViewController: UIViewController {
#IBOutlet var jsonResult: UILabel!
var textLabel = String()
override func viewDidLoad() {
jsonResult.text = textLabel
}
}

Related

swift json help in displaying data on table view controller

// my url
// https://fetch-hiring.s3.amazonaws.com/hiring.json
/*
my json
[
{"id": 383, "listId": 4, "name": ""},
{"id": 472, "listId": 1, "name": ""},
{"id": 625, "listId": 2, "name": null}
]
*/
// my main vc class for table view controller
import UIKit
class HeadlLinesTableViewController: UITableViewController {
var parse = [HiringElement]()
override func viewDidLoad() {
// Do any additional setup after loading the view.
super.viewDidLoad()
// Do any additional setup after loading the view.
let urlString = "https://fetch-hiring.s3.amazonaws.com/hiring.json"
guard let url = URL(string: urlString) else { return }
// 2
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
}
guard let data = data else { return }
// 3
//Decode data
self.Elements = try? JSONDecoder().decode(HiringElement.self, from: data)
print(data)
// 4
//Get back to the main queue
DispatchQueue.main.async {
self.tableView.reloadData()
}
// 5
}.resume() // fires of request
}
My model struct for my api this is something I used from quickTypeIo api generator
struct HiringElement: Codable {
let id, listID: Int
let name: String?
enum CodingKeys: String, CodingKey {
case id
case listID
case name
}
} typealias Hiring = [HiringElement]
And my table view controller method here I can't display data on and some some errors. I am using tableview controller so doesn't need tableview delegate or datasource
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
guard let articles = Elements else { return 0 }
return return parse.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
as? newsTableViewCell else {
fatalError(" cell not found ") }
// here I have errors thanks
cell.titleLabel.text = parse[indexPath.row].name
print(cell.titleLabel.text)
return cell
}
}
Here is my table view cell class
import UIKit
class newsTableViewCell: UITableViewCell {
//var article:Article!
#IBOutlet weak var avator: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var newsLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
I think you should work on the decoding part. Here is a solution:
struct HiringElement: Decodable {
let id, listId: Int
let name: String?
}
#propertyWrapper
struct IgnoreFailure<Value: Decodable>: Decodable {
var wrappedValue: [Value] = []
private struct _None: Decodable {}
init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
while !container.isAtEnd {
if let decoded = try? container.decode(Value.self) {
wrappedValue.append(decoded)
}
else {
try? container.decode(_None.self)
}
}
}
}
Then write the following code in your HeadlLinesTableViewController.swift.
typealias ArrayIgnoringFailure<Value: Decodable> = IgnoreFailure<Value>
Then try decoding as:
guard let objects = try? JSONDecoder().decode(ArrayIgnoringFailure<HiringElement>.self, from: data) else { return }
self.elements = objects.wrappedValue
Hope it will solve your problems.

Xcode func used in another View Controller

I have this func in a Swift file, and it returns the value of the data in the database and prints it out in the counsel.
I want to use the value in the other View Controller but I can't get this to work, so I hope somebody can help me.
It is the nameUser, statusUser and pointUser I like to use in other View Controller.
import Foundation
import UIKit
var code = "100"
var getStatusUSer = ""
class getJSON: NSObject, URLSessionDataDelegate
{
//properties
var data : NSMutableData = NSMutableData()
func downloadItems()
{
let url = NSMutableURLRequest(url: NSURL(string: "http://www.hholm.dk/time_app/qrcode4.php")! as URL)
url.httpMethod = "POST"
let postString = "username=\(code)"
url.httpBody = postString.data(using: String.Encoding.utf8)
print(url.httpBody = postString.data(using: String.Encoding.utf8))
var session: URLSession!
let configuration = URLSessionConfiguration.default
session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let task = session.dataTask(with: url as URLRequest)
task.resume()
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
{
self.data.append(data as Data);
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
{
if error != nil
{
print("Not Found", error)
}
else
{
print("Ok")
self.parseJSON()
}
}
func parseJSON()
{
var jsonResult: NSArray = NSArray()
do
{
jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
print("jsonResult.count",jsonResult.count)
}
catch let error as NSError
{
print("jsonResult: ", error)
}
var jsonElement: NSDictionary = NSDictionary()
var contador = 0
for i in (0..<jsonResult.count)
{
jsonElement = jsonResult[i] as! NSDictionary
if let nameUser = jsonElement["name"] as? String,
let pointUser = jsonElement["point"] as? String,
let statusUser = jsonElement["status"] as? String
{
getStatusUSer = statusUser
print("Name: ", nameUser)
print("Status: ", statusUser)
print("Point: ", pointUser)
}
}
}
}
Hi Woof this is what i have in my viewcontroler:
import UIKit
class inputcodeViewController: UIViewController {
#IBOutlet weak var input: UITextField!
#IBAction func but(_ sender: Any) {
downloadItems()
}
func downloadItems(){
let getJson = GetJSON()
//setting the delegate
getJson.delegate = self
//starting download
getJson.downloadItems()
}
}
extension inputcodeViewController: GetJSONDelegate {
func didReceiveValues(name: String, status: String, point: String){
//now you can use values in your view controller
}
}
how can i print the values
You can use protocol to return those values:
import Foundation
import UIKit
var code = "100"
var getStatusUSer = ""
//define the protocol
protocol GetJSONDelegate {
func didReceiveValues(name: String, status: String, point: String)
}
//I've changed the first char of the class name to uppercase
class GetJSON: NSObject, URLSessionDataDelegate{
//properties
var data : NSMutableData = NSMutableData()
//delegate
var delegate: GetJSONDelegate?
func downloadItems(){
let url = NSMutableURLRequest(url: NSURL(string: "http://www.hholm.dk/time_app/qrcode4.php")! as URL)
url.httpMethod = "POST"
let postString = "username=\(code)"
url.httpBody = postString.data(using: String.Encoding.utf8)
print(url.httpBody = postString.data(using: String.Encoding.utf8))
var session: URLSession!
let configuration = URLSessionConfiguration.default
session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let task = session.dataTask(with: url as URLRequest)
task.resume()
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
{
self.data.append(data as Data);
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
{
if error != nil
{
print("Not Found", error)
}
else
{
print("Ok")
self.parseJSON()
}
}
func parseJSON()
{
var jsonResult: NSArray = NSArray()
do
{
jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
print("jsonResult.count",jsonResult.count)
}
catch let error as NSError
{
print("jsonResult: ", error)
}
var jsonElement: NSDictionary = NSDictionary()
var contador = 0
for i in (0..<jsonResult.count)
{
jsonElement = jsonResult[i] as! NSDictionary
if let nameUser = jsonElement["name"] as? String,
let pointUser = jsonElement["point"] as? String,
let statusUser = jsonElement["status"] as? String
{
getStatusUSer = statusUser
print("Name: ", nameUser)
print("Status: ", statusUser)
print("Point: ", pointUser)
//here we will return received data to the delegate
self.delegate?.didReceiveValues(name: nameUser, status: statusUser, point: pointUser)
}
}
}
}
Now we need to set your controller as a delegate for that protocol:
//this is an example, you need to add the methods described in your controller where you want to use those values
class YourViewController: UIViewController{
// the method that is called by you to get values
func downloadItems(){
let getJson = GetJSON()
//setting the delegate
getJson.delegate = self
//starting download
getJson.downloadItems()
}
}
//defining protocol methods in the extension of the view controller
extension YourViewController: GetJSONDelegate {
func didReceiveValues(name: String, status: String, point: String){
//now you can use values in your view controller
}
}

how to parse complex JSON and show it inside and outside of CollectionView

I have been dealing with JSON for a month now , getting better day by day. Here is a complex jigsaw I have been circling around. JSON return I get is like this :
{
"main_content": [
{
"product_title": "product 3",
"description": "",
"regular_price": "320",
"sale_price": "",
"product_currency": "$",
"size": [
{
"size_data": "L"
},
{
"size_data": "S"
}
],
"color": [
{
"color_data": "RED"
},
{
"color_data": "WHITE"
}
],
"gallery": [
{
"guid": "http://xxx/wp-content/uploads/2016/11/catagory1.jpg"
},
{
"guid": "http://xxx/wp-content/uploads/2016/11/catagory3.jpg"
}
]
}
]
}
Now , here product_title , description , regular_price , sale_price and product_currency will be outside of array as you can see. For size & color I need to fetch as array outside of my CollectionView , I dunno how to iterate through the array outside of a collectionView or tableView, coz in those I got an indexpath to iterate but I dunno what to do outside a collectionView or tableView. Finally My Image slider will be inside CollectionView therefore gallery items needs to be inside that. Here is visual image of my respective page.
Now here is the POST call using Alamofire in my view
import Foundation
import Alamofire
import SwiftyJSON
//Error could happen for these reason
enum ProductDetailsManagerError: Error {
case network(error: Error)
case apiProvidedError(reason: String)
case authCouldNot(reason: String)
case authLost(reason: String)
case objectSerialization(reason: String)
}
// APIManager Class
class ProductDetailsManager {
// THE RIGHT WAY A.K.A. "THE ONE LINE SINGLETON (NOW WITH PROOF!")
static let sharedInstance = ProductDetailsManager()
func printPublicGists(parameter: [String:Any]? , completionHandler: #escaping (Result<[ProductDetailsJSON]>) -> Void) {
let url: String = "http://xxx/wp-api/products/get_product_informations/"
Alamofire.request(url, method: .post, parameters: parameter, encoding: URLEncoding.default, headers: nil)
.responseJSON { (response) in
guard response.result.error == nil else {
print(response.result.error!)
return
}
guard let value = response.result.value else {
print("no string received in response when swapping oauth code for token")
return
}
print(value)
}
}
func fetchPublicGists(parameter: [String:Any]? , completionHandler: #escaping (Result<[ProductDetailsJSON]>) -> Void) {
let url: String = "http://xxx/wp-api/products/get_product_informations/"
Alamofire.request(url, method: .post, parameters: parameter, encoding: URLEncoding.default, headers: nil)
.responseJSON { response in
let result = self.gistArrayFromResponse(response: response)
completionHandler(result)
}
}
// Download Image from URL
func imageFrom(urlString: String, completionHandler: #escaping (UIImage?, Error?) -> Void) {
let _ = Alamofire.request(urlString)
.response { dataResponse in
// use the generic response serializer that returns Data
guard let data = dataResponse.data else {
completionHandler(nil, dataResponse.error)
return
}
let image = UIImage(data: data)
completionHandler(image, nil)
}
}
//gistArrayFromResponse function
private func gistArrayFromResponse(response: DataResponse<Any>) -> Result<[ProductDetailsJSON]> {
// For Network Error
guard response.result.error == nil else {
print(response.result.error!)
return .failure(RueDu8APIManagerError.network(error: response.result.error!))
}
// JSON Serialization Error, make sure we got JSON and it's an array
guard let jsonArray = response.result.value else {
print("did not get array of homeFeed object as JSON from API")
return .failure(RueDu8APIManagerError.objectSerialization(reason: "Did not get JSON dictionary in response"))
}
//turn JSON into gists
//let gistss = jsonArray.flatMap { HomeFeedJSON(items: $0) }
var gists = [ProductDetailsJSON]()
let jsonR = JSON(jsonArray)
let main_content = jsonR["main_content"].array
for item in main_content! {
gists.append(ProductDetailsJSON(items: item))
}
return .success(gists)
}//gistArrayFromResponse() function ends here
}
here is my model class
import Foundation
import SwiftyJSON
class ProductDetailsJSON {
var _product_title: String?
var _description: String?
var _regular_price: String?
var _sale_price: String?
var _product_currency: String?
var _size: String?
var _color: String?
var _image: URL?
init(items: JSON){
self._product_title = items["product_title"].stringValue
self._description = items["description"].stringValue
self._regular_price = items["regular_price"].stringValue
self._sale_price = items["sale_price"].stringValue
self._product_currency = items["product_currency"].stringValue
let sizeData = items["size"].arrayValue
for itemsIMG in sizeData {
self._size = itemsIMG["size_data"].stringValue
}
let colorData = items["color"].arrayValue
for itemsColor in colorData {
self._size = itemsColor["color_data"].stringValue
}
let galleryImg = items["gallery"].arrayValue
for image in galleryImg {
self._image = image["guid"].URL
}
}
var product_title: String {
if _product_title == nil {
_product_title = ""
}
return _product_title!
}
var description: String {
if _description == nil {
_description = ""
}
return _description!
}
var regular_price: String {
if _regular_price == nil {
_regular_price = ""
}
return _regular_price!
}
var sale_price: String {
if _sale_price == nil {
_sale_price = ""
}
return _sale_price!
}
var product_currency: String {
if _product_currency == nil {
_product_currency = ""
}
return _product_currency!
}
var product_color: String {
if _color == nil {
_color = ""
}
return _size!
}
var product_image: URL {
if _image == nil {
let myURL = "http://www.clker.com/cliparts/d/L/P/X/z/i/no-image-icon-hi.png"
let noImage: URL = URL(string: myURL)!
_image = noImage
}
return _image!
}
}
and here is my controller class where I am struggling to show the size , color and gallery items from JSON
import UIKit
import DropDown
import Alamofire
import SwiftyJSON
class ShopItemVC: UIViewController , UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var contentView: UIView!
#IBOutlet weak var selectedProductImg: UIImageView!
#IBOutlet weak var backgroundCardView1: UIView!
#IBOutlet weak var backgroundCardView2: UIView!
#IBOutlet weak var backgroundCardView3: UIView!
#IBOutlet weak var sizeBtn: NiceButton!
#IBOutlet weak var colorBtn: NiceButton!
#IBOutlet weak var productPrice: UILabel!
#IBOutlet weak var productTitle: UILabel!
// var Title = [ProductDetailsJSON]()
var product_id:Int? //got value from SpecificCatagoryVC
var product_detail = [ProductDetailsJSON]()
var reloadData = 0
let sizeDropDown = DropDown()
let colorDropDown = DropDown()
lazy var dropDowns: [DropDown] = {
return [
self.sizeDropDown,
self.colorDropDown
]
}()
let CatagoryPic = ["catagory1","catagory2","catagory3","catagory4","catagory5","catagory6","c atagory7"]
// let CatagoryPicture = [ProductDetailsJSON]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
sizeBtn.layer.borderWidth = 1.2
sizeBtn.layer.borderColor = UIColor.black.cgColor
colorBtn.layer.borderWidth = 1.2
colorBtn.layer.borderColor = UIColor.black.cgColor
backgroundCardView1.backgroundColor = UIColor.white
backgroundCardView1.layer.cornerRadius = 5.0
backgroundCardView1.layer.masksToBounds = false
backgroundCardView1.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
backgroundCardView1.layer.shadowOffset = CGSize(width: 0, height: 0)
backgroundCardView1.layer.shadowOpacity = 0.8
backgroundCardView2.backgroundColor = UIColor.white
backgroundCardView2.layer.cornerRadius = 5.0
backgroundCardView2.layer.masksToBounds = false
backgroundCardView2.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
backgroundCardView2.layer.shadowOffset = CGSize(width: 0, height: 0)
backgroundCardView2.layer.shadowOpacity = 0.8
backgroundCardView3.backgroundColor = UIColor.white
backgroundCardView3.layer.cornerRadius = 5.0
backgroundCardView3.layer.masksToBounds = false
backgroundCardView3.layer.shadowColor = UIColor.black.withAlphaComponent(0.2).cgColor
backgroundCardView3.layer.shadowOffset = CGSize(width: 0, height: 0)
backgroundCardView3.layer.shadowOpacity = 0.8
setupDropDowns()
}
override func viewDidAppear(_ animated: Bool) {
self.scrollView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height + 40)
loadGists(parameter: ["product_id":product_id ?? 0])
}
func setupDropDowns() {
setupSizeDropDown()
setupColorDropDown()
}
func setupSizeDropDown() {
sizeDropDown.anchorView = sizeBtn
sizeDropDown.bottomOffset = CGPoint(x: 0, y: sizeBtn.bounds.height)
// You can also use localizationKeysDataSource instead. Check the docs.
sizeDropDown.dataSource = [
"XXL",
"XL",
"L",
"M",
"S"
]
// Action triggered on selection
sizeDropDown.selectionAction = { [unowned self] (index, item) in
self.sizeBtn.setTitle(item, for: .normal)
print(item)
}
}
func setupColorDropDown() {
colorDropDown.anchorView = colorBtn
colorDropDown.bottomOffset = CGPoint(x: 0, y: colorBtn.bounds.height)
// You can also use localizationKeysDataSource instead. Check the docs.
colorDropDown.dataSource = [
"Red",
"Blue",
"White",
"Purple",
"Pink"
]
// Action triggered on selection
colorDropDown.selectionAction = { [unowned self] (index, item) in
self.colorBtn.setTitle(item, for: .normal)
print(item)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func loadGists(parameter: [String:Any]?) {
ProductDetailsManager.sharedInstance.fetchPublicGists(parameter: parameter) {
(result) in
guard result.error == nil else {
self.handleLoadGistsError(result.error!)
return
}
if let fetchedGists = result.value {
self.product_detail = fetchedGists
}
self.reloadData = 1
self.collectionView?.reloadData()
}
}
func handleLoadGistsError(_ error: Error) { }
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return CatagoryPic.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ShopItemCell", for: indexPath) as! ShopItemCell
if reloadData == 1 {
let myProduct = self.product_detail[indexPath.row]
self.productTitle.text = myProduct.product_title
}
cell.shopItemPic.image = UIImage(named: CatagoryPic[(indexPath as NSIndexPath).row])
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// here you know which item is selected by accessing indexPath.item property, for example:
let selectedImage = UIImage(named: CatagoryPic[(indexPath as NSIndexPath).item])
selectedProductImg.image = selectedImage
}
#IBAction func sizeBtnPressed(_ sender: Any) {
sizeDropDown.show()
//print("size btn pressed")
}
#IBAction func colorBtnPressed(_ sender: Any) {
colorDropDown.show()
}
#IBAction func backBtn(_ sender: AnyObject) {
self.dismiss(animated: true, completion: nil)
}
}
There are some other class where I am facing the same issue. Hope If I get this solution I will be able to solve those. Thanks in advance .
First thing to note is that you are returning the size value and not color in the product_color variable.
Also when you loop through the arrays in your JSON, you're setting the variable to only be the final value. For example here:
let sizeData = items["size"].arrayValue
for itemsIMG in sizeData {
self._size = itemsIMG["size_data"].stringValue
}
The JSON is
"size": [
{
"size_data": "L"
},
{
"size_data": "S"
}
]
So _size is going to be set as "S" and "L" will never be assigned. I'd suggest changing _size, _color and _image to
var _sizes: [String] = []
var _colors: [String] = []
var _images: [String] = []
And then when looping through the JSON array:
let sizeData = items["size"].arrayValue
for itemsIMG in sizeData {
let size = itemsIMG["size_data"].stringValue
_sizes.append(size)
}
If I'm understanding correctly, you then want to update your dropdown data when you get the response with the gist.
sizeDropDown.dataSource = product_detail.product_sizes
Then the same for the other drop downs.
And create product_sizes, product_colors and product_images variables in the model similar sale_price and regular_price.

Parsing JSON data from alamofire into Array with Dictionary

I'm trying to parse JSON data from alamorefire as follows.
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(.GET, "https://api.mynexttrainschedule.net/")
.responseJSON { response in
guard let object = response.result.value else {
print("Oh, no!!!")
return
}
let json = JSON(object);print(json)
let schedule = json[0]["schedule"]
}
}
}
If I print json, I have a data structure like the following (stated concisely).
[
{
"schedule" : [
{"departureTime" : "05:09", "destination" : "Boston", "trainType" : "Express"},
{"departureTime" : "05:19", "destination" : "Portland", "trainType" : "Rapid"},
{"departureTime" : "05:29", "destination" : "Boston", "trainType" : "Express""}
],
"station" : "Grand Central",
"direction" : "North"
},
{
"schedule" : [
{"departureTime" : "05:11","destination" : "Washington, "trainType" : "Express""},
{"departureTime" : "05:23","destination" : "Baltimore, "trainType" : "Express""},
{"departureTime" : "05:35","destination" : "Richmond, "trainType" : "Local""}
],
"station" : "Grand Central",
"direction" : "South"
}
]
Now, how can I save the schedule array with a dictionary (departureTime, destination...) through or not through SwiftyJSON?
Thanks.
UPDATE
The following is my own solution.
import Alamofire
import SwiftyJSON
class ViewController: UIViewController {
var scheduleArray = [Dictionary<String,String>]()
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(.GET, "https://api.mynexttrainschedule.net/")
.responseJSON { response in
guard let object = response.result.value else {
print("Oh, no!!!")
return
}
let json = JSON(object)
if let jArray = json.array {
if let westHolidayArray = jArray[0]["schedule"].array {
for train in westHolidayArray {
if let time = train["departureTime"].string,
let dest = train["destination"].string,
let type = train["trainType"].string {
let dict = ["time":time, "dest":dest, "type": type]
self.scheduleArray.append(d)
}
}
}
}
}
}
}
First of all you should create a class that is your model of Schedule like this
class Schedule: NSObject {
var departureTime: String
var destination: String
var trainType: String
init(jsonDic : NSDictionary) {
self.departureTime = jsonDic["departureTime"] != nil ? jsonDic["departureTime"] as! String! : nil
self.destination = jsonDic["destination"] != nil ? jsonDic["destination"] as! String! : nil
self.trainType = jsonDic["trainType"] != nil ? jsonDic["trainType"] as! String : nil
}
}
And in your view controller your going to need an array of the Schedule object and after you could parse your Json you do it like this:
class ScheduleController: UIViewController {
// The two object use to show the spinner loading
var loadingView: UIView = UIView()
var spinner = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
// Array of your objects
var arrSchedule: [Schedule] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.getInfoSchedule()
}
func getInfoSchedule() {
showActivityIndicator()
Alamofire.request("https://api.mynexttrainschedule.net/", method: .get, parameters: nil, encoding: URLEncoding.default, headers: nil).responseJSON {
response in
self.hideActivityIndicator()
switch response.result {
case .success:
if let objJson = response.result.value as! NSArray? {
for element in objJson {
let data = element as! NSDictionary
if let arraySchedule = data["schedule"] as! NSArray? {
for objSchedule in arraySchedule {
self.arrSchedule.append(Schedule(jsonDic: objSchedule as! NSDictionary))
}
}
}
}
case .failure(let error):
print("Error: \(error)")
}
}
}
//Those two method serves to show a spinner when the request is in execution
func showActivityIndicator() {
DispatchQueue.main.async {
self.loadingView = UIView()
self.loadingView.frame = CGRect(x: 0.0, y: 0.0, width: self.view.frame.width, height: self.view.frame.height)
self.loadingView.center = self.view.center
self.loadingView.backgroundColor = UIColor(rgba: "#111111")
self.loadingView.alpha = 0.9
self.loadingView.clipsToBounds = true
self.spinner = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
self.spinner.frame = CGRect(x: 0.0, y: 0.0, width: 80.0, height: 80.0)
self.spinner.center = CGPoint(x:self.loadingView.bounds.size.width / 2, y:self.loadingView.bounds.size.height / 2)
self.loadingView.addSubview(self.spinner)
self.view.addSubview(self.loadingView)
self.spinner.startAnimating()
}
}
func hideActivityIndicator() {
DispatchQueue.main.async {
self.spinner.stopAnimating()
self.loadingView.removeFromSuperview()
}
}
}
Maybe is not the more efficient way to do it, but it worked for me. I'm using swift3 with xcode 8.1.
Hope it helps !
Basically what you have is an array of schedules. You can map it using ObjectMapper. Install its pod and just create a new Swift file. and Write this
import ObjectMapper
class TrainSchedules: Mappable {
var mySchedules: [Schedules]
required init?(_ map: Map) {
mySchedules = []
}
func mapping(map: Map) {
mySchedules <- map["schedule"]
}
}
class Schedules: Mappable {
var departureTime: String
var destination: String
var trainType: String
required init?(_ map: Map) {
departureTime = ""
destination = ""
trainType = ""
}
func mapping(map: Map) {
departureTime <- map["departureTime"]
destination <- map["destination"]
trainType <- map["trainType"]
}
}
Now you can use it like
if let data = Mapper<TrainSchedules>().map(json){
// now data is an array containt=g all the schedules
// access departureTimelike below
print(data[0].departureTime)
}
I hope it helps, Letme know if you find any difficulty.
Alamofire.request("YOUR_URL", method:.post, parameters:params, encoding:URLEncoding.default, headers: nil).responseJSON { response in
switch(response.result)
{
case .success(_):
if response.result.value != nil
{
let dict :NSDictionary = response.result.value! as! NSDictionary
print(dict)
let status = dict.value(forKey: "status")as! String
print(status)
if(status=="1")
{
self.array_placeRequestId=((dict.value(forKeyPath: "result.request_id") as! NSArray).mutableCopy() as! NSMutableArray)
}
else
{
print("Something Missed")
}
}
break
case .failure(_):
print(response.result.error)
break
}
}

nil while parsing JSON in Swift

I am doing some easy projects to learn new things. I started parsing JSON with SwiftyJSON. I am trying to show some JSON data to the tableView but now I am stuck. I do not know where is the nil and why. Can you help me guys? In given code I am trying to get the "Brands" and show them inside tableView or at least print those into console.
This is the .json file I have:
{
"Snuses": {
"Brands":{
"CATCH": [
{"Products":"white", "nicotine":"8.0"},
{"Products":"yellow", "nicotine":"8.0"}
],
"GENERAL": [
{"Products":"brown", "nicotine":"8.0"},
{"Products":"white", "nicotine":"8.0"}
]
}
}
}
And here I try to get the info like this:
var numberOfRows = 0
var snusBrandsArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
parseJSON()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func parseJSON(){
let path: String = NSBundle.mainBundle().pathForResource("snuses", ofType: "json") as String!
let jsonData = NSData(contentsOfFile: path) as NSData!
let readableJSON = JSON(data: jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil)
var brands = readableJSON["Snuses", "Brands"]
NSLog("\(brands)")
numberOfRows = readableJSON["Snuses"].count
for i in 1...numberOfRows{
var brands = "Snuses"
brands += "\(i)"
var name = readableJSON["Snuses", "Brands"].string as String!
snusBrandsArray.append(name)
}
}
What about something simple, like this? Below is Playground code but the parsing is the same.
//: Playground
import UIKit
import Foundation
var jsonStr = "{ \"Snuses\": { \"Brands\":{ \"CATCH\": [ {\"Products\":\"white\", \"nicotine\":\"8.0\"}, {\"Products\":\"yellow\", \"nicotine\":\"8.0\"} ], \"GENERAL\": [ {\"Products\":\"brown\", \"nicotine\":\"8.0\"}, {\"Products\":\"white\", \"nicotine\":\"8.0\"} ] } } }"
func parseJSON(jsonStr:String) throws -> [AnyObject]? {
var brandNameKeys:[AnyObject]?
let jsonData = jsonStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let json = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions())
if let brandNameDict = json["Snuses"]!?["Brands"] as? NSDictionary
{
brandNameKeys = brandNameDict.allKeys
}
return brandNameKeys
}
if let result = try parseJSON(jsonStr)
{
print(result)
}
In my Playground this outputs ["CATCH", "GENERAL"] which I think is what you want.
Here's a full UITableViewController demonstrating the solution in use:
import UIKit
class TableViewController: UITableViewController {
var data:[AnyObject]?
override func viewDidLoad() {
super.viewDidLoad()
if let path: String = NSBundle.mainBundle().pathForResource("Data", ofType: "json")
{
do
{
let jsonStr = try String(contentsOfFile: path)
data = try parseJSONStr(jsonStr)
}
catch _ {
print("Loading json failed")
}
}
}
// JSON Parsing
func parseJSONStr(jsonStr:String) throws -> [AnyObject]? {
var brandNameKeys:[AnyObject]?
let jsonData = jsonStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let json = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions())
if let brandNameDict = json["Snuses"]!?["Brands"] as? NSDictionary
{
brandNameKeys = brandNameDict.allKeys
}
return brandNameKeys
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let data = data
{
return data.count
}
else
{
return 0
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("SampleCell", forIndexPath: indexPath)
if let rowData = data![indexPath.row] as? String
{
cell.textLabel?.text = rowData
}
return cell
}
}