Joker Joker - 2 months ago 8
iOS Question

Mssing return in a function expected to return 'UITableViewCell'

There might be similar questions in SO but None helped me achieving my result and hence end up asking here.

The Scenario

I have a ViewController(HomeViewController).In my HomeController I have a subview with a tableview inside. This subview is partially visible and users can Pan it down to reveal Tableview data. The Tableview will display Notifications like Messages , Photos , Notes and Events. My application is a Group chat only app. So these Messages , photos , Notes and Events will be Displayed based on Groups. And a group will show only 25 Messages , 8 photos , 2 notes and 1 event details. Fro showing messages I have created a TableviewCell and registered it to the Tableview inside HomeViewController like this

var notifications : NotificationsView!
notifications.frame = CGRectMake(0, -self.view.frame.height + 175, self.view.frame.size.width, self.view.frame.size.height)
notifications._tableview.dataSource = self
notifications._tableview.delegate = self
notifications._tableview.registerNib(UINib(nibName: "TimelineCell", bundle: nil), forCellReuseIdentifier: "timelinecell")
notifications._tableview.registerNib(UINib(nibName: "PhotosCell", bundle: nil), forCellReuseIdentifier: "photos")
notifications._tableview.registerNib(UINib(nibName: "NotesCell", bundle: nil), forCellReuseIdentifier: "notes")
notifications._tableview.registerNib(UINib(nibName: "CalendarCell", bundle: nil), forCellReuseIdentifier: "calendar")


And My Model Class looks like this

class TimelineModal : Object {
dynamic var groupID = ""
dynamic var groupName = ""
let messages = List<TimelineGroupMessages>()
let photos = List<TimelineGroupPhotos>()
let notes = List<TimelineGroupNotes>()
let calendarDetails = List<TimelineGroupCalendar>()

override class func primaryKey() -> String? { return "groupID" }

}

class TimelineGroupMessages : Object {

dynamic var message = ""
dynamic var userName = ""
dynamic var messagetype = ""
}

class TimelineGroupPhotos : Object {

dynamic var photo = ""
}

class TimelineGroupNotes : Object {

dynamic var noteTitle = ""

}

class TimelineGroupCalendar : Object {

dynamic var calendarEventDate = ""
dynamic var calendarEventTitle = ""

}


Data inside Tableview will be such a way that each group's Messages(25) shows first then Photos(8) , then Notes (2) and finally Event (1) and again the same formatted data will show for another group.

For showing data the Data from realm is Fetched on
viewWillAppear()


private var numberofRowsforTimeline : Int = 0
private var realmdata : Results<TimelineModal>!
private var groupsCount : Int = 0
private var messagesCount : Int = 0
private var photosCount : Int = 0
private var notesCount : Int = 0
private var eventsCount : Int = 0

private func LoadDatafromRealm()
{
let realm = try! Realm()
let realmDbData = realm.objects(TimelineModal)
print("Data : \(realmDbData)")
groupsCount = realmDbData.count
let messages_Count : Int = Int(realm.objects(TimelineGroupMessages).count)
let photos_Count : Int = Int(realm.objects(TimelineGroupPhotos).count)
let notes_Count : Int = Int(realm.objects(TimelineGroupNotes).count)
let events_Count : Int = Int(realm.objects(TimelineGroupCalendar).count)
self.realmdata = realmDbData

numberofRowsforTimeline += messages_Count + photos_Count + notes_Count + events_Count

}


And here is the code where I gets the error mentioned

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberofRowsforTimeline
}

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

var cell : UITableViewCell!
// let cellMessages : TimelineCell = tableView.dequeueReusableCellWithIdentifier("timelinecell", forIndexPath: indexPath) as! TimelineCell
//let cellPhotos : PhotosCell = tableView.dequeueReusableCellWithIdentifier("photos", forIndexPath: indexPath) as! PhotosCell
//let cellNotes : NotesCell = tableView.dequeueReusableCellWithIdentifier("notes", forIndexPath: indexPath) as! NotesCell
//let cellCalendar : CalendarCell = tableView.dequeueReusableCellWithIdentifier("calendar", forIndexPath: indexPath) as! CalendarCell

for __data in self.realmdata
{
if __data.messages.count > 0
{
let cellMessages : TimelineCell = tableView.dequeueReusableCellWithIdentifier("timelinecell", forIndexPath: indexPath) as! TimelineCell

for x in 0..<__data.messages.count - 1
{
cellMessages.topConstraintforgroupNameLabel.constant = heightConstraints.topConstraintForRowZero.rawValue
cellMessages.topConstraintfortabNameLabel.constant = heightConstraints.topConstraintForRowZero.rawValue
cellMessages.lblGroupID.text = __data.groupID
cellMessages.lblGroupID.hidden = true
cellMessages.lblGroupName.text = __data.groupName
cellMessages.lblmessage.text = __data.messages[x].message
return cellMessages
}

}
else if __data.photos.count > 0
{
let cellPhotos : PhotosCell = tableView.dequeueReusableCellWithIdentifier("photos", forIndexPath: indexPath) as! PhotosCell

for p in 0..<__data.photos.count - 1
{
cellPhotos.imgPhoto1_photos.image = UIImage(imageLiteral: __data.photos[p].photo)
return cellPhotos
}
}
else if __data.notes.count > 0
{
let cellNotes : NotesCell = tableView.dequeueReusableCellWithIdentifier("notes", forIndexPath: indexPath) as! NotesCell

for n in 0..<__data.notes.count - 1
{
cellNotes.lblNoteName1.text = __data.notes[n].noteTitle
return cellNotes
}
}
else if __data.calendarDetails.count > 0
{
let cellCalendar : CalendarCell = tableView.dequeueReusableCellWithIdentifier("calendar", forIndexPath: indexPath) as! CalendarCell
for c in 0..<__data.calendarDetails.count - 1
{
cellCalendar.lblEventName1.text = __data.calendarDetails[c].calendarEventTitle
return cellCalendar
}

}
else
{
return cell

}
}
} //-> Error Mssing return in a function expected to return 'UITableViewCell'


Where i went wrong? Sorry if made my question too broad. Just tried to make sure you understand what I need. That's it. Help! Help! Help!

Note : I tried returning Cell in different ways where the error mentioned didn't occured but the Tableview had same data for all cell.

Answer

I think you've misunderstood how the tableView delegate and datasource methods are used to build a tableView. In particular, the cellForRowAtIndexPath method is called multiple times, once for each row that is to be displayed. The indexPath parameter tells you which section/row is required. There is no need to loop through your data - just use the indexPath to select the correct elements in your arrays. The loops are in any event futile, since the first time the return statement is executed, the whole function is terminated - the loop will not progress to its next iteration.

For example, the following should result in a table with a section for each Group, with rows in each section for messages, photos, notes and events:

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return self.groupsCount // separate section for each Group
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // locate the correct Group for the given section
    let __data = self.realmdata[section]
    // the total number of rows for this section (ie Group) is:
    // number of messages + number of photos + number of notes + number of events:
    return __data.messages.count + __data.photos.count + __data.notes.count + __data.calendarDetails.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    // locate the correct Group for the given section (using the indexPath)
    let __data = self.realmdata[indexPath.section]
    if (indexPath.row < __data.messages.count) { // first rows are the messages
        // use the indexPath.row to get the required index for the messages:
        let messageIndex = indexPath.row
        let cellMessages : TimelineCell = tableView.dequeueReusableCellWithIdentifier("timelinecell", forIndexPath: indexPath) as! TimelineCell
        cellMessages.topConstraintforgroupNameLabel.constant = heightConstraints.topConstraintForRowZero.rawValue
        cellMessages.topConstraintfortabNameLabel.constant = heightConstraints.topConstraintForRowZero.rawValue
        cellMessages.lblGroupID.text = __data.groupID
        cellMessages.lblGroupID.hidden = true
        cellMessages.lblGroupName.text = __data.groupName
        // use the index to locate the correct message text:
        cellMessages.lblmessage.text = __data.messages[messageIndex].message
        return cellMessages
    } else if (indexPath.row < __data.messages.count + __data.photos.count) { // next are the photos
        // use the indexPath.row (adjusted to account for the messages rows) to get the required index for the photos:
        let photoIndex = indexPath.row - __data.messages.count
        let cellPhotos : PhotosCell    = tableView.dequeueReusableCellWithIdentifier("photos", forIndexPath: indexPath)  as! PhotosCell
        cellPhotos.imgPhoto1_photos.image = UIImage(imageLiteral: __data.photos[photoIndex].photo)
        return cellPhotos
    } else if (indexPath.row < __data.messages.count + __data.photos.count + __data.notes.count) { // next are the notes
        let noteIndex = indexPath.row - __data.messages.count - __data.photos.count
        let cellNotes : NotesCell     = tableView.dequeueReusableCellWithIdentifier("notes", forIndexPath: indexPath) as! NotesCell
        cellNotes.lblNoteName1.text = __data.notes[noteIndex].noteTitle
        return cellNotes
    } else { // next are the Events
        let eventIndex = indexPath.row - __data.messages.count - __data.photos.count - __data.notes.count
        let cellCalendar    : CalendarCell  = tableView.dequeueReusableCellWithIdentifier("calendar", forIndexPath: indexPath)       as! CalendarCell
        cellCalendar.lblEventName1.text = __data.calendarDetails[eventIndex].calendarEventTitle
        return cellCalendar
    }
}