问题
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
回答1:
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.
回答2:
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.
回答3:
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.
回答4:
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
回答5:
This is change in Xcode 8.0
class chatViewController: UIViewController {
change this line to this
class chatViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
来源:https://stackoverflow.com/questions/34360088/ios-failed-to-obtain-a-cell-from-its-datasource