Efficiently Modifying CGColor - iphone

I have an iPhone app where I'm "adding" a lot of CGColors together by breaking them down into their components, averaging the components, and then making a new color with the new components. When I run this code, Instruments finds that I'm leaking lots of CGColors, and the app runs slowly.
I feel like I could solve the memory leak issue if there were a way to do what I'm doing without using CGColorCreate(colorspace, components) every time.
This is the code for the color "adding"
const CGFloat *cs=CGColorGetComponents(drawColor);
const CGFloat *csA=CGColorGetComponents(add->drawColor);
CGFloat r=(cs[0]*w+csA[0]*aW)/1;
CGFloat g=(cs[1]*w+csA[1]*aW)/1;
CGFloat b=(cs[2]*w+csA[2]*aW)/1;
CGFloat components[]={r, g, b, 1.f};
drawColor=CGColorCreate(CGColorSpaceCreateDeviceRGB(), components);
Any help would be really appreciated, even if the help is "add the colors less often." I'm sure I'm not the only person trying to modify CGColors.
EDIT: So, rob's comment put me on the right track, but I'm getting malloc double free errors because the method with the color adding is called multiple times before a new drawColor is assigned. Is there a way to check whether drawColor exists before I release it? Here is the new relevant code.
CGColorSpaceRef colorSpace=CGColorSpaceCreateDeviceRGB();
CGColorRelease(drawColor);
drawColor=CGColorCreate(colorSpace, components);
CGColorSpaceRelease(colorSpace);

Pretty sure you just need to CGColorRelease(drawColor) to prevent the leak. See how that helps your performance.

If you're leaking CGColor objects, the first step to solving your problem is to stop leaking them. You need to call CGColorRelease when you're done with a color object. For example, you are obviously leaking the drawColor object in your example code. You should be doing this:
CGColorRelease(drawColor);
drawColor=CGColorCreate(CGColorSpaceCreateDeviceRGB(), components);
to release the old object referenced by drawColor before you assign the new object to drawColor.
CGColor objects are immutable, so you won't be able to just modify your existing objects.

Related

Core Text Memory allocation issue

I inspected my app with the allocation instrument and I discovered that this code down here cause me an allocation issue. The method returns the suggested height of a squared area filled with the passed attributed string; I need this in order to calculate how much space I need to draw that text and then generating book pages:
- (CGFloat)boundingHeightForWidth:(CGFloat)inWidth ForAttributedString:(NSAttributedString *)attributedString
{
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFMutableAttributedStringRef)attributedString);
CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(inWidth, 10000), NULL);
CFRelease(framesetter);
return suggestedSize.height ;
}
Since I am calling this method many and many times during the flow, I am wondering how this is causing up to 7MB of memory allocation.. I thought releasing the frame setter could be enough, am I wrong?
I did some detailed debugging WRT to this issue, you can find the results in my answer to this question. There are a couple of things you could try. 1, does you app do these allocations in a secondary thread, if yes then does moving them to the main thread make the lost memory go away? Two, you could hold on to the CTFramesetterRef and then invoke CTFramesetterSuggestFrameSizeWithConstraints over and over with the same framesetter. The leak appears to be in the CTFramesetterCreateWithAttributedString() call, so perhaps you could minimize the leak by not invoking that method so many times.

Do NSMutableAttributedString addAttribute methods retain the passed in value?

For example is the following code memory safe?
NSMutableAttributedString *str = ...;
CTFontRef aFont = CTFontCreateWithName((CFStringRef)fontName, size, NULL);
[str addAttribute:(NSString*)kCTFontAttributeName value:(id)aFont range:range];
CFRelease(aFont);
Also, is CTFontCreateWithName efficient to call multiple times or should some effort be made to cache CTFontRef's for the same font/size?
I believe it is safe to release the font object after adding it as an attribute. I have done so in my own Core Text code and never have any issues.
As for caching, it would make sense to keep a font object around if it will be used multiple times rather than releasing it and recreating it many times. Though, this is likely pre-optimisation, so I wouldn't make any conscious effort just yet. Profile it with your current code and decide whether or not the extra microseconds will be worth the work.

Unable to release a CGContextRef (context is from a CGLayer)

When you create a CGLayer like so, and then get the context...it appears to be impossible to release the CGContextRef?
Releasing the CGLayerRef itself (apparently) works fine.
You'd think you could release the CGContextRef just before releasing the CGLayer - but no? Nor can you release the CGContextRef just after releasing the CGLayer.
If you release the CGContextRef, the app crashes.
CGLayerRef aether = CGLayerCreateWithContext(
UIGraphicsGetCurrentContext(), CGSizeMake(1024,768), NULL);
CGContextRef weird = CGLayerGetContext(aether);
// paths, strokes, filling etc
// paths, strokes, filling etc
// try releasing weird here
CGLayerRelease(aether);
// or, try releasing weird here
Does anyone know what is going on here? (Note further that CGContextRelease is indeed just the same as CFRelease, with some nil checking.)
In fact should you never manually release CGContextRef? Does anyone know? Cheers.
CGContextRelease(weird); // impossible, not necessary, doesn't work???
Regarding Joel's spectacular answer below:
Is releasing the CGLayerRef correct and proper? Joel has pointed out:
"Yes, since the function you're obtaining it from has 'Create' in its signature. See: documentation/CoreFoundation/"
You do not own the context returned from CGLayerGetContext, and so should not release it*. In particular, see http://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/writerid/cfGetRule for information regarding 'Get' functions in Core Foundation.
*: at least, you shouldn't release it given your example code. If you retained it first (CGContextRetain(weird)), then you should have a CGContextRelease to balance it.

What's making NSArray access so slow?

I'm working up a graphics effect for an iPhone app that simulates a low-res plasma effect from old demoscene days. I've got 600 squares on screen that are updating as fast as possible. Since I am using CoreGraphics (for now), I can get a very constant 11FPS with no freezing--
BUT when I try to add one simple NSArray lookup, the iPhone as well as the simulator freezes for several seconds every few seconds. I've run this in instruments and it says there is a leak -- the leak has to do with NSAutoReleasePool, but that doesn't really help. (I am creating an NSAutoReleasePool at the beginning of every update frame and draining the pool at the end.)
By process of elimination, I've been able to narrow it down to one line that's causing the slowdown. This line happens for each of the 600 block sprites each frame update:
//SLOOWWWNESS /LEAKING NSAUTORELEASEPOOL IS here (freezing every second or so)
UIColor *color = [palette objectAtIndex:colorNum];
//BUT DOESNT HAPPEN HERE... (works at full speed)
UIColor *color = [UIColor colorWithRed:0.25f green:0.25f blue:colorNum/15.0 alpha:1.0f];
... where palette is a NSArray property in the sprite, and contains a list of UIColor objects that I've created. This array of UIColor objects is created only once, when the app launches, and all sprites are using the same array.
Anyone have any ideas?
What is colorNum? Could it ever be some crazy value outsides the array's bounds?
Is palette a 'retain' property... the palette object really has been retained, right? Is it synthesized, or have you implemented your own getPalette method?

Objective-C Sprite Class (iPhone SDK)

Okay, just for starters, I am very new to Objective-C, (C in general). I am not new to programming, and I've found the transition seamless so far, until now. I'm trying to implement a Sprite class I found online in order to develop a game on the iPhone, but I'm getting many errors. For example...
size = CGSizeMake([image size].width , [image size].height);
Where size is a CGSize object, synthesized and image is a UIImage object, synthesized. They are both declared in the Sprite.h file. The error I'm getting is "incompatible types in this assignment". Any help would be greatly appreciated. I feel as though the error is something simple, like an #include or something because every error has to do with a CoreGraphics function (CGRectMake, CGSizeMake, CGRectIntersectRect, etc.). I didn't know if I should post the entire class here, but I'll be happy to if requested to.
When you say "size" is a CGSize object, I think you have a misunderstanding. CGSize is a regular C structure, and CGSizeMake returns a "CGSize" not a "CGSize *". My guess is that "size" is declared as "CGSize *" because you thought it was an object. Try removing the *.