Sections by month in UITableView - ios

I've created a tableView which displays my array, it's an historic of my performances.
I want to "group" those performances in sections by month and in my array i got the creation date of each performance.
But i'm kind of lost on how to proceed. Here is the code of my tableview.
var historic: Historic!
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.historic == nil {
return 0
}
return self.historic.performances.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("HistoricTableViewCellOne", forIndexPath: indexPath) as! HistoricTableViewCell
// Configure the cell...
if self.historic != nil {
let perf = self.historic.performances[indexPath.row]
cell.configureWithPerformance(perf)
}
return cell
}
And here are my objects
class Historic: NSObject {
var totalDistance: CLLocationDistance = 0.0
var performances: [Performance] = [Performance]()
override init() {
super.init()
}
}
class Performance: NSObject {
var urlCover: NSURL
var duration: Double = 0
var length: Double = 0
var id: UInt = 0
var publicationStatus: PerformancePublicationStatus?
var creationDate: NSDate?
init(urlCover: NSURL, creationDate: NSDate){
self.urlCover = urlCover
self.creationDate = creationDate
}
}
Final Edit: It's working ! I'm putting the code here in case someone is interest.
var perfSections = [String]()
var tableViewCellsForSection = [Performance]()
var perfCells = Dictionary<String, [Performance]>()
// MARK: - Setup Data Source
private func setupDataSource() {
var calendar = NSCalendar.currentCalendar()
var dateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale.currentLocale()
dateFormatter.timeZone = calendar.timeZone
dateFormatter.setLocalizedDateFormatFromTemplate("MMMM YYYY")
let dateComponents: NSCalendarUnit = .CalendarUnitYear | .CalendarUnitMonth
var previousYear: Int = -1
var previousMonth: Int = -1
for performance in historic.performances {
var components: NSDateComponents = calendar.components(dateComponents, fromDate: performance.creationDate!)
var year: Int = components.year
var month: Int = components.month
if (year == previousYear && month == previousMonth) {
self.tableViewCellsForSection.append(performance)
previousYear = year
previousMonth = month
}
if (year != previousYear || month != previousMonth) {
if !self.tableViewCellsForSection.isEmpty {
var sectionHeading: String = dateFormatter.stringFromDate(self.tableViewCellsForSection.last!.creationDate!)
self.perfSections.append(sectionHeading)
self.perfCells[sectionHeading] = self.tableViewCellsForSection
self.tableViewCellsForSection = []
}
self.tableViewCellsForSection.append(performance)
previousYear = year
previousMonth = month
}
}
var sectionHeading: String = dateFormatter.stringFromDate(self.tableViewCellsForSection.last!.creationDate!)
self.perfSections.append(sectionHeading)
self.perfCells[sectionHeading] = self.tableViewCellsForSection
self.tableViewCellsForSection = []
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return self.perfSections.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if self.historic == nil {
return 0
}
var key = self.perfSections[section]
self.tableViewCellsForSection = self.perfCells[key]!
return self.tableViewCellsForSection.count
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.perfSections[section]
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("HistoricTableViewCellOne", forIndexPath: indexPath) as! HistoricTableViewCell
// Configure the cell...
if self.historic != nil {
var key = self.perfSections[indexPath.section]
self.tableViewCellsForSection = self.perfCells[key]!
let perf = self.tableViewCellsForSection[indexPath.row]
cell.configureWithPerformance(perf)
}
return cell
}

The problem is that your data model (self.historic.performances) is too simple-minded. You need sections and rows, but your data model expresses only rows. You will need a data model that structures your performances into sections. A typical approach is to use an array of arrays — each outer array is a section, and each inner array is the rows of that section. But of course many other approaches are possible.

Related

Can only delete an object from the Realm it belongs to Swift

I'm trying do delete the note from Realm in my NotesApp and facing this error: "Can only delete an object from the Realm it belongs to". This note has been saved before also in Realm and
could display it in my TableView by tapping on the date in my FSCalendar. I tried to replace realm.add(item) with realm.create(item), but also got the error: "Cannot convert value of type 'T' to expected argument type 'Object.Type' (aka 'RealmSwiftObject.Type')". I'm new in programming, so any help would be appreciated. Here's the relevant code code:
in my ToDoListItem.swift
class ToDoListItem: Object {
#objc dynamic var noteName: String = ""
#objc dynamic var date: Date = Date()
#objc dynamic var descriptionText: String = ""
#objc dynamic var noteImage = Data()
init(date: Date, noteName: String) {
self.date = date
self.noteName = noteName
}
override init() {
self.noteName = ""
self.date = Date()
self.descriptionText = ""
self.noteImage = Data()
}
}
in my RealmManager.swift
class RealmManager {
static let shared = RealmManager()
private let realm = try! Realm()
func write<T: Object>(item: T) {
realm.beginWrite()
realm.add(item)
try! realm.commitWrite()
}
func getObjects<T: Object>(type: T.Type) -> [T] {
return realm.objects(T.self).map({ $0 })
}
func delete<T: Object>(item: T) {
try! realm.write {
realm.delete(item)
}
}
}
in my ViewController where i can edit and delete the notes
#IBAction func didTapDelete() {
let note = ToDoListItem()
RealmManager.shared.delete(item: note)
self.deletionHandler?()
navigationController?.popToRootViewController(animated: true)
}
and finally in my TableViewController where the notes are displayed (honestly i think the problem is hidden here but cannot find it...
#IBOutlet var tableViewPlanner: UITableView!
#IBOutlet var calendarView: FSCalendar!
private var data = [ToDoListItem]()
var datesOfEvents: [String] {
return self.data.map { DateFormatters.stringFromDatestamp(datestamp: Int($0.date.timeIntervalSince1970)) }
}
var items: [ToDoListItem] = []
func getCount(for Date: String) -> Int {
var count: [String : Int] = [:]
for date in datesOfEvents {
count[date] = (count[date] ?? 0) + 1
}
return count[Date] ?? 0
}
func getEventsForDate(date: Date) -> [ToDoListItem] {
let string = DateFormatters.stringFromDatestamp(datestamp: Int(date.timeIntervalSince1970))
return self.data.filter {DateFormatters.stringFromDatestamp(datestamp: Int($0.date.timeIntervalSince1970)) == string }.sorted(by: {$0.date < $1.date})
}
override func viewDidLoad() {
super.viewDidLoad()
calendarView.rounding()
tableViewPlanner.rounding()
data = RealmManager.shared.getObjects(type: ToDoListItem.self)
self.items = self.getEventsForDate(date: Date())
calendarView.delegate = self
calendarView.dataSource = self
tableViewPlanner.delegate = self
tableViewPlanner.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.calendarView.select(Date())
self.calendarView.reloadData()
refresh()
}
//MARK:- TableView Data Source
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count //data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: K.plannerCellIdentifier, for: indexPath) as! NoteTableViewCell
let note = self.items[indexPath.row]
cell.configureCell(note: note)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let note = data[indexPath.row]
guard
let vc = storyboard?.instantiateViewController(identifier: K.infoVCIdentifier) as? InfoViewController else { return }
vc.note = note
vc.deletionHandler = { [weak self] in
self?.refresh()
}
vc.title = note.noteName
navigationController?.pushViewController(vc, animated: true)
}
//MARK:- User Interaction
#IBAction func didTapAddButton() {
guard
let vc = storyboard?.instantiateViewController(identifier: K.entryVCIdentifier) as? EntryViewController else { return }
vc.completionHandler = { [weak self] in
self?.refresh()
}
vc.title = K.entryVCTitle
navigationController?.pushViewController(vc, animated: true)
}
func refresh() {
DispatchQueue.main.async {
self.data = RealmManager.shared.getObjects(type: ToDoListItem.self)
self.tableViewPlanner.reloadData()
self.calendarView.reloadData()
}
}
}
extension PlannerViewController: FSCalendarDelegateAppearance & FSCalendarDataSource {
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventDefaultColorsFor date: Date) -> [UIColor]? {
let dateString = DateFormatters.yearAndMonthAndDateFormatter.string(from: date)
if self.datesOfEvents.contains(dateString) {
return [UIColor.blue]
}
return [UIColor.white]
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
self.items = self.getEventsForDate(date: date)
self.tableViewPlanner.reloadData()
}
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = DateFormatters.yearAndMonthAndDateFormatter.string(from: date)
let count = self.getCount(for: dateString)
self.tableViewPlanner.reloadData()
return count
}
}
The real problem is the didTapDelete function -- Why are you creating a new note just to delete it (I hope it was only to test out realm delete syntax). You should delete the note object that you passed to the view controller to edit / delete. (vc.note in did select row -> self.note in the other VC - where didTapDelete is)
So your did tap delete will look like --
RealmManager.shared.delete(item: note)
//show deleted alert & go back
A little explanation on the error - Just instantiating a Realm object (ToDoListItem()) does not add it to Realm (the Database system). To delete / edit a realm object, it has to be either fetched from a realm (RealmManager.shared.getObjects(type: ToDoListItem.self)) or added to the realm.
I'd advise going through a Realm tutorial before jumping in the code (there are plenty of them)

How to Fetch JSON to Swift to tableView as Sections and Rows?

I wanna ask how to implement the files as sections depends on userId then show all again in the tableview
I'm started build simple project i fetched json file as decoder and show all in table view
func fetchUsers(using url: String){
let url = URL(string: url)!
let _ = URLSession.shared.dataTask(with: url){ (data,response,error)
in
guard let data = data else {return}
do{
let objects = try JSONDecoder().decode([User].self, from: data) // decode * ( Codable )
self.users = objects
} catch{
print("error loading data cause: \(error)")
}
}.resume()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "users",for: indexPath) as? customeCellTableViewCell{
let indexRow = users[indexPath.row]
cell.dataModel(forModel: indexRow)
return cell
}
return UITableViewCell()
}
private func numberOfUsers(in users: [User]) -> Int {
return 1
}
func numberOfSections(in tableView: UITableView) -> Int {
return numberOfUsers(in: self.users)
}
Like #vadian mentions tuples should be avoided for this so here is an improved solution.
Instead of a tuple we can use a struct to hold the grouped data
struct UsersByID {
let id: Int
var users : [User]
}
then change the load function to
func load(withUsers users: [User]) {
let dict = Dictionary(grouping: users) { return $0.userID }
usersByID = dict.map { (key, values) in
return UsersByID(id: key, users: values)
}.sorted(by: { $0.id < $1.id })
}
The rest of the code is the same but replace key with id and value with users
Old solution
First create a dictionary to hold your sections (keys) and rows (values) as a property in the view controller
var usersByID = [(key: Int, value: [User])]()
then fill that dictionary using grouping:by: using the array from json
func load(withUsers users: [User]) {
usersByID = Dictionary(grouping: users, by: { user in
user.userID }).sorted(by: { $0.0 < $1.0})
}
then the table view functions use this dictionary
override func numberOfSections(in tableView: UITableView) -> Int {
return usersByID.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return usersByID[section].value.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return String(usersByID[section].key)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath)
let user = usersByID[indexPath.section].value[indexPath.row]
cell.textLabel?.text = user.title
//...
return cell
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return datesArr.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if (contractsDict.keys.contains(datesArr[section])) {
return contractsDict[datesArr[section]]!.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ContractsCollectionViewCell
DispatchQueue.main.async {
if (self.contractsDict.keys.contains(self.datesArr[indexPath.section])) {
for _ in 0..<(self.contractsDict[self.datesArr[indexPath.section]]!.count) {
cell.contract = self.contractsDict[self.datesArr[indexPath.section]]![indexPath.row]
cell.delegate = self
}
}
}
return cell
}
}
}
ContractServices.shared.fetchAllContracts(completion: { (contracts, err) in
DispatchQueue.main.async {
if (err != nil) {
print(err!, "1323")
return
}
for contract in (contracts?.data)! {
self.allContractsArr.append(contract)
if let callDate = contract.revdat {
let formatterGet = DateFormatter()
formatterGet.dateFormat = "yyyy-MM-dd HH:mm:ss"
let newFormat = DateFormatter()
newFormat.dateFormat = "dd MMM yyyy"
if let date = formatterGet.date(from: callDate) {
self.datesArr.append(newFormat.string(from: date))
}
}
}
for i in 0..<self.allContractsArr.count {
if let callDate = self.allContractsArr[i].revdat {
let formatterGet = DateFormatter()
formatterGet.dateFormat = "yyyy-MM-dd HH:mm:ss"
let newFormat = DateFormatter()
newFormat.dateFormat = "dd MMM yyyy"
if let date = formatterGet.date(from: callDate) {
self.allContractsArr[i].revdat = newFormat.string(from: date)
}
}
}
self.allContractsArr = self.allContractsArr.sorted(by: { ($0.revdat)! > ($1.revdat)! })
self.contractsDict = Dictionary(grouping: self.allContractsArr, by: { ($0.revdat)! })
let newFormat = DateFormatter()
newFormat.dateFormat = "dd MMM yyyy"
self.datesArr = Array(Set(self.datesArr))
self.datesArr = self.datesArr.sorted(by: { newFormat.date(from: $0)! > newFormat.date(from: $1)! })
self.contractListCV.reloadData()
DispatchQueue.main.async {
self.activityBackView.isHidden = true
self.activity.isHidden = true
self.activity.stopAnimating()
self.design()
}
}
})
This is how I'm doing.
Getting the data in array format, converting them into Dictionary by grouping(by:) method, and then operating everything related to the collectionview upon those dictionary data.

Table view from array index out of range

I'm using an array to read data from a database, Currently I have 8 items in the array. I am trying to make a table where I have a section header. Currently I have 4 sections and I have set that properly and it works. It also works running the first time but when I try to scroll back I get an index out of range. I am using myarray[myindex] to set the cell data for each item and that is not working.
It seems that I need to break up my data into 4 sections that contains only the data for each section to let the table view control it properly. The data can contain any number of sections.
Is there a better way to do this?
I have attached a pic to describe the problem.
Thanks
Adding code on request.
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
print("Returning Sections - > \(sections)")
return sections //seems to work
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
print("Return number of rows in section -> \(noRowsInSection[section])")
return noRowsInSection[section] // seems to work
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionHeader[section] // seems to work
}
override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
// Format for section Headers
let header:UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView
header.textLabel!.textColor = UIColor.blueColor()
UIColor.blueColor()
header.textLabel!.font = UIFont.boldSystemFontOfSize(12)
header.textLabel!.frame = header.frame
header.textLabel!.textAlignment = NSTextAlignment.Right
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("OurCell", forIndexPath: indexPath) as! OurTableViewCell
print("myindex - > \(myindex) row -> \(indexPath.row)")
cell.OurCellLabel.text = MyHouses[myindex].getAddressDetails() // End configure houses.cell
//cell.OurCellLabel.text = MyHouses[indexPath.row].getAddressDetails() // End configure houses.cell
myindex++ // PROBLEM HERE - GOES OUT OF RANGE
return cell
}
Here I am getting data from the sqlite DB
func GetListOfHousesFromDB() {
let docsDir = dirPaths[0]
let databasePath = docsDir.stringByAppendingString("/newdb.db")
if fileMgr.fileExistsAtPath(databasePath as String) {
let houseDB = FMDatabase(path: databasePath as String)
if houseDB.open() {
var noRows: Int = 0
var sql = "select count(Address) as cnt from Houses" // Define Query
houseDB.executeStatements(sql) // Execute Query
let results:FMResultSet? = houseDB.executeQuery(sql,withArgumentsInArray: nil) //Get results from Query
if results?.next() == true {
let cnt = (results?.stringForColumn("cnt"))! // Retrieve number of rows from DB
noRows = Int(cnt)!
}
var i = 0
sql = "SELECT Address, Street, City, State, Zip from Houses ORDER BY State, City, Street, Address" // Define Query
houseDB.executeStatements(sql) // Execute Query
let results2:FMResultSet? = houseDB.executeQuery(sql,withArgumentsInArray: nil) // Get results from Query
while results2?.next() == true {
MyHouses.append(newhouse())
MyHouses[i].address = (results2?.stringForColumn("Address"))!
MyHouses[i].street = (results2?.stringForColumn("Street"))!
MyHouses[i].city = (results2?.stringForColumn("City"))!
MyHouses[i].state = (results2?.stringForColumn("State"))!
MyHouses[i].zip = (results2?.stringForColumn("Zip"))!
print("Address -> \(i) \(MyHouses[i].getAddressDetails())")
i++
}
}
houseDB.close()
}
}
Based on your other post, what you need is an updated House model and updated data structure for handling data for your table view.
House - Model class
struct House {
var address: String
var street: String
var city: String
var state: String
var zip: String
func getAddressDetails() -> String {
return "\(address) \(street) \(city) \(state) \(zip)"
}
func getCityState() -> String {
return "\(city) - \(state)"
}
}
Helper Class for loading data
class HouseDataHelper {
private static let _sharedInstance = HouseDataHelper()
var myHouses: Dictionary<String, [House]> = [:]
private init() {
loadHouseData()
}
static func sharedInstance() -> HouseDataHelper {
return _sharedInstance
}
private func loadHouseData() {
var houses = [House]()
//Populating your actual values here. GetListOfHousesFromDB()
//Loading dummy data for testing
var sectionHeader = ""
for i in 0...4 {
sectionHeader = "Header \(i)"
houses += [House(address: "Address1", street: "Street1", city: "City1", state: "State1", zip: "Zip1")]
houses += [House(address: "Address2", street: "Street2", city: "City2", state: "State2", zip: "Zip2")]
houses += [House(address: "Address3", street: "Street3", city: "City3", state: "State3", zip: "Zip3")]
houses += [House(address: "Address4", street: "Street4", city: "City4", state: "State4", zip: "Zip4")]
houses += [House(address: "Address5", street: "Street5", city: "City5", state: "State5", zip: "Zip5")]
myHouses.updateValue(houses, forKey: sectionHeader)
houses = []
}
}
}
Table View Controller
class TableViewController: UITableViewController {
var houses = HouseDataHelper.sharedInstance().myHouses
var sectionHeaders: [String] = []
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
sectionHeaders = Array(houses.keys.sort())
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return houses.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let rows = houses[sectionHeaders[section]] {
return rows.count
}
return 0
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionHeaders[section]
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//Populate cells based on "houses"
}
}

Swift - Construct a sentence from array of <AnyObject>

Good day! I'm building an app that needs to construct a sentence from the data from Core Data. I have this:
var players = Array<AnyObject> = []
#IBOutlet weak var sentenceLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context: NSManagedObjectContext = appDelegate.managedObjectContext!
let freq = NSFetchRequest(entityName: "Orders")
players = context.executeFetchRequest(freq, error: nil)!
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return players.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("checkCell") as! SummaryCustomCell!
if cell == nil {
cell = SummaryCustomCell(style: UITableViewCellStyle.Default, reuseIdentifier: "checkCell")
}
var data: NSManagedObject = players[indexPath.row] as! NSManagedObject
cell.playerNameLabel.text = data.valueForKey("playerName") as? String
cell.teamLabel.text = data.valueForKey("team") as? String
cell.yearsLabel.text = data.valueForKey("yearsOfPlaying") as? String
for var i = 0; i < players.count;i++ {
var dataLooped: NSManagedObject = myOrders[i] as! NSManagedObject
var playerName = dataLooped.valueForKey("playerName") as? String
var team = dataLooped.valueForKey("team") as? String
var years = dataLooped.valueForKey("yearsOfPlaying") as? String
var constructedSentence: NSString = NSString(format: "%# was playing for %# for %# years.", playerName, team, years)
sentenceLabel.text = constructedSentence as! String
}
}
return cell
}
Then it gives only the last row in the database. It must loop the sentence in a single string. For example. "Kobe Bryant was playing for LA Lakers for 5 years; Lebron James was playing for Cavs for 3 years." and so on..
How can I implement this? Thank you very much!

UITableViewController - Different number of cells for each section

I'm currently trying to load different entities from my CoreData model into one UITableView but under different sections. I've tried the following method:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
// #warning Incomplete method implementation.
// Return the number of rows in the section.
var rows = 0
if section == 0 {
rows = crew.count
} else if section == 1 {
rows = aircraft.count
} else if section == 2 {
rows = batteries.count
}
return rows
}
But that doesn't seem to work. It returns the first crew.count for every section. I should note that crew, aircraft and batteries are arrays of NSManagedObject.
Does anyone have any advice on how to implement what I'm looking for?
Thanks.
EDIT: Here are other methods I'm implementing for clarity..
var crew = [NSManagedObject]()
var aircraft = [NSManagedObject]()
var batteries = [NSManagedObject]()
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let crewFetchRequest = NSFetchRequest(entityName:"Crew")
var crewError: NSError?
let crewFetchedResults = managedContext.executeFetchRequest(crewFetchRequest, error: &crewError) as? [NSManagedObject]
if let crewResults = crewFetchedResults {
crew = crewResults
} else {
println("Could not fetch \(crewError), \(crewError!.userInfo)")
}
let aircraftFetchRequest = NSFetchRequest(entityName:"Aircraft")
var aircraftError: NSError?
let aircraftFetchedResults = managedContext.executeFetchRequest(aircraftFetchRequest, error: &aircraftError) as? [NSManagedObject]
if let aircraftResults = crewFetchedResults {
aircraft = aircraftResults
} else {
println("Could not fetch \(aircraftError), \(aircraftError!.userInfo)")
}
let batteryFetchRequest = NSFetchRequest(entityName:"Battery")
var batteryError: NSError?
let batteryFetchedResults = managedContext.executeFetchRequest(batteryFetchRequest, error: &batteryError) as? [NSManagedObject]
if let batteryResults = crewFetchedResults {
batteries = batteryResults
} else {
println("Could not fetch \(batteryError), \(batteryError!.userInfo)")
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 3
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
// #warning Incomplete method implementation.
// Return the number of rows in the section.
var rows = 0
if section == 0 {
rows = crew.count
} else if section == 1 {
rows = aircraft.count
} else if section == 2 {
rows = batteries.count
}
return rows
}
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String?
{
return sectionTitles[section]
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("CrewCell", forIndexPath: indexPath) as! UITableViewCell
// Configure the cell...
switch indexPath.section.description
{
case "0":
cell.textLabel!.text = crew[indexPath.item].valueForKey("name") as? String
if crew[indexPath.item].valueForKey("pilot") as? Bool == true {
cell.detailTextLabel!.text = "Pilot"
} else {
cell.detailTextLabel!.text = " "
}
break;
case "1":
cell.textLabel!.text = "Aircraft"
break;
case "2":
cell.textLabel!.text = "Battery"
break;
default:
break;
}
return cell
}
Your code is good, but you will need to set the number of section in tableview as well by implementing
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}
EDITED:
From the edited question I can now clearly see that your problem is with your data source
let aircraftFetchRequest = NSFetchRequest(entityName:"Aircraft")
var aircraftError: NSError?
let aircraftFetchedResults = managedContext.executeFetchRequest(aircraftFetchRequest, error: &aircraftError) as? [NSManagedObject]
if let aircraftResults = crewFetchedResults {
aircraft = aircraftResults
} else {
println("Could not fetch \(aircraftError), \(aircraftError!.userInfo)")
}
let batteryFetchRequest = NSFetchRequest(entityName:"Battery")
var batteryError: NSError?
let batteryFetchedResults = managedContext.executeFetchRequest(batteryFetchRequest, error: &batteryError) as? [NSManagedObject]
if let batteryResults = crewFetchedResults {
batteries = batteryResults
}
if let aircraftResults = crewFetchedResults and if let batteryResults = crewFetchedResults will return crewFetchResults so all crew,aircrafts and batteries arrays are holding exactly the same elements. You must replace these lines with if let aircraftResults = aircraftFetchedResults and if let batteryResults = batteryFetchedResults. Hope I was clear enough

Resources