2

I am new to swift and what I am trying to do is return the specified columns in my table to display in a separate viewcontroller. I have defined a function using SQLite.swift which returns them in an array, just like I want them to be. (It works when called in the same viewcontroller)

func returncolumns() -> Array<String> {
    print("RETURNING")
    var namearray = [String]()
    do {
        for wardrobe in try wardrobedb.prepare(wardrobe.select(name)) {
            namearray.append(wardrobe[name])
        }
    } catch {
        print("This no worko \(error)")
    }
    return namearray
}

But when I call the function from another viewcontroller, I get a fatal error due to it trying to unwrap a nil value.

var clothes = ViewController().returncolumns()

What I gather is that since I am calling the function from the viewcontroller without the table, it is not able to get the information that it needs.

Here is the database in the first viewcontroller

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

var wardrobedb: Connection!

let wardrobe = Table("wardrobe")

let id = Expression<Int64>("id")
let name = Expression<String>("name")
let type = Expression<String>("type")
let color = Expression<String>("color")
let style = Expression<String>("style")
let weight = Expression<String>("weight")
let pattern = Expression<String>("pattern")

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    do {
        let documentDirectory = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        let fileUrl = documentDirectory.appendingPathComponent("wardrobe").appendingPathExtension("sqlite3")
        let wardrobedb = try Connection(fileUrl.path)
     //   let wardrobedb = try remove(fileUrl.path)
        self.wardrobedb = wardrobedb
    } catch {
        print(error)
    }
}

So should I try to combine the view controllers so that its all accessible? or move the wardrobe instantiation to another class? or is there a nice simple addition I can make to the function call which will allow for the table to be accessed.

Thank you!

Second ViewController:

import UIKit

class WardrobeTableViewController: UITableViewController {

var clothes = [String]()

// MARK: - Table view data source

override func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    return clothes.count
}

override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return "Section \(section)"
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath)

    let clothesname = clothes[indexPath.row]
    cell.textLabel?.text = clothes[indexPath.row]
    cell.detailTextLabel?.text = "Very cool!"
//    cell.imageView?.image = UIImage(named: clothesname)

    return cell
}
}

Here is first viewcontroller calls

func returncolumns() -> Array<String> {
    print("RETURNING")
    var namearray = [String]()
    do {
        for wardrobe in try wardrobedb.prepare(wardrobe.select(name)) {
            namearray.append(wardrobe[name])
        }
    } catch {
        print("This no worko \(error)")
    }
    return namearray
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "wardrobemove" {
      //  if let destinationVC = segue.destination as? WardrobeTableViewController {
            WardrobeTableViewController().clothes = returncolumns()
      ///  }
    }
}

So here I am identifying "wardrobemove" as the segue which moves into a navigation controller. I commented out the if statement because in this instance the destination viewcontroller is the navigation controller not the WardrobeTableViewController where the clothes array is being stored. When I run the debugger, I see it passing the information and the clothes array being assigned. but it still disappears before that.

Between the Navigation controller and the WardrobeTableViewController there is a Table view controller which has a few cells and when the first one is selected, it opens the WardrobeTableViewController.

This is a bit of a mess, I have followed two guides and I think the second one bringing in the navigation controller has messed things up a bit.

Adam7397
  • 57
  • 1
  • 7

1 Answers1

2

EDIT 2: you were not setting the clothes property of the instance of the class the segue is performed (but you were setting a new instance). Change like this:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    //check if the performed segue has "wardrobemove" id
    if segue.identifier == "wardrobemove" {
        //check if the destination is kind of WardrobeTableViewController
        if let destinationVC = segue.destination as? WardrobeTableViewController {
            //if it is so, then set its property clothes
            destinationVC.clothes = returncolumns()
      }
   }
}

EDIT

In your second vc, you want to reload your tableView every time you set the array of clothes:

var clothes = [String]() {
    didSet {
        self.tableView.reloadData()
    }
}

Old answer

var clothes = ViewController().returncolumns()

You have everything in your FirstVC and you want to set clothes in the SecondVC based on the value returned by the method returncolumns()

If it is so, you might want to perform a segue between FirstVC and SecondVC, and implement prepareForSegue to set clothes. Something like:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "segueIdentifier" {
        if let destinationVC = segue.destination as? SecondViewController {
            destinationVC.clothes = returncolumns()
        }
    }
}
mrcfal
  • 424
  • 3
  • 9
  • Hi, so I am close on this I think. I see in the debugger that it is assigning the correct values to the clothes array in the second view controller. The problem is that once I leave the first controller and go to the second, the array is now empty. I don't know why it empties – Adam7397 Jul 17 '18 at 00:44
  • I added it. It is pretty simple. I was reading it could have something to do with the navigation controller causing previous values to de-allocate? But am not too sure on that – Adam7397 Jul 17 '18 at 11:39
  • see my edit, if everything was setting the right way, the only thing you missed is to reload your table once you set the array – mrcfal Jul 17 '18 at 11:49
  • The second setting of the clothes var is showing an invalid redeclaration. If I comment out that line, I am still seeing an empty array once the second view controller is reached – Adam7397 Jul 17 '18 at 14:13
  • Yes it was part of the old answer. If you share the code about how you perform the segue and prepare, maybe we can figure it out – mrcfal Jul 17 '18 at 14:35
  • I added what I think will help. I appreciate the help big time – Adam7397 Jul 17 '18 at 15:14
  • see my edit, when you were initializing a new view controller object instead of using the segue.destination view controller – mrcfal Jul 17 '18 at 15:37
  • Gotcha, I think I understand how the segue works now. So I think my issue is that I am not going to the WardrobeTableViewController directly from the ViewController. So when the segue gets to that line, it checks the if statement, and then moves past it. The segue "wardrobemove" is moving to a navigation controller. And there is another segue at the point where WardrobeTableViewController is loaded, but its coming from a table view and not the initial viewcontroller where the segue and data is... – Adam7397 Jul 17 '18 at 15:46
  • I added some comments in my answer. Basically the flow is: firstVC perform a segue to secondVC, in prepareForSegue you want to check if the id matches that segue (you could have more than one segues) and you want to check if the destination is kind of secondVC. If it is so, then you want to set some property of your destinationVC. Let me know if my answer helped you! – mrcfal Jul 17 '18 at 15:53
  • Hey so final update. I cut out the middle navigation controller since that was preventing the data be passed efficiently. thank you for showing (and explaining!) the prepare for segue function. I appreciate it so much! – Adam7397 Jul 19 '18 at 01:35