Button action in swift 3 throwing error when not using storyboard

Good day - I've been trying to create a simple collectionview with a button and an action to a function programatically without using storyboards.


When I click on the button xcode throws an error to the AppDelegate file and if I continue it then ends as a SIGABRT with NSException in the debugger. I can't figure out why, is it perhaps an issue with adding a button to a collectionview and how the button's action is assigned? Need help please - I've posted the AppDelegate, ViewController and ViewCell below:


AP:

@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

window = UIWindow(frame: UIScreen.main().bounds)

window?.makeKeyAndVisible()

let busSearchController = ViewController(collectionViewLayout: UICollectionViewFlowLayout())

let navigationController = UINavigationController(rootViewController: busSearchController)

window?.rootViewController = navigationController

return true

}

}


VC:

class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

let cellId = "cellId"


override func viewDidLoad() {

super.viewDidLoad()

navigationItem.title = "Testing button press"

collectionView?.backgroundColor = UIColor.init(white: 0.95 , alpha: 1)

collectionView?.register(TestViewCell.self, forCellWithReuseIdentifier: cellId)

}


override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

print("selected")

}


override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

return 1

}


override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)

return cell

}


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

return CGSize(width: view.frame.width, height: 515)

}


override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

super.viewWillTransition(to: size, with: coordinator)

collectionView?.collectionViewLayout.invalidateLayout()

}

}


ViewCell:

class TestViewCell: UICollectionViewCell {


override init(frame: CGRect) {

super.init(frame: frame)

setupViews()

}

required init?(coder aDecoder: NSCoder) {

fatalError("init(coder:) has not been implemented")

}

let myButton: UIButton = {

let button = UIButton()

button.backgroundColor = UIColor.green()

button.setTitle("Test Button", for: [])

button.addTarget(TestViewCell.self, action: Selector(("handleLabelPress:")), for: .touchUpInside)

return button

}()

func handleLabelPress(sender:UIButton) {

print("label pressed")

}

func setupViews() {

backgroundColor = UIColor.white()


addSubview(myButton)

addConstraintsWithFormat(format: "H:|-14-[v0]-14-|", views: myButton)

addConstraintsWithFormat(format: "V:|-14-[v0(30)]", views: myButton)

}

}

Answered by Beast in 161804022

The problem is with this line:

button.addTarget(TestViewCell.self, action: Selector(("handleLabelPress:")), for: .touchUpInside)


TestViewCell.self is a class, not an instance of a class.


You need to refactor your button initialization code and use self instead.

Accepted Answer

The problem is with this line:

button.addTarget(TestViewCell.self, action: Selector(("handleLabelPress:")), for: .touchUpInside)


TestViewCell.self is a class, not an instance of a class.


You need to refactor your button initialization code and use self instead.

OK I see now - Thanks! I've updated the code with the change - first had to downclass to TestViewCell and then added the action with the correct Swift 3 syntax. Works now 🙂


override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! TestViewCell

cell.myButton.addTarget(self, action: #selector(handleLabelPress), for: .touchUpInside)

return cell

}

func handleLabelPress(sender:UIButton) {

print("label pressed")

}

Button action in swift 3 throwing error when not using storyboard
 
 
Q