iamnickpitoniak
iamnickpitoniak

Reputation: 227

iOS - failed to obtain a cell from its dataSource


I written a swift file that controls a messaging connection between two users. For some reason, the file crashes on load and returns me this error:

015-12-18 11:19:07.449 collaboration[4761:357519] *** Assertion failure in -[UITableView _configureCellForDisplay:forIndexPath:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.30.14/UITableView.m:7962
2015-12-18 11:19:07.453 collaboration[4761:357519] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView (<UITableView: 0x7c9f6400; frame = (16 58; 288 412); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7a7a4170>; layer = <CALayer: 0x7a7a3250>; contentOffset: {0, 0}; contentSize: {288, 44}>) failed to obtain a cell from its dataSource (<collaboration.chatViewController: 0x7a7a0750>)'
*** First throw call stack:
(
    0   CoreFoundation                      0x00304a14 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x02233e02 objc_exception_throw + 50
    2   CoreFoundation                      0x003048aa +[NSException raise:format:arguments:] + 138
    3   Foundation                          0x00946d26 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 118
    4   UIKit                               0x00ede528 -[UITableView _configureCellForDisplay:forIndexPath:] + 228
    5   UIKit                               0x00eeb3cf -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 877
    6   UIKit                               0x00eeb4e1 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 90
    7   UIKit                               0x00ebb948 -[UITableView _updateVisibleCellsNow:isRecursive:] + 3347
    8   UIKit                               0x00eda0d6 __29-[UITableView layoutSubviews]_block_invoke + 52
    9   UIKit                               0x00ef519e -[UITableView _performWithCachedTraitCollection:] + 88
    10  UIKit                               0x00ed9fab -[UITableView layoutSubviews] + 214
    11  UIKit                               0x00e30008 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 810
    12  libobjc.A.dylib                     0x02248059 -[NSObject performSelector:withObject:] + 70
    13  QuartzCore                          0x05bf580a -[CALayer layoutSublayers] + 144
    14  QuartzCore                          0x05be94ee _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 388
    15  QuartzCore                          0x05be9352 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
    16  QuartzCore                          0x05bdbe8b _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 317
    17  QuartzCore                          0x05c0fe03 _ZN2CA11Transaction6commitEv + 561
    18  QuartzCore                          0x05c11674 _ZN2CA11Transaction17flush_transactionEv + 50
    19  UIKit                               0x00d94dfa _afterCACommitHandler + 197
    20  CoreFoundation                      0x0021dffe __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
    21  CoreFoundation                      0x0021df5e __CFRunLoopDoObservers + 398
    22  CoreFoundation                      0x002138dc __CFRunLoopRun + 1340
    23  CoreFoundation                      0x002130e6 CFRunLoopRunSpecific + 470
    24  CoreFoundation                      0x00212efb CFRunLoopRunInMode + 123
    25  GraphicsServices                    0x05696664 GSEventRunModal + 192
    26  GraphicsServices                    0x056964a1 GSEventRun + 104
    27  UIKit                               0x00d63bfa UIApplicationMain + 160
    28  collaboration                       0x000b125c main + 140
    29  libdyld.dylib                       0x02c97a21 start + 1
    30  ???                                 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

I accidentally deleted the file. Luckily I had a backup so I was able to create a new file under the same name and paste all of the code into it.
Code in question:

import UIKit

class chatViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!

    var timer = NSTimer()

    var tableBackgroundInc = 1

    let EnigmaMachine = EncryptionMachine()

    var friendChosen: String!

    var isConnectedToInternet: Bool!

    var receivedUsername:String!

    @IBOutlet weak var testLabel: UILabel!

    var messageStringRecords = []

    var messages: NSMutableArray = NSMutableArray()

    func sendAlert(subject: String, message: String) {
        let alertController = UIAlertController(title: subject, message:
            message, preferredStyle: UIAlertControllerStyle.Alert)
        alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default,handler: nil))
        self.presentViewController(alertController, animated: true, completion: nil)
    }

    func tableView(tableView: UITableView, numberOfRowsInSection Section: Int) -> Int {
        return self.messages.count
    }

    /*@IBAction func refreshButton(sender: UIButton) {
        reloadTable()
    }*/

    @IBOutlet weak var messageTextInput: UITextField!

    @IBAction func sendButton(sender: UIButton) {
        let chatPartner = self.friendChosen
        let username = NSUserDefaults.standardUserDefaults().stringForKey("username")! as String
        let theMessage = messageTextInput.text! as String
        let messageTextPreOne = EnigmaMachine.encrypt(theMessage)
        let messageTextPreTwo = messageTextPreOne.stringByReplacingOccurrencesOfString(" ", withString: "039254space925403")
        let messageText = self.voidInvalidCharacters(messageTextPreTwo)
        if messageText != "" {
            let secretKey = "0000"
            let myUrl = NSURL(string: "http://www.neverforgottenbbq.com/gfg/sendMessage.php")
            let request = NSMutableURLRequest(URL: myUrl!)
            request.HTTPMethod = "POST"
            let postString = "secretKey=\(secretKey)&username=\(username)&chatPartner=\(chatPartner)&message=\(messageText)"
            request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
            let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
                data, response, error in
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {

                    if let responseData = data {

                        let responseString = NSString(data: responseData, encoding: NSUTF8StringEncoding)
                        if error != nil {
                            print("Error: \(error)")
                        }
                        dispatch_async(dispatch_get_main_queue()) {
                            print("")
                        }
                    } else {
                        print("The connection quit")
                    }
                }
            }

            task.resume()
        }

        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = self.tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! chatTableViewCell
            //cell.messageLabel?.text = self.messages.objectAtIndex(indexPath.row) as? String
            let wholeMessage = self.messages.objectAtIndex(indexPath.row) as? String
            if wholeMessage! as String != "Loading......" && wholeMessage! as String != "No messages" {
                let splitMessage = wholeMessage!.componentsSeparatedByString("203598123589")
                let theMessage = splitMessage[0]
                if EnigmaMachine.decrypt(splitMessage[1]) as String == friendChosen.uppercaseString as String {
                    let completeMessage = friendChosen.uppercaseString + ": " + theMessage
                    cell.messageLabel?.text = completeMessage
                } else {
                    cell.messageLabel.textAlignment = NSTextAlignment.Right
                    let completeMessage = theMessage
                    cell.messageLabel?.text = completeMessage
                }
            } else {
                cell.messageLabel?.text = wholeMessage! as String
            }
            tableView.estimatedRowHeight = requiredHeight(self.messages.objectAtIndex(indexPath.row) as! String)
            tableView.rowHeight = UITableViewAutomaticDimension
            cell.layer.cornerRadius = 5
            cell.layer.masksToBounds = true
            return cell
        }

        func requiredHeight(text:String) -> CGFloat {
            let font = UIFont(name: "Georgia", size: 16.0)
            let label:UILabel = UILabel(frame: CGRectMake(0, 0, 200, CGFloat.max))
            label.numberOfLines = 0
            label.lineBreakMode = NSLineBreakMode.ByWordWrapping
            label.font = font
            label.text = text
            label.sizeToFit()
            return label.frame.height
        }

        func reloadTable() {
            refreshTable()
            self.messages = []
            let chatPartner = NSUserDefaults.standardUserDefaults().stringForKey("usernameToMessageWith")! as String
            let username = NSUserDefaults.standardUserDefaults().stringForKey("username")! as String
            let myUrl = NSURL(string: "http://www.neverforgottenbbq.com/gfg/getMessagesForCurrentChat.php")
            let request = NSMutableURLRequest(URL: myUrl!)
            request.HTTPMethod = "POST"
            let postString = "username=\(username)&chatPartner=\(chatPartner)"
            request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
            let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
                data, response, error in
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {

                    if let responseData = data {

                        let responseString = NSString(data: responseData, encoding: NSUTF8StringEncoding)
                        if error != nil {
                            print("Error: \(error)")
                        }
                        dispatch_async(dispatch_get_main_queue()) {
                            self.messageStringRecords = responseString!.componentsSeparatedByString("3292985383")
                            for index in self.messageStringRecords {
                                let indexSplit = index.componentsSeparatedByString("9254203598")
                                if indexSplit.count > 1 {
                                    let theMessage = indexSplit[0]
                                    let messageId = indexSplit[1]
                                    self.updateReadStatus(messageId)
                                    let theNewMessage = theMessage
                                    self.messages.addObject(self.EnigmaMachine.decrypt(theNewMessage))
                                    self.tableBackgroundInc = 1
                                    self.tableView.reloadData()
                                }
                            }
                        }
                    } else {
                        print("The connection quit")
                    }
                }
            }

            task.resume()
            self.tableView.estimatedRowHeight = 44.0
            self.tableView.rowHeight = UITableViewAutomaticDimension
            self.tableBackgroundInc = 1
            self.tableView.reloadData()
        }
    }

    func updateReadStatus(messageId: String) {
        let theSecretKey = "0000"
        let myUrl = NSURL(string: "http://www.neverforgottenbbq.com/gfg/updateReadStatus.php")
        let request = NSMutableURLRequest(URL: myUrl!)
        request.HTTPMethod = "POST"
        let postString = "id=\(messageId)&secretKey=\(theSecretKey)"
        request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {

                if let responseData = data {

                    _ = NSString(data: responseData, encoding: NSUTF8StringEncoding)
                    if error != nil {
                        print("Error: \(error)")
                    }
                    dispatch_async(dispatch_get_main_queue()) {
                        print("")
                    }
                } else {
                    print("The connection quit")
                }
            }
        }

        task.resume()
    }

    func voidInvalidCharacters(stringToVoid: String) -> String {
        var returnString = ""
        var sanitizedArray: [String] = []
        let acceptableCharacters = [
            "A",
            "B",
            "C",
            "D",
            "E",
            "F",
            "G",
            "H",
            "I",
            "J",
            "K",
            "L",
            "M",
            "N",
            "O",
            "P",
            "Q",
            "R",
            "S",
            "T",
            "U",
            "V",
            "W",
            "X",
            "Y",
            "Z",
            "a",
            "b",
            "c",
            "d",
            "e",
            "f",
            "g",
            "h",
            "i",
            "j",
            "k",
            "l",
            "m",
            "n",
            "o",
            "p",
            "q",
            "r",
            "s",
            "t",
            "u",
            "v",
            "w",
            "x",
            "y",
            "z",
            "0",
            "1",
            "2",
            "3",
            "4",
            "5",
            "6",
            "7",
            "8",
            "9",
            "-",
            ".",
            "_",
            "~",
            ":",
            "/",
            "?",
            "#",
            "[",
            "]",
            "@",
            "!",
            "$",
            "'",
            "(",
            ")",
            "*",
            "+",
            ",",
            ";",
            "="
        ]
        let stringToVoidArray = Array(stringToVoid.characters)
        for letter in stringToVoidArray {
            var isAcceptable = false
            for character in acceptableCharacters {
                if character as String == String(letter) {
                    isAcceptable = true
                }
            }
            if isAcceptable == true {
                sanitizedArray.append(String(letter))
            }
        }
        for letter in sanitizedArray {
            returnString = returnString + letter
        }
        return returnString
    }

    func keyboardWillShow(notification: NSNotification) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }

    func keyboardWillHide(notification: NSNotification) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            self.view.frame.origin.y += keyboardSize.height
        }
    }

    func dismissKeyboard() {
        self.messageTextInput.resignFirstResponder()
    }
    func refreshTable () {
        let newMessages: NSMutableArray = NSMutableArray()
        let chatPartner = self.receivedUsername
        if chatPartner == "" {
            self.sendAlert("Error", message: "Can not connect to chat partner")
        }
        let username = NSUserDefaults.standardUserDefaults().stringForKey("username")! as String
        let myUrl = NSURL(string: "http://www.neverforgottenbbq.com/gfg/getMessagesForCurrentChat.php")
        let request = NSMutableURLRequest(URL: myUrl!)
        request.HTTPMethod = "POST"
        let postString = "username=\(username)&chatPartner=\(chatPartner)"
        request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
                let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
                if error != nil {
                    print("Error: \(error)")
                }
                dispatch_async(dispatch_get_main_queue()) {
                    if responseString !== "" {
                        self.messageStringRecords = responseString!.componentsSeparatedByString("3292985383")
                        for index in self.messageStringRecords {
                            let indexSplit = index.componentsSeparatedByString("9254203598")
                            let theMessage = indexSplit[0]
                            let theNewMessagePre = theMessage.stringByReplacingOccurrencesOfString("039254space925403", withString: " ")
                            let theNewMessage = theNewMessagePre + "203598123589\(String(indexSplit[3]))"
                            newMessages.addObject(self.EnigmaMachine.decrypt(theNewMessage))
                        }
                        self.messages = []
                        for i in newMessages {
                            self.messages.addObject(i)
                        }
                        self.tableBackgroundInc = 1
                        self.tableView.reloadData()
                    } else {
                        self.messages = []
                        self.messages.addObject("No messages")
                        self.tableView.reloadData()
                    }
                }
            }
        }
        task.resume()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().addObserverForName(
            UIApplicationUserDidTakeScreenshotNotification,
            object: nil,
            queue: NSOperationQueue.mainQueue())
            {
                notification in
                2
                let chatPartner = self.friendChosen
                let username = NSUserDefaults.standardUserDefaults().stringForKey("username")! as String
                let theMessage = "I took a screenshot. I am sorry that I cannot be trusted :("
                let messageTextPreOne = self.EnigmaMachine.encrypt(theMessage)
                let messageTextPreTwo = messageTextPreOne.stringByReplacingOccurrencesOfString(" ", withString: "039254space925403")
                let messageText = self.voidInvalidCharacters(messageTextPreTwo)
                if messageText != "" {
                    let secretKey = "00000"
                    let myUrl = NSURL(string: "http://www.neverforgottenbbq.com/gfg/sendMessage.php")
                    let request = NSMutableURLRequest(URL: myUrl!)
                    request.HTTPMethod = "POST"
                    let postString = "secretKey=\(secretKey)&username=\(username)&chatPartner=\(chatPartner)&message=\(messageText)"
                    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
                    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
                        data, response, error in
                        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
                            _ = NSString(data: data!, encoding: NSUTF8StringEncoding) // lazy responseString: NSString
                            if error != nil {
                                print("Error: \(error)")
                            }
                            dispatch_async(dispatch_get_main_queue()) {
                                //print(responseString)
                            }
                        }
                    }
                    task.resume()
                } else {
                    self.sendAlert("Error", message: "You cannot send a blank message")
                }
        }
        self.receivedUsername = friendChosen
        self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
        let swipe: UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "dismissKeyboard")
        swipe.direction = UISwipeGestureRecognizerDirection.Down
        self.view.addGestureRecognizer(swipe)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
        self.messages.addObject("Loading......")
        refreshTable()
        print("this is a test")
    }


    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: Selector("refreshTable"), userInfo: nil, repeats: true)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()

    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
        timer.invalidate()
    }
} 

Thank you very much for the help,
Nick

Upvotes: 2

Views: 10869

Answers (5)

Vivek
Vivek

Reputation: 5213

Swift 3.0

You just need to add UITableViewDelegate and UITableViewDataSource

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource

Below image is just for your reference.

enter image description here

Upvotes: 4

Ruchin Somal
Ruchin Somal

Reputation: 1103

This is change in Xcode 8.0

class chatViewController: UIViewController {

change this line to this

class chatViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

Upvotes: 1

Daniel T.
Daniel T.

Reputation: 33967

I just got bit by this myself and figured it out... chatViewController is not marked as implementing the UITableViewDataSource protocol.

This is new behavior for Swift 3.

Change the line:

class chatViewController: UIViewController {

to:

class chatViewController: UIViewController, UITableViewDataSource {

And the code will work.

Upvotes: 16

App Dev Guy
App Dev Guy

Reputation: 5536

This uncommon mistake also occurs when you haven't given your reusable cell an identifier but you are trying to reference it in your class.

// Set the cell to be the custom cell
let cell : CustomCell! = tableView.dequeueReusableCellWithIdentifier("cell") as? CustomCell

rookie mistakes

Upvotes: 3

rmaddy
rmaddy

Reputation: 318824

The error is essentially saying that it can't get a cell for the table view. This means you are returning nil from cellForRowAtIndexPath.

But you have such a method and as written it can't return nil. The problem is that your cellForRowAtIndexPath function is embedded in another function. It can't be. Make sure all of your table view data source and delegate functions are top-level functions in the class.

Upvotes: 4

Related Questions