Represent result of parsing JSON in tableView Swift - ios

I start learning swift with Paul Hudson's "100 Days of Swift" and I need your advices.
I'm trying making app with country's info (capital, language, currencies etc.) and stuck with trying represent result of my JSON parsing in tableView.
This is my struct for parsing country's info from https://restcountries.com/v3.1/all
struct Country: Codable {
let name: Name
let cca2: String
let capital: [String]?
let population: Int
let currencies: [String: Currency]?
}
struct Name: Codable {
let common: String
let official: String
}
struct Currency: Codable {
let name: String?
let symbol: String?
}
I have problems with currencies. I don't understand how represent them properly in tableView. This is code of my ViewController:
import UIKit
class ViewController: UITableViewController {
var countries = [Country] ()
override func viewDidLoad() {
super.viewDidLoad()
let urlString = "https://restcountries.com/v3.1/all"
if let url = URL(string: urlString) {
if let data = try? Data(contentsOf: url) {
parse(json: data)
return
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
countries.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Country", for: indexPath)
let country = countries[indexPath.row]
cell.textLabel?.text = country.name.common
cell.imageView?.image = UIImage(named: country.cca2.lowercased())
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier: "Detail") as? DetailViewController {
vc.country = countries[indexPath.row]
present(vc, animated: true)
}
}
func parse(json: Data) {
let decoder = JSONDecoder()
do {
let jsonCountries = try decoder.decode([Country].self, from: json)
countries = jsonCountries
}
catch let error {
print(error)
}
}
}
And this is code of my DetailViewController:
import UIKit
class DetailViewController: UITableViewController {
var country: Country!
let flag = "Flag"
let general = "General"
let currency = "Currency"
var currencyName = ""
var currencySymbol = ""
lazy var sectionTitles = [flag, general, currency]
lazy var currencies = country.currencies?.values
override func viewDidLoad() {
super.viewDidLoad()
title = country.name.common
getCurrencyName()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return sectionTitles.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionTitles[section]
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch sectionTitles[section] {
case flag:
return 1
case general:
return 4
case currency:
// How make to return proper number's of rows??
return 2
default:
return 0
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch sectionTitles[indexPath.section] {
case flag:
let cell = tableView.dequeueReusableCell(withIdentifier: "Flag", for: indexPath)
if let cell = cell as? FlagCell {
cell.flagImageView.image = UIImage(named: country.cca2.lowercased())
}
return cell
case general:
let cell = tableView.dequeueReusableCell(withIdentifier: "Text", for: indexPath)
cell.textLabel?.numberOfLines = 0
switch indexPath.row {
case 0:
cell.textLabel?.text = "Common country name: \(country.name.common)"
case 1:
cell.textLabel?.text = "Official country name: \(country.name.official)"
case 2:
cell.textLabel?.text = "Capital: \(country.capital?[0] ?? "Unknown")"
case 3:
cell.textLabel?.text = "Population: \(country.population) people"
default:
return cell
}
return cell
case currency:
let cell = tableView.dequeueReusableCell(withIdentifier: "Text", for: indexPath)
cell.textLabel?.numberOfLines = 0
switch indexPath.row {
case 0:
// How to represent each currency of country?
cell.textLabel?.text = "Currency name: \(currencyName)"
case 1:
cell.textLabel?.text = "Currency symbol: \(currencySymbol)"
default:
return cell
}
return cell
default:
break
}
return UITableViewCell ()
}
func getCurrencyName () {
for currency in currencies! {
currencyName = currency.name ?? ""
currencySymbol = currency.symbol ?? ""
}
}
}
For now I understand how to represent one currency of each country, but how I can represent all currencies of each country in different rows?
Sorry for my English it's not my native language :)

I would suggest getting a sorted list of the currencies. E.g., for a given Country:
let currencies = country.currencies?.sorted { $0.0 < $1.0 }
To get the count:
let count = currencies?.count ?? 0
To get the details for a particular row, it would be:
if let (code, currency) = currencies?[indexPath.row] {
let currencyCode = code
let currencyName = currency.name
let currencySymbol = currency.symbol
}

You can access the number of currencies for each country with this, and use it in the numberOfRowsInSection method to return enough number of rows for currencies:
country.currencies.count
The rest is filling the cells in the cellForRowAt method by using the indexPath's section and row values. You should iterate over the currencies dictionary of the selected country, and display each key and value pair in the dictionary in a row.
You can do the iteration like so:
for (key, value) in dict {
// Use key and value here
}

Related

Trouble converting JSON Ints to Strings (Swift 5)

New to Swift and coding in general. Trying to put an array of JSON objects into a tableView. Having trouble converting my Ints to Strings in the tableView delegate method's detailTextView.text. Getting an error "Initializer 'init(_:)' requires that 'Int?' conform to 'LosslessStringConvertible.'" Try to use that, but it's a rabbit hole of errors from there. Been browsing SO most of the day but no luck.
class AllCountriesVC: UITableViewController {
struct CovidData: Codable {
let country: String
let cases: Int?
let todayCases: Int?
let deaths: Int?
let todayDeaths: Int?
let recovered: Int?
let active: Int?
let critical: Int?
let totalTests: Int?
}
var data = [CovidData]()
override func viewWillAppear(_ animated: Bool) {
load()
self.tableView.reloadData()
}
override func viewDidLoad() {
super.viewDidLoad()
}
func load() {
if let url = URL(string: "https://coronavirus-19-api.herokuapp.com/countries/") {
let jsonData = try! Data(contentsOf: url)
self.data = try! JSONDecoder().decode([CovidData].self, from: jsonData)
self.tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count ?? 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let countryData = data[indexPath.row]
cell.textLabel?.text = countryData.country
cell.detailTextLabel?.text = String(countryData.cases)
//this is where it fails with error "Initializer 'init(_:)' requires that 'Int?' conform to 'LosslessStringConvertible'"
return cell
}
}
From looking at the data, the only property that has null data is recovered, so you change the rest of the properties to non-optionals. This will make things a lot easier for you.
I would also recommend that you use do/try/catch rather than try!.
class AllCountriesVC: UITableViewController {
struct CovidData: Codable {
let country: String
let cases: Int
let todayCases: Int
let deaths: Int
let todayDeaths: Int
let recovered: Int?
let active: Int
let critical: Int
let totalTests: Int
}
var data = [CovidData]()
override func viewWillAppear(_ animated: Bool) {
load()
}
func load() {
if let url = URL(string: "https://coronavirus-19-api.herokuapp.com/countries/") {
do {
let jsonData = try Data(contentsOf: url)
self.data = try JSONDecoder().decode([CovidData].self, from: jsonData)
self.tableView.reloadData()
}
catch {
print(error)
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count ?? 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let countryData = data[indexPath.row]
cell.textLabel?.text = countryData.country
cell.detailTextLabel?.text = String(countryData.cases)
return cell
}
}
If you did want to use an optional, say recovered then you can use the nil coalescing operator - ??
String(countryData.recovered ?? 0)

How to group tableview cells based on field in JSON array

Essentially I have am using JSON data to create an array and form a tableview.
I would like the table cells to be grouped by one of the fields from the JSON array.
This is what the JSON data looks like:
[{"customer":"Customer1","number":"122039120},{"customer":"Customer2","number":"213121423"}]
Each number needs to be grouped by each customer.
How can this be done?
This is how I've implemented the JSON data using the table:
CustomerViewController.swift
import UIKit
class CustomerViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, FeedCustomerProtocol {
var feedItems: NSArray = NSArray()
var selectedStock : StockCustomer = StockCustomer()
let tableView = UITableView()
#IBOutlet weak var customerItemsTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//set delegates and initialize FeedModel
self.tableView.allowsMultipleSelection = true
self.tableView.allowsMultipleSelectionDuringEditing = true
self.customerItemsTableView.delegate = self
self.customerItemsTableView.dataSource = self
let feedCustomer = FeedCustomer()
feedCustomer.delegate = self
feedCustomer.downloadItems()
}
}
func itemsDownloaded(items: NSArray) {
feedItems = items
self.customerItemsTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of feed items
print("item feed loaded")
return feedItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Retrieve cell
let cell = tableView.dequeueReusableCell(withIdentifier: "customerGoods", for: indexPath) as? CheckableTableViewCell
let cellIdentifier: String = "customerGoods"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
// Get the stock to be shown
let item: StockCustomer = feedItems[indexPath.row] as! StockCustomer
// Configure our cell title made up of name and price
let titleStr = [item.number].compactMap { $0 }.joined(separator: " - ")
return myCell
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
let cellIdentifier: String = "customerGoods"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
myCell.textLabel?.textAlignment = .left
}
}
FeedCustomer.swift:
import Foundation
protocol FeedCustomerProtocol: class {
func itemsDownloaded(items: NSArray)
}
class FeedCustomer: NSObject, URLSessionDataDelegate {
weak var delegate: FeedCustomerProtocol!
let urlPath = "https://www.example.com/example/test.php"
func downloadItems() {
let url: URL = URL(string: urlPath)!
let defaultSession = Foundation.URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Error")
}else {
print("stocks downloaded")
self.parseJSON(data!)
}
}
task.resume()
}
func parseJSON(_ data:Data) {
var jsonResult = NSArray()
do{
jsonResult = try JSONSerialization.jsonObject(with: data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
} catch let error as NSError {
print(error)
}
var jsonElement = NSDictionary()
let stocks = NSMutableArray()
for i in 0 ..< jsonResult.count
{
jsonElement = jsonResult[i] as! NSDictionary
let stock = StockCustomer()
//the following insures none of the JsonElement values are nil through optional binding
if let number = jsonElement[“number”] as? String,
let customer = jsonElement["customer"] as? String,
{
stock.customer = customer
stock.number = number
}
stocks.add(stock)
}
DispatchQueue.main.async(execute: { () -> Void in
self.delegate.itemsDownloaded(items: stocks)
})
}
}
StockCustomer.swift:
import UIKit
class StockCustomer: NSObject {
//properties of a stock
var customer: String?
var number: String?
//empty constructor
override init()
{
}
//construct with #name and #price parameters
init(customer: String) {
self.customer = customer
}
override var description: String {
return "Number: \(String(describing: number)), customer: \(String(describing: customer))"
}
}
You can achieve this by making an array of array. So something like this
[[{"customer": "customer1", "number": "123"}, {"customer": "customer1", "number": "456"}], [{"customer": "customer2", "number": "678"}, {"customer": "customer2", "number": "890"}]]
This is not the only data structure you can use to group. Another possibility is:
{"customer1": [{"customer": "customer1", "number": "123"}, {"customer": "customer1", "number": "456"}], "customer2": [{"customer": "customer2", "number": "678"}, {"customer": "customer2", "number": "890"}]}
Then you can use UITableView sections to group by customers. Section count would be the number of inside arrays and each section would contain as many rows as there are numbers in that inside array.
You can group a sequence based on a particular key using one of the Dictionary initializer,
init(grouping:by:)
The above method init will group the given sequence based on the key you'll provide in its closure.
Also, for parsing such kind of JSON, you can easily use Codable instead of manually doing all the work.
So, for that first make StockCustomer conform to Codable protocol.
class StockCustomer: Codable {
var customer: String?
var number: String?
}
Next you can parse the array like:
func parseJSON(data: Data) {
do {
let items = try JSONDecoder().decode([StockCustomer].self, from: data)
//Grouping the data based on customer
let groupedDict = Dictionary(grouping: items) { $0.customer } //groupedDict is of type - [String? : [StockCustomer]]
self.feedItems = Array(groupedDict.values)
} catch {
print(error.localizedDescription)
}
}
Read about init(grouping:by:) in detail here: https://developer.apple.com/documentation/swift/dictionary/3127163-init
Make the feedItems object in CustomerViewController of type [[StockCustomer]]
Now, you can implement UITableViewDataSource methods as:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.feedItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customerGoods", for: indexPath) as! CheckableTableViewCell
let items = self.feedItems[indexPath.row]
cell.textLabel?.text = items.compactMap({$0.number}).joined(separator: " - ")
//Configure the cell as per your requirement
return cell
}
Try implementing the approach with all the bits and pieces and let me know in case you face any issues.

Show data in table view from mysql using alamofire and swiftyjson

I have a php script on my server which is just a basic sql SELECT statement which gets some data from a mysql database and it returns a number of rows.
I have used alamofire and swiftyjson to print the data out to console but I want to show it in a table view.
Due to the call not being in the same scope as the tableView code ( I think that is the reason I am getting an error which says 'Use of unresolved idenfifier')
I am not sure how to make it global but I guess I need to create a global array variable but not sure if it should just be empty?
global:
let serviceURL = "http://example.com/service.php"
I put it in a function like this:
func getUsers() {
Alamofire.request(serviceURL, method: .get).validate().responseJSON { (response) in
if response.result.isSuccess {
let userJSON : JSON = JSON(response.result.value!)
for (index,subJson):(String, JSON) in userJSON {
let firstName = subJson["first_name"].string
let lastName = subJson["last_name"].string
print(firstName)
}
} else {
print("Could not get results")
}
}
}
I need to somehow count the rows returned
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return firstName.count
}
And then actually display in the cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath)
cell.textLabel?.text = names[indexPath.row]
return cell
}
UPDATE
import UIKit
import Alamofire
import SwiftyJSON
struct User {
var firstName: String
var lastName: String
private enum CodingKeys: String, CodingKey {
case firstName = "first_name"
case lastName = "last_name"
}
}
class UserTableViewController: UITableViewController {
var users = [User]()
let serviceURL = "http://example.com/service.php"
override func viewDidLoad() {
super.viewDidLoad()
getUsers()
}
func getUsers() {
Alamofire.request(serviceURL, method: .get).validate().responseJSON { (response) in
if response.result.isSuccess {
let userJSON : JSON = JSON(response.result.value!)
for (index,subJson):(String, JSON) in userJSON {
let firstName = subJson["first_name"].string
let lastName = subJson["last_name"].string
let user = User(firstName: firstName!, lastName: lastName!)
self.users.append(user)
}
} else {
print("Could not get results")
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath)
let user = users[indexPath.row]
cell.textLabel?.text = "\(user.firstName) \(user.lastName)"
return cell
}
}
First of all you need a structure to hold your data
struct User {
var firstName: String
var lastName: String
}
Then you need an array to hold the users from the json message, declare it as an attribute in your view controller
var users = [User]()
And then make use of it in your code
func getUsers() {
Alamofire.request(serviceURL, method: .get).validate().responseJSON { (response) in
if response.result.isSuccess {
let userJSON : JSON = JSON(response.result.value!)
for (index,subJson):(String, JSON) in userJSON {
let firstName = subJson["first_name"].string
let lastName = subJson["last_name"].string
let user = User(firstName: firstName, lastName: lastName)
users.append(user)
}
} else {
print("Could not get results")
}
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath)
let user = users[indexPath.row]
cell.textLabel?.text = "\(user.firstName) \(user.lastName)"
return cell
}

Unable to download firebase database to my app

I am new to programming in swift. I am trying to make an app which downloads student data from firebase database. I am unable to get the app running. This is my JSON file:
{"classA":[
{
"name": "Student1",
"USN": "1DS16CS095"
},
{
"name": "student2",
"USN": "1DS16CS065"
},
{
"name":"student3",
"USN":"1DS16CS047"
}
]
}
This is my code to download the above JSON file and put it in tableView. Modelstudent is my class where I have my variables name and USN stored. and marksstudentlistTableViewCell is the class I am using to manipulate the labels of my prototype cell.
import UIKit
import Firebase
import FirebaseDatabase
struct StudentData {
let StudentName : String
let StudentUSN : String
}
class marksstudentlist: UIViewController, UITableViewDelegate, UITableViewDataSource{
var FetchedStudentIDs = [StudentData]()
#IBOutlet weak var tableView: UITableView!
var ref: DatabaseReference!
var _selectedsub: Int!
var selectedsub: Int {
get {
return _selectedsub
}set {
_selectedsub = newValue
}
}
override func viewDidLoad() {
tableView.delegate = self
tableView.dataSource = self
if(classselected==0){
ref = Database.database().reference().child("classA")
ref.observe(DataEventType.value, with: { (snapshot) in
if snapshot.childrenCount>0{
for students in snapshot.children.allObjects as! [DataSnapshot]{
let studentObject = students.value as? [String: String]
let studentname = studentObject?["name"]
let studentUSN = studentObject?["USN"]
let student = Modelstudent(name: studentname , USN: studentUSN)
self.FetchedStudentIDs.insert(StudentData(StudentName :(studentname as? String!)! , StudentUSN : (studentUSN as? String!)! ) , at: 0)
}
self.tableView.reloadData()
}
})
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return FetchedStudentIDs.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "marksstudentlistcell", for: indexPath) as! marksstudentlistTableViewCell
cell.namelbl.text = FetchedStudentIDs[indexPath.row].StudentName// Student name comes from Firebase
cell.USNlbl.text = FetchedStudentIDs[indexPath.row].StudentUSN
return cell
}
#IBAction func backbtn(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}
Using Swift Struct is the best way to get your firebase data inside the tableView,
Let's Get started
on your TableView swift file, above the class and stuff paste this
Struct StudentData {
let StudentObject : String // If it's
let StudentName : String // It returns a string right?
let StudentUSN : String
// do the others.
}
okay so then create a var just down below the class call it
var FetchedStudentIDs = [StudentData]()
then you got the reading method from firebase
ref = Database.database().reference().child("classA")
ref.observe(DataEventType.value, with: { (snapshot) in
if snapshot.childrenCount>0{
self.studentslist.removeAll()
for students in snapshot.children.allObjects as! [DataSnapshot]{
let studentObject = students.value as? [String: AnyObject]
let studentname = studentObject?["name"]
let studentUSN = studentObject?["USN"]
let student = Modelstudent(name: studentname as! String?, USN: studentUSN as! String?) //storing in Modelstudent class
self.
FetchedStudentIDs.insert(StudentData(studentname:StudentName as! String , studentUSN : StudentUSN as! String ) , at: 0) // Student name comes from the struct Above, do the others as this
}
self.tableView.reloadData() // make sure you call this
}
})
return your tableView
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return FetchedStudentIDs.count
}
your CellForRowAtIndexPath
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! TableViewCell
cell.exampleLabel.text = FetchedStudentIDs[Indexpath.row].StudentName// Student name comes from Firebase
return cell
}
Hope this Helps

Displaying an array of data from plist in tableview

I'm working on displaying data from a plist in multiple "drill down" tableViews. The displayed data is only going to be read-only and I don't want it to necessarily be based on web data, and there will only be a maximum of about 100 data points so I'm fairly happy with plist instead of JSON.
Anyway, the question... I've got an array of dictionary items that I'm managing to display fairly well. I started with the GitHub relating to the following question on stack overflow (I modified it a little bit but thats not important).
Load data from a plist to two TableViews
https://github.com/DonMag/SWPListData
What I need help with is displaying an array of items ("friends" in this example) under each person. Code below will hopefully explain.
I've created an empty array in the model
struct EmployeeDetails {
let functionary: String
let imageFace: String
let phone: String
//This is the new array I've added and am having trouble displaying
let friends: [String]
init(dictionary: [String: Any]) {
self.functionary = (dictionary["Functionary"] as? String) ?? ""
self.imageFace = (dictionary["ImageFace"] as? String) ?? ""
self.phone = (dictionary["Phone"] as? String) ?? ""
//I've initialised it here.
self.friends = (dictionary["Friends"] as? [String]) ?? [""]
Now in the viewController displaying the data. I don't have any problems at all displaying the correct data for the "functionary", "imageFace" and "phone" - but I just can't seem to display "friends" as an array in its own section. I'm pretty sure the main problem is in numberOfRows and cellForRow:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
if let theEmployee = newPage {
return theEmployee.details.count
}
return 0
}
else if section == 1 {
return 1
}
else if section == 2 {
if let theEmployee = newPage {
return theEmployee.details.count
}
return 0
}
else {
return 0
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) // as! TableViewCell2
if indexPath.section == 0 {
cell.textLabel?.text = "A"
if let theEmployee = newPage {
cell.textLabel?.text = theEmployee.details[indexPath.row].functionary
cell.detailTextLabel?.text = theEmployee.details[indexPath.row].phone + " (" + theEmployee.details[indexPath.row].imageFace + ")"
}
}
else if indexPath.section == 1 {
cell.textLabel?.text = "Test"
}
else if indexPath.section == 2 {
cell.textLabel?.text = ????
}
return cell
}
I thought it would work writing the following in numberOfRows:
else if section == 2 {
if let theEmployee = newPage {
return theEmployee.details.friends.count
}
return 0
}
But I get the error:
value of type '[EmployeeDetails]' has no member 'friends'.
What do I need to do to get that array?
Note: The array is not empty.
Any suggestions/help would be much appreciated!
Problem is that you are accessing the friends property on details whereas it is a property on the structs stored inside details so you would have to access it through indexing something like this
theEmployee.details[yourIndex].friends.count
Update:
//First you need to make changes inside the .plist file, please go there and add Friends Array inside just like Details
Now this will require you to change your Employee struct code
struct Employee {
let position: String
let name: String
let details: [EmployeeDetails]
let friends: [String]
init(dictionary: [String: Any]) {
self.position = (dictionary["Position"] as? String) ?? ""
self.name = (dictionary["Name"] as? String) ?? ""
let t = (dictionary["Details"] as? [Any]) ?? []
self.details = t.map({EmployeeDetails(dictionary: $0 as! [String : Any])})
self.friends = (dictionary["Friends"] as? [String]) ?? []
}
}
Next step would be to add this in the table view as follows
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let theEmployee = newPage {
if section == 0 {
return theEmployee.details.count
}else if section == 1 {
return theEmployee.friends.count
}
}
return 0
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Subordinates"
}else if section == 1 {
return "Friends"
}
return ""
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) // as! TableViewCell2
cell.textLabel?.text = "A"
if let theEmployee = newPage {
if indexPath.section == 0 {
cell.textLabel?.text = theEmployee.details[indexPath.row].functionary
cell.detailTextLabel?.text = theEmployee.details[indexPath.row].phone + " (" + theEmployee.details[indexPath.row].imageFace + ")"
}else if indexPath.section == 1 {
cell.textLabel?.text = theEmployee.friends[indexPath.row]
}
}
return cell
}
}

Resources