Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView Unit Test Bad Access on dequeueReusableCellWithReuseIdentifier

To summarize my problem I am trying to test a collection view's data source. I Initialize a view controller and call viewDidLoad() to initialize the components which initializes a custom class to use as a data source. This is the class that I am testing.

The program starts in a unit test here:

class BubbleViewManagerTest: XCTestCase {

var viewController : DashboardViewController = DashboardViewController()
//var bubbleViewManager : BubbleViewManager = BubbleViewManager()

override func setUp() {
    super.setUp()

    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
    viewController = storyboard.instantiateViewControllerWithIdentifier("DashboardViewControllerId") as! DashboardViewController
    bubbleViewManager = viewController.bubbleViewManager
    viewController.loadView()
    viewController.viewDidLoad()
}

func testCellForItemAtIndexPath() {
    DataManager.singleton.dayActivities = []

    DataManager.singleton.addGoal(Period(name: "asdf", hour: 1, minute: 1, color: UIColor.blackColor(), priority: PeriodPriority.Low))

    var cell = bubbleViewManager.collectionView(viewController.bubbleView, cellForItemAtIndexPath: NSIndexPath(forRow: 0, inSection: 0)) as! BubbleCollectionViewCell

    XCTAssertEqual(cell.bounds.width, 45)
    XCTAssertEqual(cell.bounds.height, 45)
    XCTAssertNotNil(cell.bubbleView.period)

    DataManager.singleton.addGoal(Period(name: "asdf", hour: 1, minute: 1, color: UIColor.blackColor(), priority: PeriodPriority.Medium))
    DataManager.singleton.addGoal(Period(name: "asdf", hour: 1, minute: 1, color: UIColor.blackColor(), priority: PeriodPriority.High))

    var index = NSIndexPath(forRow: 1, inSection: 0)

    cell = bubbleViewManager.collectionView(viewController.bubbleView, cellForItemAtIndexPath: index) as! BubbleCollectionViewCell

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    let period: Period = DataManager.singleton.dayActivities[indexPath.row]
    var cell: BubbleCollectionViewCell = BubbleCollectionViewCell()

    switch period.priority {
        case .High:
            cell = collectionView.dequeueReusableCellWithReuseIdentifier(self.reuseIdentifierHighPriority, forIndexPath: indexPath) as! BubbleCollectionViewCell
            break;
        case .Medium:
            cell = collectionView.dequeueReusableCellWithReuseIdentifier(self.reuseIdentifierMediumPriority, forIndexPath: indexPath) as! BubbleCollectionViewCell
            break;
        case .Low:
            cell = collectionView.dequeueReusableCellWithReuseIdentifier(self.reuseIdentifierLowPriority, forIndexPath: indexPath) as! BubbleCollectionViewCell
    }

    // Give the bubble view the period for it to work on.
    cell.bubbleView.period = period


    // The bubble view needs to monitor a timer to redraw the bubble. Observer is assigned here.
    if let timer = cell.bubbleView.period?.globalTimer {
        timer.observer = cell.bubbleView
    }

    return cell
}

The program breaks on the line cell = collectionView.dequeueReusableCellWithReuseIdentifier(self.reuseIdentifierMediumPriority, forIndexPath: indexPath) as! BubbleCollectionViewCell

I understand an EXC_BAD_ACCESS occurs when an object is accessed after it's autoreleased or when it isn't initialized in the first place. In my case I get the error and have made sure all objects are initialized and their references are strong (not weak). I've enabled NSZombies and had no luck with that.

What is confusing to me is that func collectionView(collectionView:cellForItemAtIndexPath:) -> UICollectionViewCell has executed once already before the thread breaks.

Is this maybe related to the fact I am running on the Test target? This code operates as expected when I run the app on iOS Simulator.

Any help would be greatly appreciated.

like image 815
Steven Williamson Avatar asked Sep 28 '22 12:09

Steven Williamson


1 Answers

This was solved by calling reloadData() after adding new data to test against. When trying to simulate a view controller to test a data source. viewController.collectionView.reloadData() must be called. I never considered this because it is done in the viewDidLoad() call and this was done prior to adding the data.

like image 114
Steven Williamson Avatar answered Oct 13 '22 00:10

Steven Williamson