-1

It's not a duplicate question!! I've searched for many similar questions, but I can't find someone declaring/calling the data model as a class like me.

I want to pass my store's information from Table View Controller to Detail View Controller. I have trouble declaring the right type of variable store to receive the passed data in my Detail View Controller.

My Store Model:

class StoreModel{
    var name: String?
    var desc: String?
    var url: String?
    var rate: Double

    init(name: String?, desc: String?, url: String?, rate: Double){
        self.name = name
        self.desc = desc
        self.url = url
        self.rate = rate
    }
}

In my Table View Controller I declared store to save the data from Firebase:

class TableViewController: UITableViewController, UISearchResultsUpdating {
    var storeList = [StoreModel]()

    override func viewDidLoad() {
        //Hide some codes that initialize Firebase connection ...
        refStores.observe(DataEventType.value, with: {(snapshot) in
            if snapshot.childrenCount > 0{
                for stores in snapshot.children.allObjects as! [DataSnapshot]{
                    let storeObject = stores.value as? [String: AnyObject]
                    let storeName = storeObject?["storeName"]
                    let storeDesc = storeObject?["storeDesc"]
                    let storeUrl = storeObject?["storeUrl"]
                    let storeRate = storeObject?["storeRate"]

                    let store = StoreModel(name: storeName as! String?,
                        desc: storeDesc as! String?,url: storeUrl as! String?, 
                        rate: storeRate as! Double)
                    self.storeList.append(store)
                }
                self.tblSearch.reloadData()
    }})}

Below's my attempt:

In my Detail View Controller, I declare storeList to receive the passed data:

var storeList = [StoreModel]()

I create a segue (with identifier showDetailView) between my Table View Controller & Detail View Controller.

override func tableView(_ tableView: UITableView, 
    didSelectRowAt indexPath: IndexPath) {
        let selectedStore = storeList[indexPath.row]
        let destinationVC = DetailViewController()
        destinationVC.storeList = selectedStore
        destinationVC.performSegue(withIdentifier: "showDetailView", sender: self)
}  }

I got the error message Cannot assign value of type 'StoreModel' to type '[StoreModel]', at the line destinationVC.storeList = selectedStore, so I think I have problem declaring the right type of variable in my Detail View Controller.

Thanks for help!

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Vanessa Leung
  • 770
  • 1
  • 10
  • 22
  • At `Detail View Controller` Setup `var storeList = StoreModel()` not `Array` – biloshkurskyi.ss Mar 21 '19 at 16:06
  • @biloshkurskyi.ss Hi! This way shows error: `Missing argument for parameter 'name' in call`. – Vanessa Leung Mar 21 '19 at 16:09
  • The most significant issue is `let destinationVC = DetailViewController()`. This is **not** the expected controller instance. The error is pretty clear: `selectedStore` is a **single** object and `storeList` expects **multiple** objects. – vadian Mar 21 '19 at 16:16
  • 3
    It certainly is a duplicate. Passing what the property at the far end expects is trivial and up to you. And now in comments your question has devolved into other stuff about Swift language basics, also trivial and also well covered here already. – matt Mar 21 '19 at 16:54
  • @ayaio Hi, I can't find the "answer your question" button here, guess it's because my question's marked duplicate. – Vanessa Leung Mar 25 '19 at 05:12

2 Answers2

0

As the error message describes Cannot assign value of type 'StoreModel' to type '[StoreModel]'. You are trying to assign a single instance of the model to an array in DetailViewController. Either declare

var storeList = StoreModel()

in DetailViewController. Or pass the value as

destinationVC.storeList = [selectedStore]

Also for creating an instance like

var storeList = StoreModel()

provide a no argument initializer.

class StoreModel() {
    var name: String?
    var desc: String?
    var url: String?
    var rate: Double

    init(name: String?, desc: String?, url: String?, rate: Double){
        self.name = name
        self.desc = desc
        self.url = url
        self.rate = rate
    }
    init() {
    }
}
Diamond Mohanty
  • 151
  • 1
  • 10
  • Hi! I've tried both of your ways. Both popped up error : `Missing argument for parameter 'name' in call` – Vanessa Leung Mar 21 '19 at 16:13
  • Please highlight the line number where the error is popped up – Diamond Mohanty Mar 21 '19 at 16:17
  • It's the line `var storeList = StoreModel()` – Vanessa Leung Mar 21 '19 at 16:18
  • Since you have provided a parameterized initializer for the class you can not instantiate without calling the provided initializer. If you want to initialize like var storeList = StoreModel(). Add a no argument initializer to the class like init() {}. – Diamond Mohanty Mar 21 '19 at 16:20
  • Hi! I'm not sure I understood your answer correctly. But I tried to add `init(){}` to my `StoreModel` class, it showed the error `Return from initializer without initializing all stored properties`. – Vanessa Leung Mar 21 '19 at 16:26
  • Since rate is not optional you need to provide a default value to it in the initializer. Or mark rate as an optional. Also if rate is made optional you need to change argument type to optional in the parameterized initializer. – Diamond Mohanty Mar 21 '19 at 16:28
0

You are passing only one Store data. So you need to change in Detail View Controller from this

var storeList = [StoreModel]()

to

var storeList:StoreModel!

And this is because here let selectedStore = storeList[indexPath.row] you are selecting just one selectedStore.

dieroste
  • 394
  • 1
  • 3
  • 15
  • Hi! I've tried your method, the error `Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver () has no segue with identifier 'showDetailView''` popped up. But I do set the identifier `showDetailView` to the segue. – Vanessa Leung Mar 21 '19 at 16:22
  • @VanessaLeung Of course it crashes because it's not the controller in the storyboard. You have to override `prepare(for segue`. Study the duplicate. – vadian Mar 21 '19 at 16:24