AJ152
AJ152

Reputation: 685

Find a string inside a plist Dictionary

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.

enter image description here plist ClientArray

enter image description here plist ProductArray

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
    }
}

Upvotes: 0

Views: 530

Answers (2)

vadian
vadian

Reputation: 285200

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.

Upvotes: 2

Mikael
Mikael

Reputation: 2395

First, I recommend using the proper data type here. A plist can be a dictionary

For example:

if let path = Bundle.main.path(forResource: "ClientList", ofType: "plist"), let clientDict = NSDictionary(contentsOfFile: path) as? [String: AnyObject] {
}

Then you will have 2 dictionaries and you need to just access the productID of each item of the biggest file (one loop) and iterate on the items of the smallest file (n loops) to just find the same productID and match the data.

let clients = ["item0": ["productId": "10002"], "item1": ["productId": "10005"]]
let products = ["item0": ["productId": "10002"], "item1": ["productId": "10005"], "item2": ["productId": "10004"]]

let specialKey = "productId"

for product in products {
    for client in clients {
        if client.value[specialKey] == product.value[specialKey] {
            print("Product found!")
            break
        }
    }
}

Upvotes: 1

Related Questions