2

I am having a strange problem. I am trying to assign a dataSource to a table programatically.

I have created a UITableView and an IBOutlet for it in my ViewController using the Interface Builder. I have created a class that implements UITableViewDataSource. I set the dataSource of my table to be an instance of the dataSource. Everything compiles and runs fine, until the line that sets the dataSource is executed in runtime.

The error is Thread 1: EXC_BAD_ACCESS (code=EXC_i386_GPFLT) and the class AppDelegate definition line is highlighted.

class ViewController: UIViewController {

    @IBOutlet weak var table: UITableView!

    override func viewDidLoad() {
        let ds = MyData()
        table.dataSource = ds // <---- Runtime error
        table.reloadData()
        super.viewDidLoad()
    }
    // ... other methods
}


class MyData: NSObject, UITableViewDataSource {
    func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
        return 5
    }
    func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
        let cell = UITableViewCell()
        cell.textLabel.text = "a row"
        return cell
    }
}

Any ideas why I am getting this runtime error? I am using XCode 6 beta 4 with Swift.

4
  • 2
    What error are you getting? Commented Aug 1, 2014 at 8:09
  • 2
    the dataSource delegate is usually a weak property, and you are not keeping your ds alive with a strong pointer outside of the scope, so that will be released immediately when the –viewDidLoad() runs out of its own scope... that may cause your problem here. Commented Aug 1, 2014 at 8:25
  • 1
    @holex I was thinking exactly the same. The solution is to move the line: let ds = MyData() out of the viewDidLoad, just below IBOutlet weak var table:UItableView Commented Aug 1, 2014 at 8:33
  • Thanks @holex and @Greg. Yes, that was the reason. So, is it meaningful to say that the we are setting table.dataSource by reference, not by value? If it was set by value would the code have worked? Commented Aug 1, 2014 at 8:54

1 Answer 1

17

Change your code to:

class ViewController: UIViewController 
{
    @IBOutlet weak var table: UITableView!
    var dataSource: MyData?

    override func viewDidLoad() 
    {
        super.viewDidLoad()

        dataSource = MyData()
        table.dataSource = dataSource!
    }
}

Your app breaks because the ds is deallocated as soon as viewDidLoad returns. You have to keep a reference to your data source.

Sign up to request clarification or add additional context in comments.

4 Comments

saved my day. any particular reason why it only works if you declare it as a global variable?
@user431791 UITableView's dataSource is weak so there must a strong reference somewhere, in this case the class variable
makes perfect sense @SteveKuo
@user431791 it is a bit late, and maybe you understand it now, but this is not a global variable. This is an instance variable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.