3

I'm a beginner, clearly out of my league and I haven't been able to find an answer online.

I have a UITableViewController with a UITableViewshowing custom objects stored in one array. I don't show all the object of the array in one single section of said TableView: the TableView has multiple sections, each containing a filtered portion of my objects array (I filter the custom objects array checking that the object category property is equal to a category that I specified in a categories array).

This filtering and showing the single array in different sections is working fine (I understand that maybe it's not elegant, as I said I'm a beginner in coding and I absolutely needed to work with one single array, without creating other arrays corresponding to the filtered results), but to better understand my issue I think it's better that I show what I did, so here's the TableView part of my code:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return myCategoriesArray.count
    }

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        for (var i = 0; i <= section; i++){
            if section == i {
                for eachCategory in myCategoriesArray {
                    return myObjectsArray!.filter() { $0.objectCategoryProperty == myCategoriesArray[i] }.count
                }
            }
        }
    // ...
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {   
        var cell = tableView.dequeueReusableCellWithIdentifier("objectCell", forIndexPath: indexPath) as UITableViewCell
        for (var i = 0; i <= indexPath.section; i++){
            if indexPath.section == i {
                for eachCategory in myCategoriesArray {
                    cell.textLabel?.text = myObjectsArray!.filter() { $0.objectCategoryProperty == myCategoriesArray[i] }[indexPath.row].nameProperty
                    return cell
                }
            }
        }
    // ...
}

This works in the sense that I have the UITableViewController showing all my objects, but filtered in separated sections by category.

My issue is with the segue when I select a cell and show a detail view.

Here's my prepareForSegue method:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        var nextVC = segue.destinationViewController as MyNextViewController
        if let indexPath = tableView.indexPathForSelectedRow() {
            let selected = myObjectsArray![indexPath.row]
            nextVC.passedObject = selected
        }
    }
}

I'm sure that many of you already see my issue: the object that I pass to the next ViewController is selected in the custom objects array using as index [indexPath.row], but indexPath.row starts at 0 for each section, so when I select an object its index in the TableView is not equal to the index in the custom objects array, meaning that I pass the wrong object.

Now, I'm stuck because I don't see a way to pass the right (meaning, selected) object to the next View Controller while preserving the fact that I'm working with only a single array.

I was toying with the idea of adding an objectIDString property to every object and a single var currentlySelectedObjectIDString that is set every time a cell is selected and try to pass to the next View Controller the object with the objectIDString property matching the currentlySelectedObjectIDString, but it looks like a bad idea to my inexperienced eyes and I'm actually not sure how I could accomplish that even if I wanted to (maybe implementing didSelectRowAtIndexPath:, but I have not been able to make it work).

Any help would be really appreciated, I've been stuck on this for so long I begin to question a) my sanity b)every decision I made so far in the project (meaning, the single array for all objects that is filtered in sections), but I'm already so invested in it that I really would like not to have to start over.

Thank you,

Cesare

P.S. I hope my question is clear, english isn't my main language... sorry for any mistake!

cdf1982
  • 764
  • 1
  • 18
  • 34

2 Answers2

1

I suggest you, to use a NSFetchedResultsController. This class have a property sectionNameKeyPath. In this property you could set your category and you won't need more iterate with a repetition in each numberOfSection and numberOfRows.

like this:

    let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: moc, sectionNameKeyPath: "event.startDate", cacheName: nil)

In my case i need filter data by event.startDate.

I don't know if you are using core data, but if you are using, this is the better way to do this.

I'll expose them for you! In the first moment NSFetchedResultsController like complicated, but its very very useful. Don't be afraid.

I don't know exactly your model and data. In this case i'll show you my owner sample.

Please see my question in the following link: Sectioning TableView and rows with Core Data Swift

In this link, see my question, and in the bottom i'll explain the complete solution with the others answer.

If this is not clear for you, please, talk with me :.)

Community
  • 1
  • 1
Weles
  • 1,275
  • 13
  • 17
  • Thank you very much for taking the time to answer & help me! Early in my project I decided not to use Core Data because I thought it was too complex, but I'm beginning to realize that I would have probably been better off if I spent a few days learning it: I've spent all day trying to fix this issue (I was offline and didn't see your answer earlier) and I think I've put together a pile of workarounds that could work (if so I'll post them), but I'm afraid it's easily breakable. I'm bookmarking your answer and "Sectioning TableView and rows w/Core Data Swift" & begin looking into it, thx again! – cdf1982 Feb 22 '15 at 18:49
  • I am happy for sharing something with you! i am learning swift and English, smiles. When i started with swift i avoided core data, but when i came in this point, like you, category or section, i needed use it. This article, help me so much. i'll share with you: http://rshankar.com/coredata-tutoiral-in-swift-using-nsfetchedresultcontroller/ – Weles Feb 22 '15 at 19:05
  • Thank you again for your kindness and for sharing this article. I knew from the beginning that the app I am developing, which could have a decent amount of data that will be presented sorted in different ways, and that will need iCloud syncing, was ideally to be developed with Core Data, but I really wanted to dive into developing and I didn't have the patience to study before beginning, and now I am paying for that. Thanks again, I'll bother you with further questions about this, if I may, in the future! Best of luck, Cesare – cdf1982 Feb 22 '15 at 20:16
  • Hi Cesare! Congratulations! You found a solution! Good luck! Count with me, if i could be help in something! – Weles Feb 22 '15 at 21:39
  • Thanks again, I actually don't consider it a real solution, it's too much of an hack, so I Intend to go the way of Core Data following the article you sent me before. But the workaround I found, while not beautiful, allows me to temporarly move forward in the development while I learn Core Data, so I'm happy of this day. Please let me know if there's any chance that I could return the favor! – cdf1982 Feb 22 '15 at 21:42
  • Welcome. I am happy for your victory! I am starting programming swift and the way for solve many problems, was to use temporary solutions! I think you will learn core data, very fast. Let's go to help other people and learn more in stack overflow. For me is the better forum of the world. Even with my difficult with English, i prefer search and use this forum in English, because many people of different country use it. Good Luck for you, God Bless you! – Weles Feb 23 '15 at 00:48
  • The more I look to Core Data, the more I see is the way to go for me: instead of reinventing the wheel for everything (I don't even dare to think to add row reordering / deleting with the method I described in my self-reply), this is what I need to learn and use. Thanks again @Weles for pointing me in the right direction, I accepted your answer, as it clearly is the right one not just for me, but for everybody else who would happen to land to this page looking for help in this kind of situation. – cdf1982 Feb 25 '15 at 02:59
  • Hi @cdf1982! I am happy for your decision. Count with me for help in anyone about this! I found a new detailed article, about core data and i will share with you: http://www.raywenderlich.com/85578/first-core-data-app-using-swift Good Luck my friend! here my email, if you need someone and i may help: kweles@gmail.com – Weles Feb 25 '15 at 12:40
0

I spent all day trying to figure out a way to solve my own question above and I think I've finally found a working-workaround. My premise and disclaimer is that this is a pile of hacks, I post this only in case this might help someone in my situation in the future, but clearly the way to deal with this kind of situation is Core Data, as suggested by Weles' answer, not what I did.

Here's briefly what I've done to get my multi-component UITableView, in which all the data come from a single array of custom objects that is filtered by a different value in every component, to pass the selected object to the detail view when a cell is selected.

1) I added to all my customObjects an objectID : String computed property (current date + random number).

2) I added a var currentlySelectedObjectID : String? in my TableViewController.

3) I subclassed UITableViewCell, creating a CustomTableViewCell class that only adds to the normal class a var selectedCellID : String?, then I changed my cellForRowAtIndexPath to return a CustomTableViewCell instead of a UITableViewCell. Inside this method, before returning the cell, I also set the property selectedCellID of the cell equal to objectID of the current object. I also had to change the class of the cell in the Storyboard from UITableViewCell to CustomTableViewCell.

4) In the Storyboard I removed the segue from the cell to the detailViewController that was automatically created by Xcode and I set a custom StoryboardID to the detailViewController ("detailVC"),

5) Inside didSelectRowAtIndexPath of TableViewController I did all the work that before I was trying to do in prepareForSegue, but in a different way (not a segue, a self.navigationController?.pushViewController). Here's the code:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

let indexPath = tableView.indexPathForSelectedRow();

let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as CustomTableViewCell!;

self.currentlySelectedObjectID = currentCell.selectedCellID

// detailViewController instance
var detailVC = self.storyboard?.instantiateViewControllerWithIdentifier("detailVC") as MyDetailViewController

// I filter my objects array to "extract" the object with the objectID property equal to the currentlySelectedObjectID property (which is equal to the currentCell.selectedCellID, as set above). This array must have only 1 value. If so, I set the property passedCustomObject that I have in my detailViewController to the same object selected.
if (myObjectsArray!.filter() { $0.objectID == self.currentlySelectedObjectID }).count == 1 {
    detailVC.passedCustomObject = (myObjectsArray!.filter() { $0.objectID == self.currentlySelectedObjectID })[0]

} else {
    println("Error passing the object selected in the TableView to the DetailView")
}

// I push the detailViewController on top of the stack
self.navigationController?.pushViewController(detailVC, animated: true)
}

I think there are very good chance that a decent programmer (I am not one, but I hope to become one some day), seeing what I did, could faint. Again, I don't think anyone should do this, if you're in my same situation go straight to Core Data: I spent a day on this, there's good chance that in three or four I could have had Core Data working. But still, as hacked and inefficient as this is, it works... I tested multiple times. So, having spent so much time and having found no useful similar previous answers online, I thought to post mine.

Don't do this, I'm really afraid this is easily breakable! :)

I still look forward to other answers, to learn from my numerous mistakes!

cdf1982
  • 764
  • 1
  • 18
  • 34