ShinobiChart inside UICollectionView


#1

Hi,

I want to add a shinobiChart to cell of the UICollectionView. But when I run the app I have this error:   “thread1 : EXC_BAD_ACCESS”.

But if I run only the shinobiChart without UICollectionView this works.

I was missing some thing?

ChartTest.swift

//
// chartTest.swift
//
// 


import UIKit

class ChartTest: UIViewController, SChartDatasource {
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        var chart = ShinobiChart(frame: CGRectMake(0, 0, 370, 200));
        chart.datasource = self;
     // chart.gesturePanType = SChartGesturePanTypeNone;
        self.view.addSubview(chart);
    }
 
    
    /* SChartDatasource methods */
    func numberOfSeriesInSChart(chart: ShinobiChart!) -> Int {
        return 1
    }
    
    func sChart(chart: ShinobiChart!, seriesAtIndex index: Int) -> SChartSeries! {
        return SChartLineSeries()
    }
    
    func sChart(chart: ShinobiChart!, numberOfDataPointsForSeriesAtIndex seriesIndex: Int) -> Int {
        return 100
    }
    
    func sChart(chart: ShinobiChart!, dataPointAtIndex dataIndex: Int, forSeriesAtIndex seriesIndex: Int) -> SChartData! {
        let dp = SChartDataPoint()
        dp.xValue = dataIndex
        dp.yValue = dataIndex * dataIndex
        return dp
    }
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
}







UICollectionView

//
// ViewControllerCollection.swift


import UIKit

public class ViewControllerUICollectionSection: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource{ 
    
    
    public var layoutCollectionView : UICollectionView!

    var apiController : APIController?;
    
    public var sections : [Row]?;
    var screenID : String!;
    var isTest : Bool! = false;
    
    public init(id:String, isTest: Bool){
        self.screenID = id;
        self.isTest = isTest;
       
        super.init(nibName: nil, bundle: nil);
        
        let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        apiController = appDelegate.getAPIController();
        
    }

    required public init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder);
    }


       
    override public func viewDidLoad() {
        super.viewDidLoad()
        self.sections = [Row]();
      
       
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        layout.minimumLineSpacing = 0;
        layout.minimumInteritemSpacing=0;
        layoutCollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        layoutCollectionView.dataSource = self
        layoutCollectionView.delegate = self
        layoutCollectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
        layoutCollectionView.backgroundColor = UIColor.whiteColor()
        self.view.addSubview(layoutCollectionView)
        
        getLayout();
        
    }

    
    override public func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
           
    
    
    func getLayout(){
    
        if isTest == false{
            apiController!.getLayout(self.screenID) { (resultsArr: NSDictionary) in
                self.sections! = LayoutParser.layoutWithJson(resultsArr);
                self.layoutCollectionView.reloadData();
            };
        }

    }
    
    public func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return sections!.count;
    }
    
     public func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return sections![section].panels.count;
    }
    
    
    
    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewFlowLayout,
        sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize{
            
            var widthx = sections![indexPath.section].panels[indexPath.row].width;
            var heightx = sections![indexPath.section].panels[indexPath.row].height;
                       
            return CGSize(width: CGFloat(widthx), height: CGFloat(heightx))
    }
    
    
    public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell{
        
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as UICollectionViewCell
              
        var panelId : String = sections![indexPath.section].panels[indexPath.row].widget.id;
        var widgetType = sections![indexPath.section].panels[indexPath.row].widget.type;
        var widget : Widget = sections![indexPath.section].panels[indexPath.row].widget;
              
        cell.layer.borderWidth = 2;
        cell.layer.borderColor = UIColor.blackColor().CGColor;
       
      
        cell.addSubview(ChartTest().view);//WidgetVCFactory.createWidgetVC(widgetType, widget: widget)!);
        
        return cell
    }
  }

Thanks,


#2

Hi ateresa,

I’ve not had the time to look through your code, but here are some suggestions that will hopefully be useful:

  • The crash happening only when you use a chart in a collection view, but not when you use the chart in isolation makes it sound like there may be an issue with how collection view is being configured.
  • Use the backtrace from the crash to debug where the issue is occuring. Once you know where the crash is occuring in the code you’ll probably have a better idea of how to fix it. 
  • If that fails then try launching your app with some breakpoints in and stepping through to find out where the crash occurs.

I hope that helps! Let us know how you get on! :slight_smile:

Thanks

Ryan


#3

I choosed this solution:

  1. Keep a reference to the view controllers whose views you wish to display in the cells of the collection view.

The following code is a simple view controller that demonstrates this, using your ChartTest view controller. Notice for simplicity that it subclasses UICollectionViewController and that the sizing parameters etc have been set up in a storyboard:

public class ViewController : UICollectionViewController {

let cellVCs = [ChartTest(), ChartTest(), ChartTest()]

public override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {

return 1

}

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

return 3

}

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

let cell = collectionView.dequeueReusableCellWithReuseIdentifier(“Cell”, forIndexPath: indexPath) as UICollectionViewCell

cell.layer.borderWidth = 2;

cell.layer.borderColor = UIColor.blackColor().CGColor;

cell.addSubview(cellVCs[indexPath.item].view);

return cell

}

}

Note that the view controllers are retained in the cellVCs array property.


#4

Thanks for sharing that. I’m glad you managed to find an acceptable solution!