5

I am configuring my BEMSimpleLineGraph and have been able to do so successfully except for the linear gradient shading. After referencing this code in the provided example Obj-C project

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    size_t num_locations = 2;
    CGFloat locations[2] = { 0.0, 1.0 };
    CGFloat components[8] = {
        1.0, 1.0, 1.0, 1.0,
        1.0, 1.0, 1.0, 0.0
    };
    self.myGraph.gradientBottom = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations);

and transcribing it to this in Swift:

let colorspace:CGColorSpaceRef = CGColorSpaceCreateDeviceRGB()
        let num_locations:size_t = 2
        var locations: [CGFloat] = [0.0, 1.0]
        var components: [CGFloat] = [
            1.0, 1.0, 1.0, 1.0,
            1.0, 1.0, 1.0, 0.0
        ]

       self.myGraph.gradientBottom = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations)

everything builds correctly but throws up the EXC_BAD_ACCESS memory error in the BEMLine.m file included, stopping at this line

CGContextDrawLinearGradient(ctx, self.bottomGradient, CGPointZero, CGPointMake(0, CGRectGetMaxY(fillBottom.bounds)), 0);

I've included the obj-c bridging header, added CoreGraphics framework, enabled bottom color in the attributes pane of the respective ViewController in Storyboard, referenced Apple's Development pages to ensure correct data types of all the parameters, but am still coming up dry. In checking for error similarities, I have also realized that the same error comes up with trying to draw the top linear gradient as well. The error seems to lie in the Obj-C code trying to draw the gradient, but again I'm at a loss of what to do.

Dane Jordan
  • 1,071
  • 1
  • 17
  • 27
  • mind sharing the full crash report (`.crash` file)? – Johannes Weiss Mar 29 '15 at 18:17
  • @JohannesWeiß thank you for responding! I uploaded it here for you: (https://drive.google.com/file/d/0ByFqolB5nSXKU1JhYjlYVlpjWTQ/view?usp=sharing) – Dane Jordan Mar 29 '15 at 19:40
  • I had a look and it looks like `self.bottomGradient` is not nil/NULL but is pointing to a bit of memory that doesn't contain a valid gradient. – Johannes Weiss Mar 30 '15 at 10:58
  • not sure what to do with that information to be honest. I found another crash log from the same line but seemingly a different problem. Check it out: [link]https://drive.google.com/file/d/0ByFqolB5nSXKRjV0SUFpbktSOGs/view?usp=sharing – Dane Jordan Mar 31 '15 at 04:55
  • sorry, that wasn't explained very well. So both crashes are due to `NULL` pointers. The first one says `CFRetain() called with NULL` and the second one tries to dereference address `0x0000000000000018`, that's offset 0x18 to the `NULL` pointer. However it doesn't seem like something obvious is just `NULL`, it's more that something within `self.bottomGradient` is NULL. Unfortunately it's hard to tell why that's the case, might be uninitialised memory, might be a pointer to something that's already deallocated, might be something else :-( – Johannes Weiss Apr 01 '15 at 09:58
  • One thing you could try would be to run your program with `NSZombieEnabled=YES`. So just `export NSZombieEnabled=YES; path/to/your/App`. Or in Xcode, Alt/Option click the Run button then click on the Diagnostics tab and tick "Enable Zombie Objects". That'll help debugging should it be an object that's already deallocated and is used after it has been freed. – Johannes Weiss Apr 01 '15 at 10:02

3 Answers3

6

I had the same issue when using BEMSimpleLineGraph from Swift. Luckily I found an answer on the issues page of the libraries Github:

https://github.com/Boris-Em/BEMSimpleLineGraph/issues/105

In order to solve the issue, I just declared a global gradient in the Swift class, like so:

var gradient  : CGGradient?

and just replaced the line

self.myGraph.gradientBottom = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations)

with:

self.gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations)
self.myGraph.gradientBottom = self.gradient

Apparently, the gradient will otherwise not remain allocated in memory and at the time the library needs to use it, it is no longer available.

mjrehder
  • 317
  • 4
  • 11
0

One thing that I note is that in the setup code you use self.myGraph.gradientBottom while in the drawing code you use self.bottomGradient.

Are these supposed to be the same? Or did you forget to assign a value to the latter?

Stefan Arentz
  • 34,311
  • 8
  • 67
  • 88
  • The self.bottomGradient drawing code was the Obj-C pre-provided by the BEMSimpleLineGraph charting library, so I'm not certain that's the issue, but I appreciate the response. – Dane Jordan Mar 31 '15 at 00:47
0

The underlaying reason for this is that Swift & Objective-C handle memory management for Foundation references differently.

In Objective-C, ARC does not manage the retain count of Foundation objects for you. It's the developer's job to call CFRetain/CFRelease where necessary.

In Swift the retain count is managed for you. In fact you can't call CFRetain/CFRelease at all!

When you create the gradient in Swift and assign it directly to the objective-c property no memory management is done. As there are no strong references to it, it's released (not necessary immediately).

In objective-c it will not be nil, so the check will pas, but the gradient would have been released and the memory no longer valid.

The accepted solution works because there is a strong reference - var gradient

Морт
  • 1,163
  • 9
  • 18