I'm attempting to find a string inside a plist Dictionary but I'm not sure how. Can I get some help please?
The code contains two plists, one with the list of Clients and the second with the list or Products, we're populating the client's data in a cell from the ClientArray, but I need to also include the ProductName for that client from the ProductArray in the same Cell, the matching key is productID.
import UIKit
class TestViewController: UIViewController {
var ClientArray = [[String:Any]]()
var ProductArray = [[String:Any]]()
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
//path of plist file Array Client
let path1 = Bundle.main.path(forResource: "ClientList", ofType: "plist")
ClientArray = NSArray(contentsOfFile: path1!)! as! [Any] as! [[String : Any]]
//path of plist file Array Products
let path2 = Bundle.main.path(forResource: "ProductList", ofType: "plist")
ProductArray = NSArray(contentsOfFile: path2!)! as! [Any] as! [[String : Any]]
// Do any additional setup after loading the view, typically from a nib.
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as! TestTableViewCell
//fill out custom cell values
cell.testName.text = ClientArray[indexPath.row]["name"] as? String
cell.testNumber.text = ClientArray[indexPath.row]["number"] as? String
for product in ProductArray {
if let productName = product[ClientArray[indexPath.row]["productID"] as! String] {
cell.testProduct.text = productName["productName"] as? String
}
}
return cell
}
}
First of all don't use NSArray
and NSDictionary
in Swift. Use native types. This avoids weird cast dances like NSArray ... as! [Any] as! [[String : Any]]
.
Second of all there is a class PropertyListSerialization
to convert Property List
to collection types and vice versa.
Finally the proper type of both arrays is [[String:String]]
. The avoids more unnecessary type casting.
Please conform to the naming convention that variable names start with a lowercase letter.
var clientArray = [[String:String]]()
var productArray = [[String:String]]()
override func viewDidLoad() {
super.viewDidLoad()
//URL of plist file Array Client
let clientURL = Bundle.main.url(forResource: "ClientList", withExtension: "plist")!
let clientData = try! Data(contentsOf: clientURL)
clientArray = try! PropertyListSerialization.propertyList(from: clientData, format: nil) as! [[String:String]]
//URL of plist file Array Products
let productURL = Bundle.main.url(forResource: "ProductList", withExtension: "plist")!
let productData = try! Data(contentsOf: productURL)
productArray = try! PropertyListSerialization.propertyList(from: productData, format: nil) as! [[String:String]]
// Do any additional setup after loading the view, typically from a nib.
}
In cellForRow
filter the product name with the first
function.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as! TestTableViewCell
//fill out custom cell values
let client = clientArray[indexPath.row]
cell.testName.text = client["name"]
if let product = productArray.first{ $0["productID"]! == client["productID"]! } {
cell.testNumber.text = product["productName"]
}
return cell
}
A more efficient solution is to decode the Property List into structs with PropertyListDecoder
struct Client : Decodable {
let name, number, productID : String
}
struct Product : Decodable {
let productID, productName, productQty : String
}
...
var clients = [Client]()
var products = [Product]()
override func viewDidLoad() {
super.viewDidLoad()
//URL of plist file Array Client
let clientURL = Bundle.main.url(forResource: "ClientList", withExtension: "plist")!
let clientData = try! Data(contentsOf: clientURL)
clients = try! PropertyListDecoder().decode([Client].self, from: clientData)
//URL of plist file Array Products
let productURL = Bundle.main.url(forResource: "ProductList", withExtension: "plist")
let productData = try! Data(contentsOf: productURL)
products = try! PropertyListDecoder().decode([Product].self, from: productData)
}
...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath) as! TestTableViewCell
//fill out custom cell values
let client = clients[indexPath.row]
cell.testName.text = client.name
if let product = products.first{ $0.productID == client.productID } {
cell.testNumber.text = product.productName
}
return cell
}
Consider to use CoreData with relationships for the data model. It's still more efficient.