In my project I work with CAlayers. ARC is enabled. In viewDidLoad I'm implementing all my layers and their s contents:
CALayer *tipLayer = [CALayer layer];
tipLayer.frame = CGRectMake(20, 510, 220, 30);
tipLayer.contents = (__bridge id)[UIImage imageNamed:#"tipBackground.png"].CGImage;
[tipLayer setOpacity:0.7f];
[[self.view layer] addSublayer:tipLayer];
This is one of my layers. After implementation my app's memory grow from 9Mb to 12Mb. But after [self.navigationController popViewControllerAnimated:YES]; memory stay with value 12Mb.
I already tried -[UIImage imageWithContentsOfFile:] instead [UIImage imageNamed:] but it doesn't work. How can I resolve this problem?
Related
I have a UIImageView with an array of images it iterates through to form an animation.
[imageView setAnimationImages:arrayOfImages];
I now need to move this image view along a path whilst it is animating. I had a look through the source code of this example. It uses UIBezierPath to create the path and CALayer to represent the object that moves along the path. But how would I do this for a animating UIImageView?
Many thanks for any advice.
[EDIT] Please note I also had to add the UIImageView as a subview to the current view.
Finally figured it out using the example I gave before. Here are my steps:
Create the path. (note P = CGPointMake in the code below)
UIBezierPath *trackPath = [UIBezierPath bezierPath];
[trackPath moveToPoint:P(160, 25)];
[trackPath addCurveToPoint:P(300, 120)
controlPoint1:P(320, 0)
controlPoint2:P(300, 80)];
[trackPath addCurveToPoint:P(80, 380)
controlPoint1:P(300, 200)
controlPoint2:P(200, 480)];
....
Create the UIImageView and give it an array of animation images.
UIImageView *test = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
[test setAnimationImages:[NSArray arrayWithObjects:[UIImage imageNamed:#"bee-1"],
[UIImage imageNamed:#"bee-2"], nil]];
[test startAnimating];
Set the UIImageView's layer position and add the layer to the view's layer:
[test.layer setPosition:P(160,25)];
[self.view.layer addSublayer:test.layer];
Create the CAKeyframeAnimation:
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
anim.path = trackPath.CGPath;
anim.rotationMode = kCAAnimationRotateAuto;
anim.repeatCount = HUGE_VALF;
anim.duration = 8.0;
[test.layer addAnimation:anim forKey:#"race"];
The Instruments tool reports memory leak for CALayer. I have a custom class, a subclass of UIViewController; in the viewDidLoad() I instantiate a view with CAGradientLayer and insert this view as a subview of current view, e.g.:
UIControl *view = [[[UIControl alloc] initWithFrame:CGRectMake(10, 10, 460, 220)] autorelease];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor whiteColor] CGColor], (id)[[UIColor colorWithRed:0.85 green:0.85 blue:0.85 alpha:1.0] CGColor],nil];
gradient.startPoint = CGPointMake(0, 0);
gradient.endPoint = CGPointMake(1, 1);
[view.layer insertSublayer:gradient atIndex:0];
view.layer.masksToBounds = YES;
[view.layer setCornerRadius:5];
[self.view insertSubview:view atIndex:1];
When I run the code in simulator, all is fine. However when I run it on device (iOS 4.3.3), the Instruments tool reports leaks for CALayer. When I coment out this code, there are no leaks.
What is the issue here?
Edit: I found out it only leaks if I insert the subview into a view which has a scrollview (so my subview with the gradient calayer is inserted between the view and scrollview).
release the
uiview and
layer
because simulator runs in system configuration so no problem will occur
but the device has less memory compared to system
I have a scroll view which has one UIView inside which contains the content. I am adding a UIImageView as a sub of the UIScrollView (so it should be on top of the content container) and this works on iPhone 3.2+, but on an iPhone running 3.1.3 the image does not show up above the container. My code is something like this:
// add the content container
UIView *contentContainer = [[UIView alloc] init];
[scrollView addSubview:contentContainer];
// add content, etc
// this works in 3.2+
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[scrollView addSubview:imageView];
// tried adding this for 3.1, but still didn't work
[scrollView bringSubviewToFront:imageView];
[imageView setFrame:CGRectMake(point.x, point.y, image.size.width, image.size.height)];
Is there something else that I'm missing? Thanks!
Are you also actually setting the contentSize property of the UIScrollView ?
Found the issue: when I specified the image name, I was not specifying the image extension:
UIImage *image = [UIImage imageNamed:#"myImage"];
If I change this to the following, it works:
UIImage *image = [UIImage imageNamed:#"myImage.png"];
Does iOS know to still look for the "#2x" version if available when the extension is present by chance?
I have been looking into ways of masking images on the iPhone. I came across this solution
http://iosdevelopertips.com/cocoa/how-to-mask-an-image.html
which works great for still images. What I want to do is mask an animation in a UIImageView. From what I have read I don't think this is possible whilst also achieving a decent frame rate.
This leads me to ask whether the following is possible, could I "clip" the images inside the UIImageView? ie not re-size the UIImageView to the size of the images so some parts are chopped off?
I haven't tried this for performance, but you can use a Core Animation layer as a mask. You can define a path to use in a CAShapeLayer and fill the shape. Then specify the layer mask of your UIImageView's layer. Something like:
CGMutablePathRef path = CGPathCreateMutable();
// build the path by adding points
// ...
CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
[shapeLayer setPath:path];
[shapeLayer setFillColor:[[UIColor blackColor] CGColor]];
// Set shape layer bounds and position
// ...
// Set the mask for the image view's layer
[[imageView layer] setMask:shapeLayer];
Keep in mind that this isn't actually creating a new image as the link you reference does. This just creates a mask for display over top of your image view--which may not be what you want.
I searched high and low and finally found a solution with practically no limitations at all. So, here you go:
UIImageView *maskeeImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"MaskeeImage.png"]];
[maskeeImage setAnimationRepeatCount:-1];
[maskeeImage setAnimationImages:[[NSArray alloc] initWithObjects:[UIImage imageNamed:#"MaskeeImage1.png"], [UIImage imageNamed:#"MaskeeImage2.png"], [UIImage imageNamed:#"MaskeeImage3.png"], nil]];
[maskeeImage startAnimating];
CALayer *maskeeLayer = [maskeeImage layer];
maskeeLayer = CGRectMake(0, 0, 768, 1004);
[[[self view] layer] addSublayer:maskeeLayer];
UIImage *maskImage = [UIImage imageNamed:#"ImageMask.png"];
CALayer *maskLayer = [CALayer layer];
maskLayer.contents = (id) myImageMask.CGImage;
maskLayer.frame = CGRectMake(0, 0, 768, 1004);
[maskeeLayer setMask:maskLayer];
There you go! It's actually really easy, once you know how. I tried to show a few different options; Using UIImageViews or UIImages, Animations (Which can also be used for the mask).
To sum it all up, you basically have to set the mask property on your view's CALayer. Every UIView subclass has a CALayer attached to it, so you aren't restricted at all in terms of where you get your mask or maskee from.
Hope this helped. Cheers, Dylan.
According to the Mac Dev Center docs, you should be able to set the contents property of a CALayer and have that render automatically. However, I still can't get a simple image to show up by adding a sublayer to the UIView's root later. I've tried multiple different variations; here's what I have so far:
(Note: I know there are other ways of rendering images; for my purposes I'd like to use CALayer's for some of the more complicated stuff I'm going to get into).
(in viewDidDisplay() of the ViewController):
CALayer *theLayer = [CALayer layer];
[[[self view] layer] addSublayer:theLayer];
theLayer.contents = (id)[[UIImage imageNamed:#"mypic.png"] CGImage];
theLayer.contentsRect = CGRectMake(0.0f, 0.0f, 300.0f, 300.0f);
theLayer.bounds = CGRectMake(0.0f, 0.0f, 300.0f, 400.0f);
Anyone know what I'm doing wrong?
Thanks!
You could load the image into a UIImageView, which is decended from UIView and therefore has it's own layer property.
UIImageView *imgView = [[UIImageView alloc] initWithFrame:frame];
imgView.image = [UIImage imageNamed:#"mypic.png"];
[[[self view] layer] addSublayer:[imgView layer]];
[imgView release];
You don't need to set the contentsRect (and if you do, it should be in the unit coordinate space, probably just CGRectMake(0, 0, 1.0, 1.0).
You might want to set the layer's position property.
You need to create two CALayer . This is perfect way to display the image within the CALayer.
CALayer *pulseLayer_ = [[CALayer layer] retain];
pulseLayer_.backgroundColor = [[UIColor whiteColor] CGColor];
pulseLayer_.bounds = CGRectMake(0., 0., 80., 80.);
pulseLayer_.cornerRadius = 12.;
pulseLayer_.position = self.view.center;
[self.view.layer addSublayer:pulseLayer_];
CALayer *imageLayer = [CALayer layer];
imageLayer.frame = pulseLayer_.bounds;
imageLayer.cornerRadius = 10.0;
imageLayer.contents = (id) [UIImage imageNamed:#"jacklogo.png"].CGImage;
imageLayer.masksToBounds = YES;
[pulseLayer_ addSublayer:imageLayer];
[pulseLayer_ setNeedsDisplay];
I think its make solution to your problem.