Potential leak of an object allocated on line 89 and stored into imageView
Some code:
NSUInteger i;
for (i = 0; i < kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"BackGround%i.png", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.userInteractionEnabled = YES;
}
And I don't know what to do...
[imageView release];
needs to happen inside that loop after the rest of the code. Although you don't seem to be doing anything with it.
Whatever object you "alloc" you should "release". In this case you have alloced UIImageView, but you have not called release on the object anywhere.
But, that aside what are you doing with the image view object you have created? In the code you have posted you have not used it anywhere. In case you are adding it another view, you can release the object after adding it to that view.
Related
I have the following method which takes some CAShapeLayers and converts them into a UIImage. The UIImage is used in a cell for a UITableView (much like the photos app when you select a photo from one of your libraries). This method is called from within a GCD block:
-(UIImage*) imageAtIndex:(NSUInteger)index
{
Graphic *graphic = [[Graphic graphicWithType:index]retain];
CALayer *layer = [[CALayer alloc] init];
layer.bounds = CGRectMake(0,0, graphic.size.width, graphic.size.height);
layer.shouldRasterize = YES;
layer.anchorPoint = CGPointZero;
layer.position = CGPointMake(0, 0);
for (int i = 0; i < [graphic.shapeLayers count]; i++)
{
[layer addSublayer:[graphic.shapeLayers objectAtIndex:i]];
}
CGFloat largestDimension = MAX(graphic.size.width, graphic.size.height);
CGFloat maxDimension = self.thumbnailDimension;
CGFloat multiplicationFactor = maxDimension / largestDimension;
CGSize graphicThumbnailSize = CGSizeMake(multiplicationFactor * graphic.size.width, multiplicationFactor * graphic.size.height);
layer.sublayerTransform = CATransform3DScale(layer.sublayerTransform, graphicThumbnailSize.width / graphic.size.width, graphicThumbnailSize.height / graphic.size.height, 1);
layer.bounds = CGRectMake(0,0, graphicThumbnailSize.width, graphicThumbnailSize.height);
UIGraphicsBeginImageContextWithOptions(layer.bounds.size, NO, 0);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() retain];
UIGraphicsEndImageContext();
[layer release];
[graphic release];
return [image autorelease];
}
For whatever reason, when I'm scrolling the UITableView and loading the images in, it is stuttering a little bit. I know the GCD code is fine because it's worked previously so it appears something in this code is causing the stuttering. Does anyone know what that could be? Is CAAnimation not thread safe? Or does anyone know a better way to take a bunch of CAShapeLayers and convert them into a UIImage?
In the end I believe:
[layer renderInContext:UIGraphicsGetCurrentContext()];
Cannot be done on a separate thread, so I had to do the following:
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
//draw the mutable paths of the CAShapeLayers to the context
UIImage *image = [UIGraphicsGetImageFromCurrentImageContext() retain];
UIGraphicsEndImageContext();
There is a great example of this (where I learned to do it) in the WWDC2012 video "Building Concurrent User Interfaces on iOS"
I'm new in iOS. Now I want to load view images from URL to page control using scroll view. When I run the program the first image is shown but when I try to slide to next image or I move to another page program is not responding. My guess is probably related to the size of image.
The following is my code to load the image. I put this code in -(void) viewDidLOad...
CGRect screenShot = screenView.frame;
screenShot.origin.y = description.frame.origin.y + description.frame.size.height + 30;
screenView.frame = screenShot;
pageControlBeingUsed = NO;
for (int i = 0; i < [myArrayImagesURL count]; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIImageView *iv = [[[UIImageView alloc] initWithFrame:CGRectMake(scrollView.bounds.size.width * i, 0, scrollView.bounds.size.width, scrollView.bounds.size.height)] autorelease];
iv.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:
[NSURL URLWithString:[myArrayImagesURL objectAtIndex:i]]]];
[self.scrollView addSubview:iv];
[iv release];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * [myArrayImagesURL count], self.scrollView.frame.size.height);
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = [myArrayImagesURL count];
It looks like you have set the imageView to autorelease and the released it. This should be wrong. Try removing the autorelease tag when you create the imageView. It should be properly retained now.
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(scrollView.bounds.size.width * i, 0, scrollView.bounds.size.width, scrollView.bounds.size.height)];
I need to create a horizontal UIScrollView which to hold hundreds of thumbnail images, just like a slide of thumbnails.
For example, there will be 10 thumbnails showing in a single screen, each of them are horizontally adjacent to each other.
My problem is that I don't know how to make a horizontal UIScrollView to hold the multiple thumbnails which showing at the same time ?
A sample photo is as below. See the bottom part of the screen.
Thanks.
You can add all the thumbnails programatically to your scrollview and use the setContentSize method of UIScrollView. you have to pass 2 values in contentOffset. 1 for width and 1 for height. Please follow link to explore more on this. If you need further help please leave a comment.
Hope it helps.
Please consider Following example.
- (void)setupHorizontalScrollView
{
scrollView.delegate = self;
[self.scrollView setBackgroundColor:[UIColor blackColor]];
[scrollView setCanCancelContentTouches:NO];
scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView.clipsToBounds = NO;
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
NSUInteger nimages = 0;
NSInteger tot=0;
CGFloat cx = 0;
for (; ; nimages++) {
NSString *imageName = [NSString stringWithFormat:#"image%d.jpg", (nimages + 1)];
UIImage *image = [UIImage imageNamed:imageName];
if (tot==15) {
break;
}
if (4==nimages) {
nimages=0;
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.size.height = 40;
rect.size.width = 40;
rect.origin.x = cx;
rect.origin.y = 0;
imageView.frame = rect;
[scrollView addSubview:imageView];
[imageView release];
cx += imageView.frame.size.width+5;
tot++;
}
self.pageControl.numberOfPages = nimages;
[scrollView setContentSize:CGSizeMake(cx, [scrollView bounds].size.height)];
}
I suggest you to look at nimbus
Check out bjhomer's HSImageSidebarView project. It lets you load a scrollview horizontally or vertically and load in the images. Super easy to implement.
First of all, at storyboard drag and drop the scroll view and make the outlet of scrollview named scrollView. Two array one is mutable and one is immutable.
#property(nonatomic,strong)IBOutlet UIScrollView *scrollView;
#property(nonatomic,strong)NSMutableArray *images;
#property(nonatomic,strong)NSArray *imagesName;
The immutable array only store the images which we want to show on the scroll view.Make sure UIscrollview delegate is defined.
In viewcontoller.m file in didload function do following code:
imagesName = [[NSArray alloc]initWithObjects:#"centipede.jpg",#"ladybug.jpg",#"potatoBug.jpg",#"wolfSpider.jpg", #"ladybug.jpg",#"potatoBug.jpg",#"centipede.jpg",#"wolfSpider.jpg",nil];
// mutable array used to show the images on scrollview dynamic becaus after one
// image when scroll other will come
images = [[NSMutableArray alloc]init];
scrollView.delegate = self;
scrollView.scrollEnabled = YES;
int scrollWidth = 120;
scrollView.contentSize = CGSizeMake(scrollWidth,80);
int xOffset = 0;
//the loop go till all images will load
for(int index=0; index < [imagesName count]; index++)
{
UIImageView *img = [[UIImageView alloc] init];
// make the imageview object because in scrollview we need image
img.frame = CGRectMake(5+xOffset, 0, 160, 110);
// the offset represent the values, used so that topleft for each image will
// change with(5+xOffset, 0)and the bottomright(160, 110)
NSLog(#"image: %#",[imagesName objectAtIndex:index]);
img.image = [UIImage imageNamed:[imagesName objectAtIndex:index]];
// The image will put on the img object
[images insertObject:img atIndex:index];
// Put the img object at the images array which is mutable array
scrollView.contentSize = CGSizeMake(scrollWidth+xOffset,110);
//scroll view size show after 125 width the scroll view enabled
[scrollView addSubview:[images objectAtIndex:index]];
// set images on scroll view
xOffset += 170;
}
You can calculate content size width of the scrollview as width = number of images * size of each image. Then set contentSize of the scrollview to this width and the height that you want (scrollView.contentSize = CGSizeMake(width, height))
I'm trying to dynamically add Images to a ScrollView. Before adding I check if there are any subviews in the ScrollView and delete them in a for loop.
When I release the imageview I get a runtime error stating i'm trying to acces a deallocated instance. If I remove the release statement the application will run correctly but "build and analyze" shows a leak because th reference count of imageview is not decreased..
if ([scrollView.subviews count]>0){
for (int i=0; i<[scrollView.subviews count]; ++i) {
[[scrollView.subviews objectAtIndex:i] removeFromSuperview];
}
}
//Making a scroller with results
int scrollWidth = 0.0f;
int scrollHeight = 0.0f;
for (int i = 0; i<previewImages.count;++i)
{
UIImage *image=[previewImages objectAtIndex:i];
scrollWidth = scrollWidth + image.size.width; // Width of all the images
if (image.size.height > scrollHeight)scrollHeight= image.size.height; // Maximum image height
[image release];
}
float xC = 0.0f;
for (int i=0; i<previewImages.count; ++i) {
UIImage *image=[previewImages objectAtIndex:i];
UIImageView *imageview = [[UIImageView alloc] initWithFrame:CGRectMake(xC, 0.0f, image.size.width, image.size.height)];
UILabel *subScript = [[UILabel alloc] initWithFrame:CGRectMake(xC, image.size.height-30.0f, image.size.width,30.0f)];
subScript.textColor = [UIColor whiteColor];
subScript.backgroundColor = [UIColor colorWithWhite:0.5f alpha:0.5f];
subScript.text = [imagePaths objectAtIndex:i];
imageview.image = image;
xC = xC + image.size.width;
[image release];
[scrollView addSubview:imageview];
[imageview release];
[scrollView addSubview:subScript];
[subScript release];
}
[scrollView setContentSize:CGSizeMake(scrollWidth , scrollHeight)];
Any suggestions about the memory leak or general best practices for adding and removing views from an array into a scrollView are much appreciated!
if ([scrollView.subviews count]>0){
for (int i=0; i<[scrollView.subviews count]; ++i) {
[[scrollView.subviews objectAtIndex:i] removeFromSuperview];
}
}
is wrong, because you are removing subview from subviews array. Do reverse iteration would fix that, but I would suggest keeping the view in separated array instead.
I've got a TapDetectingImageView class that is pertaining in memory after usage because I do not reuse it in my code.
I change my code now to reuse it instead of re creating a new one each time.
The goal is to configure that TapDetectingImageView object and put it in a view. I'll do it 8 times but with the code below, only the last one is showing. I'm sure I'm missing something, but what? ;)
The view holding the imageViews is potatoeView. I'm adding new TapDetectingImageView through:
[potatoeView addSubview:imageView];
What's wrong in that code?
for (int i = 0; i <= numberOfPotatoes-1; i++)
{
NSLog(#"potatoesView Generation : %d",i);
NSArray *imgArray = [[NSArray alloc] initWithArray:[p objectAtIndex:i]];
UIImage *img1 = (UIImage *) [imgArray objectAtIndex:0];
UIImage *img2 = (UIImage *) [imgArray objectAtIndex:1];
NSString *imgName = (NSString *) [imgArray objectAtIndex:2];
if (imageView == nil) {
imageView = [[TapDetectingImageView alloc] initWithImage:img1 imageHighlighted:img2];
}else {
[imageView setImage:(UIImage *)img1];
[imageView setImageHighlighted:(UIImage *)img2];
}
[imageView setDelegate:self];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = [potatoesSize floatValue] ;
rect.size.width = [potatoesSize floatValue] ;
imageView.frame = rect;
[imageView setName:(NSString *)imgName];
imageView.tag = i+1; // tag our images for later use when we place them in serial fashion
NSValue *val = [potatoesSizeAndPositions objectAtIndex:i];
CGPoint point = [val CGPointValue];
imageView.center = point;
[potatoeView addSubview:imageView];
[imgArray release];
}
You seem to be fundamentally misunderstanding how your views are drawn. When you set up the same view instance with eight different positions and images, it doesn't "stamp" them all out on some canvas as it goes. Its state won't be queried until the main run loop gets around to drawing your view, at which point it'll ask your view for its frame and contents and so on to draw it. If you want to draw eight different images with UIViews, you'll need eight different views.
You only ever create one view, set it as the subview and then change it n-1 times. Drop the if (imageView==nil) and create all 8 of them.