AbdulHadi Yasin
AbdulHadi Yasin

Reputation: 73

Swift UITableView, Insert, then delete, then insert

I have a problem with UITableView inserting, deleting rows.

I'm trying to do a "Facebook messenger" seen effect in a UITableView. I have many cells that each indicates a message, and between them, there is a many cells that each indicates people who have seen this message so far. All of those data are stored in correctly.

Now, I want that when I receive a seen notification to delete a seen cell from the table and then insert another one at the proper index depending on my data source (in most cases last item). And when a user sends a message I'm adding his message to the table then removing his last seen cell, then reinsert another one after his message.

Now debugging the logic every thing is OK with updating data source and requesting to insert, delete on the UITableView, but I still get:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (36) must be equal to the number of rows contained in that section before the update (36), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'

I' have tried to put the call to this logic inside a beginUpdates(); and endUpdates();. All insertion, deleting is called inside main thread (UI)

Any help would be appreciated, many thanks.

Edit

here is my code:

//// Insert a seen status for user, handles seen logic
private func insertSeen(event: UEvent?) -> (removed: Int, inserted: Int) {
    // Make a holder for insertion result
    var result: (removed: Int, inserted: Int) = (removed: -1, inserted: -1);

    // Check if no event was given
    if(event == nil){
        return result; }

    if(event?.creatorID == "" && self.type == .single && self.participants.count > 0){
        event?.creatorID = self.participants[0].ID
        event?.creatorName = self.participants[0].username;
    }

    // Get last seen for targeted user
    let lastSeen = lastSeenForUser(id: (event?.creatorID)!);
    // Get targeted participant
    var particiapnt = self.participant(id: event!.creatorID);

    // If sender is self -> he will not be found in particiapnts list
    // So, we should get it's data from UserData
    if(event?.creatorID == UserData.current.ID){
        particiapnt = UserData.current;
    }
    // Check if no event was given
    if(particiapnt == nil){
        return result; }

    let name = particiapnt?.username;
    var image = particiapnt?.photo;
    if(image != nil) { image = image?.Scale(Width: 20); }

    // Store number of events before updates -> usefull to tell if seen has created a new event
    let count: Int = self.events.count;

    // Check if user has just sent a seen status
    if((count > 0 && lastSeen == count - 1) || particiapnt == nil){
        // Return a no insertion result [-1,-1]
        return result;
    }

    if(delegate != nil){
        delegate.beginUpdates();
    }

    // Check if user hasn't sent any seen event before
    if(lastSeen < 0){
        // Check if last event in group is seen
        if(self.events.count > 0 && self.events.last?.type == .seen) {
            // Add participant to last event
            let _ = self.events.last?.addParticipant(id: (event?.creatorID)!, name: name!, image: image);

            // Return where this user seen event was added
            result = (removed: lastSeen, inserted: self.events.count - 1);

            // Check delegate isn't null -> can apply changes
            if(delegate != nil){
                // Tell delegate about the update
                self.delegate.updateEvent(at: result.inserted, event: self.events[result.inserted]);
            }
        } else {
            // If last event is'nt seen -> Create a new one
            // Get a basic event
            let seen = BasicEvent;
            // Set event type as seen
            seen?.type = .seen;
            // Get where this participant was added
            let _ = seen?.addParticipant(id: (event?.creatorID)!, name: name!, image: image);
            // Insert the new craeted seen event to events
            self.events.append(seen!);

            // Return where this user seen event was added
            result = (removed: lastSeen, inserted: self.events.count - 1);

            // Check delegate isn't null -> can apply changes
            if(delegate != nil){
                // Tell delegate about the update
                self.delegate.addEvent(at: result.inserted, event: event, animation: .fade);
            }
        }
    }
    // Handle user has sent a seen event before
    else {
        // Get where the targeted user has sent his last seen status
        let seen = self.events[lastSeen];
        // Remove targeted user from his last seen status event
        let _ = seen.removeParticipant(id: (event?.creatorID)!);

        // If seen is'nt empty yet -> jus t remov current participant
        if(seen.participants.count > 0){
            // Return where this user seen event was added
            result = (removed: lastSeen, inserted: self.events.count - 1);

            // Check delegate isn't null -> can apply changes
            if(delegate != nil){
                // Tell delegate about the update
                self.delegate.updateEvent(at: result.removed, event: self.events[result.inserted]);
            }
        } else {
            // Delete empty seen event
            self.events.remove(at: lastSeen);

            // Return where this user seen event was added
            result = (removed: lastSeen, inserted: self.events.count - 1);

            // Check delegate isn't null -> can apply changes
            if(delegate != nil){
                print("coount: \(delegate.getTableView().numberOfRows(inSection: 0))  | 2 ");

                // Tell delegate about the update
                self.delegate.deleteEvent(at: result.removed, event: self.events[result.removed]);
            }
        }

        // Check if last event in group is seen
        if(self.events.count > 0 && self.events.last?.type == .seen) {
            // Add participant to last event
            let _ = self.events.last?.addParticipant(id: (event?.creatorID)!, name: name!, image: image);

            // Return where this user seen event was added
            result = (removed: lastSeen, inserted: self.events.count - 1);

            // Check delegate isn't null -> can apply changes
            if(delegate != nil){
                // Tell delegate about the update
                self.delegate.updateEvent(at: result.inserted, event: self.events[result.inserted]);
            }

        } else {
            // Get a basic event
            let seen = BasicEvent;
            // Set event type as seen
            seen?.type = .seen;
            // Get where this participant was added
            let _ = seen?.addParticipant(id: (event?.creatorID)!, name: name!, image: image);
            // Insert the new craeted seen event to events
            self.events.append(seen!);

            // Return where this user seen event was added
            result = (removed: lastSeen, inserted: self.events.count - 1)

            // Check delegate isn't null -> can apply changes
            if(delegate != nil){
                // Tell delegate about the update
                self.delegate.addEvent(at: result.inserted, event: seen, animation: .fade);
            }
        }
    }

    if(delegate != nil){
        delegate.endUpdates();
    }

    // Return final result of this insertion
    return result;
}

Upvotes: 0

Views: 428

Answers (2)

vinayak vanjari
vinayak vanjari

Reputation: 98

Debug your numberOfRowsInSection method, it's still returning 36 even though you inserted 1 row in UITable

Upvotes: 0

DJ_Mobi90
DJ_Mobi90

Reputation: 139

Debug it, might be you missed to update you datasource while update the table view.

Upvotes: 0

Related Questions