I wrote this code to read country at table view from this JSON file :
JSON:
[5]
0: {
"country": "Afghanistan"
"code": "AF"
}-
1: {
"country": "Ă…land Islands"
"code": "AX"
}-
2: {
"country": "Albania"
"code": "AL"
}-
3: {
"country": "Algeria"
"code": "DZ"
}-
4: {
"country": "American Samoa"
"code": "AS"
}
My code :
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var tableCountryView: UITableView!
var json_url = "........ my url here ......... "
var TableData:Array< datastruct > = Array < datastruct >()
enum ErrorHandler:ErrorType
{
case ErrorFetchingResults
}
struct datastruct
{
var country_name:String?
var country_code:String?
init(add: NSDictionary)
{
country_name = add["country"] as? String
country_code = add["code"] as? String
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableCountryView.dataSource = self
tableCountryView.delegate = self
get_data_from_url(json_url)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
let data = TableData[indexPath.row]
cell.textLabel?.text = data.country_name! + " - " + data.country_code!
return cell
}
func get_data_from_url(url:String)
{
let url:NSURL = NSURL(string: url)!
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "GET"
request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringCacheData
let task = session.dataTaskWithRequest(request) {
(
let data, let response, let error) in
guard let _:NSData = data, let _:NSURLResponse = response where error == nil else {
print("error")
return
}
dispatch_async(dispatch_get_main_queue(), {
self.extract_json(data!)
return
})
}
task.resume()
}
func extract_json(jsonData:NSData)
{
let json: AnyObject?
do {
json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
} catch {
json = nil
return
}
if let list = json as? NSArray
{
for (var i = 0; i < list.count ; i++ )
{
if let data_block = list[i] as? NSDictionary
{
TableData.append(datastruct(add: data_block))
}
}
do_table_refresh()
}
}
func do_table_refresh()
{
dispatch_async(dispatch_get_main_queue(), {
self.tableCountryView.reloadData()
return
})
}
}
This code is working true for the first JSON syntax but if I want to read sub-array like the syntax at the following JSON file , how I can edit that in my previous code.
JSON:
{
"Countries": [4]
0: {
"countryname": "Egypt"
"code": "20"
}-
1: {
"countryname": "India"
"code": "91"
}-
2: {
"countryname": "United States"
"code": "1"
}-
3: {
"countryname": "Turkey"
"code": "90"
}-
}
Also I have the button at my storyboard and I want to show this table view of country when clicking on this button and then choose one country and close this table and show the result on the button , I know this easy but I started to learn IOS from 2 weeks only, I hope if you can give me advice in these cases.
Related
I m building iOS application using swift 4.2 and I have a TableViewController that have a strange behaviour.
This is the code:
import UIKit
class StoreByCategoryViewController: UITableViewController{
#IBOutlet var storeTableView: UITableView!
var categorySelected:CategoryModel?
var listaStore = [StoreModel]()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Elenco Partner"
if((categorySelected) != nil && categorySelected?.id != "0"){
//posso chiamare il WS estraendo tutti i negozi
//per categoria
getStoreByCategory(category : self.categorySelected!);
storeTableView.reloadData()
}else{
getStore();
}
storeTableView.delegate = self
storeTableView.dataSource = self
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return listaStore.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return listaStore.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = storeTableView.dequeueReusableCell(withIdentifier:"customCell") as! StoreTableViewCell
let storeModel = listaStore[indexPath.row]
cell.storeAddress.text = storeModel.address
cell.storePhone.text = storeModel.phoneNumber
cell.storeDescription.text = storeModel.description
if(storeModel.imageUrl != ""){
print(storeModel.imageUrl)
let imageUrl:NSURL = NSURL(string: storeModel.imageUrl!)!
print(storeModel.imageUrl)
DispatchQueue.global(qos: .userInitiated).async {
let imageData:NSData = NSData(contentsOf: imageUrl as URL)!
DispatchQueue.main.async {
let image = UIImage(data: imageData as Data)
cell.storeImage.image = image
cell.storeImage.contentMode = .scaleToFill
}
}
}
// cell.storeImage.layer.cornerRadius = cell.storeImage.frame.height / 2
return cell
}
func getStoreByCategory(category : CategoryModel){
var params = [
"cat_id" : category.id
]
let postUrl = APIRequest(endPoint: "get_store_by_category")
postUrl.sendRequest(parameters: params as! [String : String]) {
responseObject, error in
guard let responseObject = responseObject, error == nil else {
print(error ?? "Unknown error")
return
}
do{
let messageData = try JSONDecoder().decode(ResponseStoreByCategoryModel.self, from: responseObject)
var array = messageData.result
for store in array {
var imageUrl = ""
if(store.image.count > 0){
imageUrl = store.image[0].image
}
let s = StoreModel(id: "",
description: store.firstName,
imageUrl: imageUrl,
address: store.address,
phoneNumber: store.phone)
self.listaStore.append(s)
}
self.storeTableView.reloadData()
}catch{
print("errore durante la decodifica dei dati")
}
}
}
func getStore(){
var params = [
"" : ""
]
let postUrl = APIRequest(endPoint: "get_store")
postUrl.sendRequest(parameters: params as! [String : String]) {
responseObject, error in
let user = CategoryModel(id: "0",
description: "Tutti",
imageUrl: "")
//self.listaCategorie.append(user)
guard let responseObject = responseObject, error == nil else {
print(error ?? "Unknown error")
return
}
do{
let messageData = try JSONDecoder().decode(ResponseStoreModel.self, from: responseObject)
var array = messageData.result
for store in array {
var imageUrl = ""
if(store.image.count > 0){
imageUrl = store.image[0].image
}
let s = StoreModel(id: "",
description: store.firstName,
imageUrl: imageUrl,
address: store.address,
phoneNumber: store.phone)
self.listaStore.append(s)
}
self.storeTableView.reloadData()
}catch{
print("errore durante la decodifica dei dati")
}
}
}
}
Method getStore, getStoreByCategory, return 9 items, but the method
numberOfSection and the method to populate customCell, are called 3 times. So i have a table with 27 items instead of 9 items.
Looks like you want only 1 section with 9 rows in it. If that's the case, you can return 1 from numberOfSections implementation.
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
The other thing I noticed is - you have a UITableViewController and an #IBOutlet var storeTableView: UITableView! as well. You don't need the outlet, You can use self.tableView for the same.
I am very new to Swift 4 and I am not able to get an example on parsing JsonArray using JSONDecoder.
Below is the JSON Response which I am trying to parse from past many days.
{
"News": [ // how can i use this news as key in swift and parse it
{
"intId": 354,
"Guid": "4829b85d-56ed-46ed-b489-ddbaf0eaeb05",
"stTitle": "Hyatt place pune CsR Thrive Activity - 2017",
"dtUpdatedDate": "2017-06-01T11:25:00"
},
{
"intId": 115,
"Guid": "bcc1272c-6a47-4878-9091-5af224be494c",
"stTitle": "CIRCULAR W.R.T. BOMBAY HIGH COURT INJUNCTION AGAINST NOVEX",
"dtUpdatedDate": "2014-06-26T17:29:00"
},
{
"intId": 120,
"Guid": "274275db-9aa9-45d3-a00a-0f2eed662e7e",
"stTitle": "Extension of FSSAI deadline.",
"dtUpdatedDate": "2014-08-08T16:07:00"
}
]
}
Below is my Swift code:
import UIKit
/* This is struct i have created to parse jsonArray and JsonObject*/
struct JsonFromWeb:Codable {
let News: [jsonstruct]
}
struct jsonstruct:Codable {
let stTitle:String
let dtNewsDate:String
}
class ViewController:UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet var tableview: UITableView!
// below is the array for storing the response values
var arradata = [jsonstruct]()
override func viewDidLoad() {
super.viewDidLoad()
getdata() // funcction call to load the json api
}
func getdata() { // function getData to load the Api
let url = URL(string : "http://www.hrawi.com/HrawiService.svc")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
do {
if (error == nil) {
print(url!)
let news = try JSONDecoder().decode(JsonFromWeb.self, from: data!)
self.arradata = news.News
}
} catch {
print("Error In Json Data")
}
}.resume()
}
//Tableview to set the JSON Data in UITableView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arradata.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
//lblname to set the title from response
cell.lblname.text = "News Title \(arradata[indexPath.row].stTitle)"
cell.lblcapital.text = "news Date \(arradata[indexPath.row].dtNewsDate)"
return cell
}
}
Use these structs:
struct JSONFromWeb: Codable {
let news: [JsonStruct]
enum CodingKeys: String, CodingKey {
case news = "News"
}
}
struct JsonStruct: Codable {
let intID: Int
let guid, stTitle, dtUpdatedDate: String
enum CodingKeys: String, CodingKey {
case intID = "intId"
case guid = "Guid"
case stTitle, dtUpdatedDate
}
}
Note the use of coding keys to conform to the camel case naming convention in Swift. Also, the first letter in a struct name should be uppercased: JsonStruct. arradata should then be declared as [JsonStruct].
Now you can decode the json like so:
do {
let jsonFromWeb = try JSONDecoder().decode(JSONFromWeb.self, from: data)
//This web call is asynchronous, so you'll have to reload the table view
DispatchQueue.main.async {
self.arradata = jsonFromWeb.news
self.tableview.reloadData()
}
} catch {
print(error)
}
Change this to
struct jsonstruct:Codable {
let stTitle:String
let dtUpdatedDate:String
}
let news = try JSONDecoder().decode(JsonFromWeb.self, from:ata!)
DispatchQueue.main.async {
self.arradata = news.News
self.tableview.reloadData()
}
You better start struct names with capital , and vars with small , i left it as not to confuse you with your current code
I'm working with Swiftyjson in Swift 2.3. I've been able to parse json arrays into a UITableview with no problem until I got the following json response:
{
"CAR": [
{
"SID": "1",
"NAME": "BMW",
},
{
"SID": "2",
"NAME": "MERCEDES",
},
],
"BIKE": [
{
"SID": "3",
"NAME": "KAWASAKI",
},
{
"SID": "4",
"NAME": "HONDA",
},
]
}
QUESTION How do I parse "CAR" and "BIKE" into tableview sections and have their items under each section? I've managed to get the "keys" using:
// Other Code
let json = JSON(data)
for (key, subJson) in json {
self.array.append(key)
}
print(self.array)
["CAR", "BIKE"]
I wanted to know how to loop through each section and get their items properly. Any help would be great!
Since you haven't shown where you are getting your json data from, I have tested this by having your JSON above in a .json file. Also this doesn't use SwiftyJSON but you will be able to modify the syntax to get the same result.
class TableViewController: UITableViewController {
var tableData = Dictionary<String,Array<Dictionary<String,String>>>()
var sections = Array<String>()
override func viewDidLoad() {
super.viewDidLoad()
load(file: "document")
}
func load(file:String) {
guard let path = Bundle.main.path(forResource: file, ofType: "json") else { return }
guard let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else { return }
guard let json = try? JSONSerialization.jsonObject(with: data) else { return }
guard let dict = json as? Dictionary<String,Array<Dictionary<String,String>>> else { return }
self.tableData = dict
self.sections = dict.keys.sorted()
self.tableView.reloadData()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return self.sections.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let key = self.section[section]
return key
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let key = self.section[indexPath.section]
return self.tableData[key]?.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
// Configure the cell...
let key = self.section[indexPath.section]
let cellData = self.tableData[key]?[indexPath.row]
cell.textLabel?.text = cellData?["NAME"]
cell.detailTextLabel?.text = "SID: \(cellData?["SID"] ?? "Unknown")"
return cell
}
}
This is how it looks on an iPhone.
in my app i am first time using AlamofireObjectMapper.
So i am mapping api response data in one class and then i want to use that data.
So here is my code that how i map object
extension OrderListViewController
{
func get_order_list()
{
let url = "\(OrderURL)get_New_order_byPharmacy"
let param : [String : AnyObject] = [
"pharmacyId" : "131"
]
Alamofire.request(.GET, url, parameters: param, encoding: .URL).responseObject { (response:Response<OrderList, NSError>) in
let OrderList = response.result.value
print(OrderList!.Message)
}
}
}
and here is the class where i saving my data
class OrderList: Mappable {
var Message : String!
var Status : Int!
var result:[OrderResult]?
required init?(_ map: Map){
}
func mapping(map: Map) {
Message <- map["Message"]
Status <- map["Status"]
result <- map["Result"]
}
}
now in my OrderListViewController i want to use this data so how can i use this??
class OrderListViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var table_OrderList: UITableView!
override func viewDidLoad() {
slideMenuController()?.addLeftBarButtonWithImage(UIImage(named: "ic_menu_black_24dp")!)
slideMenuController()?.addRightBarButtonWithImage(UIImage(named: "ic_notifications_black_24dp")!)
get_order_list()
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : OrderList_Cell = tableView.dequeueReusableCellWithIdentifier("OrderList_Cell") as! OrderList_Cell
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
}
for example i want to print message value in my tableview cell label. so how can i get that value form OrderList?
Thanks slava its give me some solution. but my json response give me array. So how can i manage it? and i want to return in numberofrowinSetcion is count of array so how can i do this. please see my updated question.
here is my api response.
{
"Status": 1,
"Message": "records are available",
"Result": [
{
"id": 30162,
"status_id": 2,
"status_type": "New Order",
"created_date": "2016-05-11T10:45:00.6779848",
"created": "11 May 2016"
},
{
"id": 30170,
"status_id": 2,
"status_type": "New Order",
"created_date": "2016-05-12T07:01:00.6968385",
"created": "12 May 2016"
},
{
"id": 30171,
"status_id": 2,
"status_type": "New Order",
"created_date": "2016-05-12T09:12:53.5538349",
"created": "12 May 2016"
},
{
"id": 30172,
"status_id": 2,
"status_type": "New Order",
"created_date": "2016-05-12T09:46:09.4329398",
"created": "12 May 2016"
},
{
"id": 30173,
"status_id": 2,
"status_type": "New Order",
"created_date": "2016-05-12T11:26:58.3211678",
"created": "12 May 2016"
},
{
"id": 30178,
"status_id": 2,
"status_type": "New Order",
"created_date": "2016-05-16T07:34:19.9128517",
"created": "16 May 2016"
}
]
}
You need a local variable in your controller to store all the received information that will be used to fill the table. Something like that should do:
class OrderListViewController: ... {
private var orderList: OrderList? // <- the local variable needed
...
}
extension OrderListViewController {
func get_order_list() {
...
Alamofire
.request(...)
.responseObject { (response:Response<OrderList, NSError>) in
switch response.result {
case .Success(let value):
self.orderList = value // <- fill the local variable with the loaded data
self.tableView.reloadData()
case .Failure(let error):
// handle error
}
}
}
...
}
extension OrderListViewController: UITableViewDataSource {
...
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : OrderList_Cell = tableView.dequeueReusableCellWithIdentifier("OrderList_Cell") as! OrderList_Cell
// I assume 'OrderList_Cell' class has outlet for status type named 'statusTypeLabel' and OrderResult.statusType is of type String
if let orderList = orderList, orderResults = orderList.result {
cell.statusTypeLabel.text = orderResults[indexPath.row].statusType // <- use of the locally stored data
}
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let orderList = orderList, orderResults = orderList.result {
return orderResults.count
} else {
return 0
}
}
}
Note: the code should be correct in case you receive the single object in JSON from backend.
If backend sends the array of objects - you'll need to use array to store local data (private var listOfOrderLists: [OrderList]) and use Alamofire.request(...).responseArray(...) instead. But the idea about local variable is still the same.
typealias FailureHandler = (error: AnyObject) -> Void
typealias SuccessHandler = (result: AnyObject) -> Void
class WebServiceManager: NSObject {
class func getDataFromService(mehodName:String,success:(result:AnyObject)->(), apiError:(FailureHandler))
{
let url = "\(OrderURL)get_New_order_byPharmacy"
let param : [String : AnyObject] = [
"pharmacyId" : "131"
]
alamoFireManager!.request(.GET, url)
.responseJSON { response in
print(response.response!)
print(response.result)
CommonFunctions.sharedInstance.deactivateLoader()
switch response.result {
case .Success(let JSON):
print("Success with JSON: \(JSON)")
guard let _ = JSON as? NSMutableArray else {
apiError(error: "")
return
}
let listOfItem:NSMutableArray = NSMutableArray()
for (_, element) in adsArray.enumerate() {
let adsItem = Mapper<OrderList>().map(element)
listOfItem.addObject(adsItem!)
}
success(result:listOfItem)
case .Failure(let data):
print(data)
}
}
}
class OrderListViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var table_OrderList: UITableView!
var listOFOrder:NSMutableArray =[]
override func viewDidLoad() {
slideMenuController()?.addLeftBarButtonWithImage(UIImage(named: "ic_menu_black_24dp")!)
slideMenuController()?.addRightBarButtonWithImage(UIImage(named: "ic_notifications_black_24dp")!)
WebServiceManager.getDataFromService("", success: { (result) in
listOFOrder = result as NSMutableArray
self.recordTable?.reloadData()
}) { (error) in
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : OrderList_Cell = tableView.dequeueReusableCellWithIdentifier("OrderList_Cell") as! OrderList_Cell
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listOFOrder.count
}
}
situation:
I have a JSON response parsed via SwiftyJSON. And I'm populating table cells with the data. Everything is cool, but now I need to remove some dictionaries from my JSON, and it doesn't let me do that in an any way (loops or other conditions).
Example of received JSON:
{"post-comments" : [
{
"post" : "new",
"_id" : "1",
},
{
"post" : "new",
"_id" : "2",
},
{
"post" : "post with title",
"_id" : "23",
},
{
"post" : "new",
"_id" : "29",
},
{
"post" : "post with title",
"_id" : "90",
},
{
"post" : "post with title",
"_id" : "33",
}
]
}
I'm tryin to get rid of some dictionaries, lets say if "post" === "new" - I need to remove them from my JSON and continue populate my cells with left data.
Completely stuck.. Any ideas would be much appreciated.
here is the complete tableviewcontroller:
class TableViewContr: UITableViewController {
let Comments : String = "http://localhost:3000/api/comments/"
var json : JSON = JSON.null
override func viewDidLoad() {
super.viewDidLoad()
getPostComments(Comments)
}
func getPostComments(getcomments : String) {
Alamofire.request(.GET, getcomments).responseJSON {
response in
guard let data = response.result.value else {
return
}
self.json = JSON(data)
self.tableView.reloadData()
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch self.json["post-comments"].type {
case Type.Array:
return self.json["post-comments"].count
default:
return 1
}
}
func populateFields(cell: TableViewContrCell, index: Int) {
guard let comment = self.json["post-comments"][index]["post"].string else {
return
}
cell.commentContent!.text = comment
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewContrCell
populateFields(cell, index: indexPath.row)
return cell
}
}
This is an approach to parse and filter the JSON data before reloading the table view.
comments is the data source array containing the post-comments dictionaries
class TableViewContr: UITableViewController {
let commentURL : String = "http://localhost:3000/api/comments/"
var comments = [[String:String]]()
override func viewDidLoad() {
super.viewDidLoad()
getPostComments(commentURL)
}
func getPostComments(getcomments : String) {
Alamofire.request(.GET, getcomments).responseJSON {
response in
guard let data = response.result.value else { return }
let jsonData = JSON(data)
let postComments = jsonData["post-comments"].arrayObject as! [[String:String]]
self.comments = postComments.filter{$0["post"] != "new"}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comments.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewContrCell
let comment = comments[indexPath.row]
cell.commentContent!.text = comment["post"]!
return cell
}
}