Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift set delegate to self gives EXC_BAD_ACCESS

I'm going through and learning Swift by porting an existing application. I'm stuck on setting a delegate and cannot work out what the issue is.

I have a class which extends UITableViewCell

import UIKit

protocol SwitchCellDelegate{
    func switchChanged(switchCell: SwitchCell, state: Bool)
}

class SwitchCell: UITableViewCell {

    @IBOutlet var swtSelector: UISwitch
    @IBOutlet var lblTitle: UILabel

    var delegate: SwitchCellDelegate?

    init(style: UITableViewCellStyle, reuseIdentifier: String) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    @IBAction func switchChanged(){
        delegate?.switchChanged(self, state: swtSelector.on)
    }

}

Then in the ViewController is defined as

class SettingsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SwitchCellDelegate {

and within the method

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {

we have

case 2:
    storeCredentialsCell = tableView.dequeueReusableCellWithIdentifier("StoreCredentialsCell") as? SwitchCell
    if(storeCredentialsCell != nil){
        ...
        NSLog("Setting delegate to %@ for %@", self.description, storeCredentialsCell.description)
        storeCredentialsCell!.delegate = self
        ...
    }

the log output is as expected but when it hits the actual setting of the delegate the app crashes with

EXC_BAD_ACCESS(code=1, address=0xfffffffffffffff8)

I should also note that if I don't set the delegate value when delegate?.switchChanged(self, state: swtSelector.on) fires it also causes an EXC_BAD_ACCESS error but according to the doco for delegates this should fail gracefully if delegate is not set to anything.

===========================

I've simplified down to a basic project to replicate the issue.

TestTableViewController.swift

import UIKit

class TestTableViewController: UITableViewController, TestCellDelegate {

    init(style: UITableViewStyle) {
        super.init(style: style)
    }

    init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func numberOfSectionsInTableView(tableView: UITableView?) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
        let cell = tableView!.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as? TestCell

        if(cell != nil){
            cell!.delegate = self
            cell!.lblTest.text = "Test Successful"
        }

        return cell
    }

    func eventFired(sender: TestCell) {
        NSLog("Hooray!")
    }

TestCell.swift

import UIKit

protocol TestCellDelegate{
    func eventFired(sender: TestCell)
}

class TestCell: UITableViewCell {

    @IBOutlet var lblTest: UILabel
    @IBOutlet var swtTest: UISwitch

    var delegate: TestCellDelegate?

    init(style: UITableViewCellStyle, reuseIdentifier: String) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    @IBAction func switchChanged(sender: UISwitch){
        delegate?.eventFired(self)
    }
}

I then created a single Table View Controller Scene with Class of TestTableViewController. The table view is dynamic with a single cell of type TestCell. That cell contains one label and one switch which are bound to the IBOutlets from the TestCell class. The switchChanged function is bound to the value changed event on the switch.

Same EXC_BAD_ACCESS error is thrown.

like image 345
Moth Avatar asked Jun 10 '14 04:06

Moth


2 Answers

Currently you have to explicitly mark your protocols with @objc if the delegate should be an Object of a Objective-C class (Like the UITableViewController):

@objc protocol SwiftProtocol

This will enable interoperating with Objective-C

like image 53
Jayman Avatar answered Nov 16 '22 12:11

Jayman


And now for the solution....

@objc protocol SwitchCellDelegate

instead of

protocol SwitchCellDelegate
like image 42
Moth Avatar answered Nov 16 '22 11:11

Moth