MooseMan55 MooseMan55 - 1 month ago 24
Swift Question

UITable pull down to refresh crashes app

Everything seems to load correctly, but when I pull my table view down in my app it crashes and I have no idea why. Am i missing a piece of code?

Heres my viewController code:

import UIKit
import Firebase
import FirebaseDatabase

class FindPartiesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

// where we will store all the parties
var parties = [party]()

@IBOutlet weak var partyTable: UITableView!

var refreshControl = UIRefreshControl()

override func viewDidLoad() {
super.viewDidLoad()

partyTable.delegate = self
partyTable.dataSource = self


set up the refresh control:

self.refreshControl.attributedTitle = NSAttributedString(string: "Pull to refresh")
self.refreshControl.addTarget(self, action: Selector(("refresh:")), for: UIControlEvents.valueChanged)
self.partyTable?.addSubview(refreshControl)

let ref = FIRDatabase.database().reference()

// go to firebase and get all the parties and all there info
ref.child("parties").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
let snapshotValue = snapshot.value as? NSDictionary
let name = snapshotValue?["name"] as! String
let location = snapshotValue?["location"] as! String
let description = snapshotValue?["description"] as! String
let upVotes = snapshotValue?["upVotes"] as! String
let downVotes = snapshotValue?["downVotes"] as! String

self.parties.append(party(name: name, description: description, location: location, upVotes: Int(upVotes)!, downVotes: Int(downVotes)!))

// update the table view to the all the parties
DispatchQueue.main.async {
self.refreshTableData()
}
})

}

// refreshes the table data when called
func refreshTableData(){
// go thru all the parties ansd sort them from postive to negative total votes
for i in (0 ..< self.parties.count) {
let total = self.parties[i].upVotes - self.parties[i].downVotes
if i != 0{
let oldTotal = self.parties[i-1].upVotes - self.parties[i-1].downVotes
if total > oldTotal {
let savedParty = self.parties[i]
self.parties.remove(at: i)
self.parties.insert(savedParty, at:i-1)
}
}
}

self.partyTable?.reloadData()
}

// refreshes the table data when the table is pulled down
func refresh(sender:AnyObject) {
print("REFRESHED")
refreshTableData()
}


Table set up stuff:

// creates the number of cells in the table
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return parties.count
}

// define all the cells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

// Make table cells the show the party
let cell = partyTable.dequeueReusableCell(withIdentifier: "Cell")

let nameLabel = cell?.viewWithTag(1) as! UILabel
nameLabel.text = parties[indexPath.row].name

let locationLabel = cell?.viewWithTag(2) as! UILabel
locationLabel.text = parties[indexPath.row].location

let totalVotesLabel = cell?.viewWithTag(3) as! UILabel
totalVotesLabel.text = (String(parties[indexPath.row].upVotes - parties[indexPath.row].downVotes))

return cell!
}

}


UPDATE:

The error message I get:

2016-11-07 19:00:58.625 Lit[6530:1248106] -[Lit.FindPartiesViewController refresh:]: unrecognized selector sent to instance 0x7fe618d2e230
2016-11-07 19:00:58.638 Lit[6530:1248106] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Lit.FindPartiesViewController refresh:]: unrecognized selector sent to instance 0x7fe618d2e230'
*** First throw call stack:
(
0 CoreFoundation 0x000000010e82634b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010e28721e objc_exception_throw + 48
2 CoreFoundation 0x000000010e895f34 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x000000010e7abc15 ___forwarding___ + 1013
4 CoreFoundation 0x000000010e7ab798 _CF_forwarding_prep_0 + 120
5 UIKit 0x000000010ec4bb88 -[UIApplication sendAction:to:from:forEvent:] + 83
6 UIKit 0x000000010edd12b2 -[UIControl sendAction:to:forEvent:] + 67
7 UIKit 0x000000010edd15cb -[UIControl _sendActionsForEvents:withEvent:] + 444
8 UIKit 0x000000010f6e9dac -[UIRefreshControl _setRefreshControlState:notify:] + 525
9 UIKit 0x000000010f6f2231 -[_UIRefreshControlModernContentView _snappingMagic] + 53
10 UIKit 0x000000010f6f0c70 -[_UIRefreshControlModernContentView didTransitionFromState:toState:] + 205
11 UIKit 0x000000010f6e9d3d -[UIRefreshControl _setRefreshControlState:notify:] + 414
12 UIKit 0x000000010f6e8b18 -[UIRefreshControl _setVisibleHeight:] + 71
13 UIKit 0x000000010f6e91ea -[UIRefreshControl _update] + 374
14 UIKit 0x000000010ed33f5a -[UIScrollView(UIScrollViewInternal) _notifyDidScroll] + 174
15 UIKit 0x000000010ed1e919 -[UIScrollView setContentOffset:] + 478
16 UIKit 0x000000010eda96b7 -[UITableView setContentOffset:] + 316
17 UIKit 0x000000010ed23351 -[UIScrollView _updatePanGesture] + 2346
18 UIKit 0x000000010f18c289 -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + 57
19 UIKit 0x000000010f194028 _UIGestureRecognizerSendTargetActions + 109
20 UIKit 0x000000010f191af7 _UIGestureRecognizerSendActions + 227
21 UIKit 0x000000010f190d83 -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 891
22 UIKit 0x000000010f17ce56 _UIGestureEnvironmentUpdate + 1395
23 UIKit 0x000000010f17c89b -[UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:] + 521
24 UIKit 0x000000010f17ba7e -[UIGestureEnvironment _updateGesturesForEvent:window:] + 286
25 UIKit 0x000000010ecba7ad -[UIWindow sendEvent:] + 3989
26 UIKit 0x000000010ec67a33 -[UIApplication sendEvent:] + 371
27 UIKit 0x000000010f459b6d __dispatchPreprocessedEventFromEventQueue + 3248
28 UIKit 0x000000010f452817 __handleEventQueue + 4879
29 CoreFoundation 0x000000010e7cb311 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
30 CoreFoundation 0x000000010e7b059c __CFRunLoopDoSources0 + 556
31 CoreFoundation 0x000000010e7afa86 __CFRunLoopRun + 918
32 CoreFoundation 0x000000010e7af494 CFRunLoopRunSpecific + 420
33 GraphicsServices 0x00000001121afa6f GSEventRunModal + 161
34 UIKit 0x000000010ec49f34 UIApplicationMain + 159
35 Lit 0x000000010c419b3f main + 111
36 libdyld.dylib 0x0000000110e6d68d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

Answer

Since you're not using the sender, just remove it.

func refresh() {
     print("REFRESHED")
     refreshControl?.endRefreshing()
     refreshTableData()
}

Then when adding the target to the refresh control, don't bother with the : after the refresh selector (since you removed the sender parameter).

Also by using #selector(refresh) instead of Selector("refresh"), you will know if the selector is recognized before compiling.

self.refreshControl.addTarget(self, action: #selector(refresh), for: .valueChanged)