I am new in iOS development, use xcode 8.2.1 & swift 3. I take uitableview in view controller, in uitableviewcell I take uiimageview when i tap on it app is crash and same issue is occur when I take button and perform button action .
The error is:
sampleToRunBuild[3752:1620857] -[sampleToRunBuild.TapViewController
TappedOnImage:]: unrecognized selector sent to instance 0x141e07bc0
2017-04-13 18:18:00.531126 sampleToRunBuild[3752:1620857] *
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason:
'-[sampleToRunBuild.TapViewController TappedOnImage:]: unrecognized
selector sent to instance 0x141e07bc0'
* First throw call stack: (0x18343d1b8 0x181e7455c 0x183444268 0x183441270 0x18333a80c 0x1898b3f80 0x1898b7688 0x18947e73c
0x18931d0f0 0x1898a7680 0x1898a71e0 0x1898a649c 0x18931b30c
0x1892ebda0 0x189ad575c 0x189acf130 0x1833eab5c 0x1833ea4a4
0x1833e80a4 0x1833162b8 0x184dca198 0x1893567fc 0x189351534
0x100065f30 0x1822f95b8) libc++abi.dylib: terminating with uncaught
exception of type NSException
my code is :
import UIKit
class TapViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "mycell")
let img: UIImageView = cell?.viewWithTag(1) as! UIImageView
let img2: UIImageView = cell?.viewWithTag(2) as! UIImageView
img.tag = indexPath.row
img2.tag = indexPath.row
img.isUserInteractionEnabled = true
img2.isUserInteractionEnabled = true
let tapped:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector(("TappedOnImage:")))
tapped.numberOfTapsRequired = 1
tapped.delegate = self
img.addGestureRecognizer(tapped)
let tapped1:UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector(("TappedOnImage:")))
tapped1.numberOfTapsRequired = 1
tapped1.delegate = self
img.addGestureRecognizer(tapped1)
return cell!
}
func TappedOnImage(sender:UITapGestureRecognizer){
print("tap on imageview")
}
}
Thanks in advance...
add UITapGestureRecognizer like below code
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(tapGestureRecognizer)
func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
let tappedImage = tapGestureRecognizer.view as! UIImageView
// Your action
}
you need to use
#selector(TapViewController.imageTapped(sender:))
If you are using swift 3, don't use Selector() anymore, use the #selector syntax instead.
e.g.
let tapped1:UITapGestureRecognizer =
UITapGestureRecognizer(target: self, action: #selector(TappedOnImage))
The reason why your code did not work is that you forgot to add the argument label sender to selector string. That's one of the disadvantages of using the old syntax - it does not tell you the mistake at compile time. With the new syntax, there will be a compiler error if you wrote the selector incorrectly, and you don't even need to care about argument labels, you just need the name.
Related
Hello I'm trying to figure out how to call a UIButton inside a custom cell within a UItable in storyboard. At the moment I have a library that creates a sidemenu working just fine (more info here) and I can see the button I placed when I launch the simulator. However, when I click on the button the action is not triggered, can you please guide me as to how I can achieve this?
Important to note that the table was create entirely in storyboard.
My work in progress code within TopratedVC.swift to get the button to trigger the action:
override func viewDidLoad() {
super.viewDidLoad()
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewVibrantCell") as! CellClassMenu
cell.sendFeedBackBtn.tag = indexPath.row
cell.sendFeedBackBtn.addTarget(self, action: "sendFeedBackBtnAction:", forControlEvents: .TouchUpInside)
cell.contentView.userInteractionEnabled = false //tried with true as well, no difference
cell.bringSubviewToFront(cell.sendFeedBackBtn)
cell.userInteractionEnabled = true
return cell
}
func sendFeedBackBtnAction(sender: UIButton){
print("sendFeedBackBtnAction tapped")
}
My UITableViewVibrantCell.swift file contains the following:
import UIKit
class UITableViewVibrantCell: UITableViewCell {
#IBOutlet var sendFeedBackBtn: UIButton!
}
My sndFeedBackBtn has a referencing outlet to UITableViewVibrantCellsendFeedBackBtn which has a class of UITableViewVibrantCell. What am I doing wrong? Thank you.
What it looks like in simulator:
In your post, you show a UITableViewVibrantCell class, and dequeue a cell with the "UITableViewVibrantCell" identifier, but cast it as CellClassMenu?
Anyhow, it would be better practice to create a cell delegate for actions, and let your controller decide the implementation, rather than adding a target every time the cell is dequeued. You can do that like so:
UITableViewVibrantCell
import UIKit
protocol UITableViewVibrantCellDelegate: NSObjectProtocol {
func buttonPressed(sender: UIButton)
}
class UITableViewVibrantCell: UITableViewCell {
var delegate: UITableViewVibrantCellDelegate?
#IBOutlet var feedbackButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
feedBackButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .TouchUpInside)
}
func buttonPressed(sender: UIButton) {
delegate?.buttonPressed(sender)
}
}
TopratedVC
class TopratedVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewVibrantCell") as! UITableViewVibrantCell
cell.delegate = self
return cell
}
// MARK: - UITableViewVibrantCellDelegate
func buttonPressed(sender: UIButton) {
print("feedbackButton tapped")
}
}
Selectors ("sendFeedBackBtnAction:") can't pass parameters. And a param isn't needed in the sendFeedBackBtnAction function since you're calling it only for this button. So change I'd change it to simply...
func sendFeedBackBtnAction()
then I'd also recommend changing your selector to a more updated swift version...
cell.sendFeedBackBtn.addTarget(self, action: #selector(sendFeedBackBtnAction), forControlEvents: .TouchUpInside)
My goal is to perform segue when i tap on imageview of that cell. but the error does not appear when i use addTarget on a button.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
cell.imageView.userInteractionEnabled = true
let tapImageView = UITapGestureRecognizer(target: self, action: #selector(HomeFeedViewController.tapImageView(_:)))
cell.imageView.addGestureRecognizer(tapImageView)
return cell as CastleCell
}
func tapImageView(sender: AnyObject) {
let center = sender.center
let point = sender.superview!!.convertPoint(center, toView:self.tableView) //line of error
let indexPath = self.tableView.indexPathForRowAtPoint(point)
let cell = self.tableView.cellForRowAtIndexPath(indexPath!) as! CastleCell
performSegueWithIdentifier("SegueName", sender: self)
}
The line of error is let point =...
The error i get is:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
but the error does not appear when i use addTarget on a button. what could be wrong? thanks.
Am not really fond of playing with points and Superview. What is can suggest is to make a class for UITapGestureRecognizer as follows which can hold extra data. In your case it would be an index path
class CustomGesture: UITapGestureRecognizer {
let indexPath:NSIndexPath? = nil
}
And then in your didSelect you can add the index path to the newly created CustomGesture class which be would be like:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
cell.imageView.userInteractionEnabled = true
let tapImageView = CustomGesture(target: self, action: #selector(HomeFeedViewController.tapImageView(_:)))
tapImageView.indexPath = indexPath// Add the index path to the gesture itself
cell.imageView.addGestureRecognizer(tapImageView)
return cell as CastleCell
}
Now since you have added the indexPath you don't need to play around with super view's and you can access the cell like this:
func tapImageView(gesture: CustomGesture) {
let indexPath = gesture.indexPath!
let cell = self.tableView.cellForRowAtIndexPath(indexPath!) as! CastleCell
performSegueWithIdentifier("SegueName", sender: self)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "ExerciseMenuCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ExerciseOptionTableViewCell
let currentWorkout = workouts[indexPath.row]
cell.nameLabel!.text = currentWorkout.name
cell.photoImageView.image = currentWorkout.filename
cell.startWorkout.tag = indexPath.row
cell.startWorkout.addTarget(self, action:Selector("workoutAction:"), forControlEvents: .TouchUpInside)
cell.infoWorkout.tag = indexPath.row
cell.infoWorkout.addTarget(self, action:Selector("infoAction:"), forControlEvents: .TouchUpInside)
return cell
}
Both startWorkout and infoWorkout cause the application to crash with the error message 'unrecognised selector sent to instance'.
Example of code within the button actions. I am trying to return the indexPath of the button so I can then act on that.
#IBAction func workoutAction(sender: AnyObject) {
let buttonTag = sender.tag
print(buttonTag)
}
exact error message:
016-06-17 18:34:30.722 Exercises[4711:245683] - [Exercises.ExerciseMenu beginWorkout:]: unrecognized selector sent to instance 0x7fb47874a4b0
2016-06-17 18:34:30.727 Exercises[4711:245683] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Exercises.ExerciseMenu beginWorkout:]: unrecognized selector sent to instance 0x7fb47874a4b0'
A button within a custom cell cannot call an action that is in the housing view controller. You need to:
1) Move the #IBaction function to the custom cell class
2) Remove the add target code from 'cellFromRowAtIndexPath' and either write that in your custom cell(if you do this you don't need to write #IBAction) or create the connection from the button in storyboard to the #IBAction function
3) Create a delegate for your custom cell
Custom UITableViewCell delegate pattern in Swift
4) Call the delegate from your custom cell for the function you implement in the view controller
**Don't for get you need cell.delegate = self or it will crash when the delegate gets called
ex:
CustomCell.swift
protocol CustomCellDelegate {
func pressedButton()
}
class CustomCell: UITableViewCell {
var delegate: CustomCellDelegate!
#IBAction func buttonPressed(sender: UIButton) {
delegate.pressedButton()
}
}
ViewController.swift
class CustomClass: UIViewController, CustomCellDelegate {
func pressedButton() {
// Perform segue here
}
}
I want to add a tap gesture to every cell in a UITableView that edits the content in it. The two ways to add a gesture are in code or through storyboard. I tried both and they failed.
Can I add a gesture to every cell in table with storyboard drag and drop? It seems to only add gesture to the first cell. Adding gesture in code, I wrote something like,
addGestureRecognizer(UITapGestureRecognizer(target: self,action:#selector(MyTableViewCell.tapEdit(_:))))
or
addGestureRecognizer(UITapGestureRecognizer(target: self, action:"tapEdit:"))
both work. But I'd like to let the UITableViewController handle this gesture because it does something with the datasource. How do I write my target and action?
EDIT:
addGestureRecognizer(UITapGestureRecognizer(target: MasterTableViewController.self, action:#selector(MasterTableViewController.newTapEdit(_:)))
it induce an error said, unrecognized selector sent to class 0x106e674e0...
To add gesture to UITableViewCell, you can follow the steps below:
First, add gesture recognizer to UITableView
tapGesture = UITapGestureRecognizer(target: self, action: #selector(tableViewController.tapEdit(_:)))
tableView.addGestureRecognizer(tapGesture!)
tapGesture!.delegate = self
Then, define the selector. Use recognizer.locationInView to locate the cell you tap in tableView. And you can access the data in your dataSource by tapIndexPath, which is the indexPath of the cell the user tapped.
func tapEdit(recognizer: UITapGestureRecognizer) {
if recognizer.state == UIGestureRecognizerState.Ended {
let tapLocation = recognizer.locationInView(self.tableView)
if let tapIndexPath = self.tableView.indexPathForRowAtPoint(tapLocation) {
if let tappedCell = self.tableView.cellForRowAtIndexPath(tapIndexPath) as? MyTableViewCell {
//do what you want to cell here
}
}
}
}
It is possible to add gesture directly to TableView cell and access the datasource in viewController, You need to set up a delegate:
In your custom cell:
import UIKit
class MyTableViewCell: UITableViewCell {
var delegate: myTableDelegate?
override func awakeFromNib() {
super.awakeFromNib()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(MyTableViewCell.tapEdit(_:)))
addGestureRecognizer(tapGesture)
//tapGesture.delegate = ViewController()
}
func tapEdit(sender: UITapGestureRecognizer) {
delegate?.myTableDelegate()
}
}
protocol myTableDelegate {
func myTableDelegate()
}
In your viewController:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate, myTableDelegate {
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view, typically from a nib.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 35
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as? MyTableViewCell
cell?.delegate = self
return cell!
}
func myTableDelegate() {
print("tapped")
//modify your datasource here
}
}
However, this method could cause problems, see UIGestureRecognizer and UITableViewCell issue. In this case, when the swipe gesture successes, the selector get called twice for some reason. I can't say the second method is a bad one as I haven't found any direct evidence yet, but after searching through Google, it seems like the first method is the standard way.
You don't need to add gesture recognizer to achieve what you are doing.
Use the UITableViewDelegate method tableView:didSelectRowAtIndexPath: to detect which row is tapped (this is what exactly your tapGesture is going to do) and then do your desired processing.
If you don't like the gray indication when you select cell, type this in your tableView:didEndDisplayingCell:forRowAtIndexPath: just before returning the cell:
cell?.selectionStyle = .None
Adding gesture in awakeFromNib method seems much more easier and works fine.
class TestCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
let panGesture = UIPanGestureRecognizer(target: self,
action: #selector(gestureAction))
addGestureRecognizer(panGesture)
}
#objc func gestureAction() {
print("gesture action")
}
}
The easiest way to do this is to add the gesture in a custom UITableViewCell. An easier alternative to setting up a custom delegate pattern is to inform the view controller of the edits would be to use a handler in the form of a closure that the view controller can provide and which is called when user editing is finished. I'm assuming a textField is used to allow cell editing.
class CustomTableViewCell: UITableViewCell {
func activateTitleEditing() {
textField.isEnabled = true
textField.becomeFirstResponder()
}
// This will hold the handler closure which the view controller provides
var resignationHandler: (() -> Void)?
#objc private func tap(_ recognizer: UITapGestureRecognizer) {
guard recognizer.state == .ended else { return }
activateTitleEditing()
}
#IBOutlet weak var textField: UITextField! { didSet {
textField.delegate = self
let tap = UITapGestureRecognizer(target: self, action: #selector(tap(_:)))
addGestureRecognizer(tap)
textField.isEnabled = false
}}
}
extension CustomTableViewCell: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
resignationHandler?()
}
}
And within your custom UITableViewController, pass in the handler to be able to make changes to your model. Don't forget to account for possible memory cycles in the closure.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// initialize and return table view cell
let cell = tableView.dequeueReusableCell(withIdentifier: K.documentCellIdentifier, for: indexPath)
assert(cell is CustomTableViewCell, "Document cell dequeuing error")
let customCell = cell as! DocumentTableViewCell
customCell.textField.text = documentModel.documents[indexPath.row]
customCell.resignationHandler = { [weak self, unowned customCell] in
guard let self = self else { return }
if let newTitle = customCell.textField.text {
self.cellModel.cells[indexPath.row] = newTitle
}
}
return customCell
}
I am trying to add search capabilities to the map based project I am working on in swift on XCode 6. I have added SearchDisplayController to my main view controller, which contains the map. I created a class called MapSearchDisplayController, which implements necessary methods. I also changed Custom Class property of the SearchDisplayController to MapSearchDisplayController in the storyboard.
In the storyboard, I dragged SearchDisplayController to my main view controller to create an IBOutlet. My main viewDidLoad for the main view controller looks like this:
class ViewController: UIViewController, CCHMapClusterControllerDelegate, MKMapViewDelegate, ADBannerViewDelegate {
#IBOutlet weak var mapSearchDisplayController1: MapSearchDisplayController!
#IBOutlet var mapSearchDisplayController: MapSearchDisplayController!
#IBOutlet weak var banner: ADBannerView!
#IBOutlet weak var mMap: MKMapView!
var clusterController:CCHMapClusterController?
let mMaxZoomLevelForClustering : Double = 13
let mMinUniqueLocationsForClustering : UInt = 1
var formatter = NSNumberFormatter()
var databasePath = NSString()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
banner.delegate = self
// Add button to navbar
var filterButton : UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Organize, target: self, action: nil)
self.navigationItem.leftBarButtonItem = filterButton
var aboutButton : UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Add, target: self, action: "aboutAction")
var searchButton : UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Search, target: self, action: "searchAction")
var rButtons : [UIBarButtonItem] = [aboutButton, searchButton]
self.navigationItem.rightBarButtonItems = rButtons
// Deal with Search Display Controller
self.mapSearchDisplayController.delegate = self.mapSearchDisplayController;
self.mapSearchDisplayController.searchResultsDataSource = self.mapSearchDisplayController;
self.mapSearchDisplayController.searchResultsDelegate = self.mapSearchDisplayController;
self.mapSearchDisplayController.searchBar.placeholder = "Search Destination";
self.mapSearchDisplayController.searchResultsTableView.delegate = self.mapSearchDisplayController
self.mapSearchDisplayController.searchResultsTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
Issue 1: I had to add an additional mapSearchDisplayController1 - otherwise my mapSearchDisplayController was nil and I had an exception when I tried to to use it. Now when I have an additional variable mapSearchDisplayController1 (it is declared, but never used) it is not throwing exceptions and some functionality is working. Tried to add/remove weak, bt it did not make any difference. I can't figure out what have I missed that leads to this behavior.
Isse 2: Even bigger problem that I have, is that the instance variables of mapSearchDisplayController, which handles the search related functionality, are nil, its init method is not being invoked, but the functionality in the delegate methods work. So, data1 variable is nil, despite being initialized to hardcoded string array. Same goes for all other members, including googleAPIKey which is a constant. If shouldReloadTableForSearchString set data1 again data1 = ["1111", "222", "ZAAAA"] then it remains initialized, but if I assign data1 the value I get as a searchresult - it is lost. I would understand if the entire object was nil, but the methods are being invoked and working, it is just an instance variables and init which are not "working". Code below:
class MapSearchDisplayController: UISearchDisplayController, UISearchDisplayDelegate, UITableViewDataSource, UITableViewDelegate, LPGoogleFunctionsDelegate
{
var data1 : [String]! = ["1111", "222", "ZAAAA"]
var googleFunctions : LPGoogleFunctions? = LPGoogleFunctions()
let googleAPIKey = "myKey"
//MARK: UITableViewDelegate
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
println("In numberOfRowsInSection - \(data1.count)")
return self.data1.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
println("In cellForRowAtIndexPath")
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
if !(cell != nil) {
println("new cellForRow")
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
}
// Get the corresponding candy from our candies array
let candy = self.data1[indexPath.row]
// Configure the cell
cell!.textLabel.text = candy
cell!.detailTextLabel?.text = "Cell Details"
return cell!
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
// Dismiss search display controller
self.active = false;
// Force selected annotation to be on map
}
func tableView(tableView: UITableView, numberOfSectionsInTableView indexPath: NSIndexPath) -> Int{
println("numberOfSectionsInTableView")
return 1
}
//MARK: Search methods
func filterContentForSearchText (searchText: String) {
println(searchText)
}
func searchDisplayController(controller: UISearchDisplayController!, shouldReloadTableForSearchString searchString: String!) -> Bool {
var length : Int32 = Int32(countElements(searchString))
if (countElements(searchString) < 3 ) {
println("Short searchString. Not enough info")
return false
}
data1 = []
if (googleFunctions == nil)
{
googleFunctions = LPGoogleFunctions()
googleFunctions!.sensor = false
googleFunctions!.delegate = self
googleFunctions!.googleAPIBrowserKey = "myKey"
}
println(googleFunctions?.googleAPIBrowserKey)
googleFunctions?.loadPlacesAutocompleteWithDetailsForInput(searchString, offset: length, radius: 0, location: nil, placeType: LPGooglePlaceTypeGeocode, countryRestriction: nil, successfulBlock: {(pd : [AnyObject]!) in
println("--------------GOOGLE search success")
for place in pd{
var pl = place as LPPlaceDetails
self.data1.append(pl.name)
println(pl.name)
}
}
, failureBlock: {(status : LPGoogleStatus) in
println("---- GOOGLE failed")
})
//data1 = ["1111", "222", "ZAAAA"]
return true
}
func searchDisplayControllerWillBeginSearch(controller: UISearchDisplayController!){
controller.searchBar.showsCancelButton = true
}
func searchDisplayControllerWillEndSearch(controller: UISearchDisplayController!){
println("searchDisplayControllerWillEndSearch")
}
//MARK: LPGogleFunctions methods
override init() {
println("Initializing GoogleFunctions")
if (googleFunctions == nil){
googleFunctions = LPGoogleFunctions()
}
data1 = []
super.init()
googleFunctions!.sensor = false
googleFunctions!.delegate = self
googleFunctions!.googleAPIBrowserKey = "myKey"
}
}
Any help would be greatly appreciated.
I am answering my own question, in case someone ever has the same problem.
Issue #1 I resolved by deleteing both IBOutlets and re-adding them in the storyboard.
Issued #2: I did not made a call to searchResultsTableView.reloadData().
Since the network call was async, results were received in the lambda after the tableview was updated. Forcing an update sovled the problem.