I use EGOPhotoView for my image local gallery. The number of images is 152 and their resolution is 1400x950px.
I have problems with the memory of my device! Memory does not get released. I display one image 45mb + next 55mb + next 72mb.....and over 130mb the app crashes.
In this code I have added images:
NSMutableArray *photos = [[NSMutableArray alloc] init];
for (Picture *picture in [self fetchedResultsController].fetchedObjects) {
UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:#"%#.jpg", picture.imgName]];
MyPhoto *photo = [[MyPhoto alloc] initWithImageURL:nil name:[NSString stringWithFormat:#"%#, %#, %#", picture.friendlyName, picture.type, picture.date] image:img painter:(Painter *)picture.painter];
[photos addObject:photo];
[photo release];
}
MyPhotoSource *source = [[MyPhotoSource alloc] initWithPhotos:[NSArray arrayWithArray:photos]];
EGOPhotoViewController *photoController = [[EGOPhotoViewController alloc] initWithPhotoSource:source];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:photoController];
navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
navController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentModalViewController:navController animated:YES];
[navController release];
[photoController release];
[source release];
[photos release];
I use EGOPhotoViewer as a modalView.
What could be the problem I'm having?
Even though you're explicitly releasing the instances of UIImage, the photos array that you're using still has a reference to them. This means that the images aren't being released from memory as it appears you're expecting.
I'm not familiar with EGOPhotoViewer, unfortunately. Is there a way you can lazy load the images? There are probably other options such as reducing the size of the images, but that's dependent upon what your requirements are.
Related
I was recently examining the project "Demo Photo Board" found here.
This is a simple demonstration of adding UIImageViews to the screen that have UIGestureRecognizers added to them...allowing the user to manipulate the various UIImageViews.
I add the view like so:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
imageview = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
imageview.userInteractionEnabled = YES;
[imageview setImage:image];
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scale:)];
[pinchRecognizer setDelegate:self];
[imageview addGestureRecognizer:pinchRecognizer];
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
[rotationRecognizer setDelegate:self];
[imageview addGestureRecognizer:rotationRecognizer];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[imageview addGestureRecognizer:panRecognizer];
[self.view addSubview:imageview]; }
I can even save the view like so:
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[NSKeyedArchiver archivedDataWithRootObject:imageview] forKey:#"imageViewSaved"];
Now my question: The following method saves only the last imageview added to the screen. Anyone know how to save all of the imageviews that are on the screen...if the user adds more than one?
I really don't think you want to be saving the entire UIImageView object to the user defaults. Instead, try saving a list of UIImage objects, which will be much more lightweight. (And which make much more sense to serialize.)
You can do this like so:
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSArray *savedArray = [defs objectForKey:#"SAVED_IMAGES"];
// Create a mutable version in case the serialized copy is an NSArray
NSMutableArray *mutableImages = savedArray ? [NSMutableArray arrayWithArray:savedArray] : [NSMutableArray array];
[mutableImages addObject:image];
[defs setObject:mutableImages forKey:#"SAVED_IMAGES"];
[defs save];
To distinguish the UIImageViews on the screen you can do the following.
Define the start ImageView Tag number
#define kImageViewTag 3000
Define an instance var for number of images added to the screen.
NSUInteger numberOfImage = 0
Whenever you create a new UIImageView, increase the count and add it with the kImageViewTag and assign it to the tag property.
imageview = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
imageview.userInteractionEnabled = YES;
[imageview setImage:image];
numberOfImage += 1;
imageView.tag = kImageViewTag + numberOfImage;
Whenever you enumerate the screen subviews, if the class is UIImageView with the tag >= kImageViewTag, you know those are the images added to the screen from the UIImagePickerController.
reading the Apple's documentation i tried using it's new face detection API but with no luck,, although there are no compile or runtime errors the instance method featuresInImage always return an array of CIFeature objects with null values.
First timer on stackoverflow, still tried my best to be short and specific.
A minimal code (working) to test out the new iOS 5 face detection API
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CIImage *ciImage = [[CIImage alloc] initWithImage:[UIImage imageNamed:#"IMG_0056.JPG"]];
NSLog(#"showing image now");
//[imageView setImage:image];
if (ciImage == nil)
NSLog(#"CIImage is nil");
//imageView.image = [UIImage imageWithCGImage:[context createCGImage:ciImage fromRect:ciImage.extent]];
[imageView setImage:[UIImage imageNamed:#"IMG_0056.JPG"]];
NSDictionary *options = [[NSDictionary alloc] initWithObjectsAndKeys:
#"CIDetectorAccuracy", #"CIDetectorAccuracyHigh",nil];
CIDetector *ciDetector = [CIDetector detectorOfType:CIDetectorTypeFace
context:nil
options:options];
NSArray *features = [ciDetector featuresInImage:ciImage];
NSLog(#"no of face detected: %d", [features count]);
NSString *myString = [[NSString alloc] initWithFormat:#"%d face(s) detected\n",[features count]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Face detection" message:myString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
UIImage* uiimage = nil;
CIImage* image = [CIImage imageWithCGImage:uiimage.CGImage];
CIDetector* detector = [CIDetector detectorOfType:CIDetectorTypeFace context:nil options:[NSDictionary dictionaryWithObject:CIDetectorAccuracyHigh forKey:CIDetectorAccuracy]];
See here for full tutorial
http://b2cloud.com.au/how-to-guides/face-detection-in-ios-5
I'm new to the hole Xcode/objective-c thing so it would be kind answering my questions in a way I can understand you :)
My problem is: I'm trying to create a slot machine with a picker and a button (to spin the wheels of course ;) ) so I'm implementing 5 images (apple,crown,cherry,lemon,seven,banana) but at the point when I start the app I get this error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImage initWithImage:]: unrecognized selector sent to instance 0x4b649b0'
My code looks like this:
- (void)viewDidLoad {
UIImage *apple = [UIImage imageNamed:#"apple.png"];
UIImage *banana = [UIImage imageNamed:#"banana.png"];
UIImage *cherry = [UIImage imageNamed:#"cherry.png"];
UIImage *crown = [UIImage imageNamed:#"crown.png"];
UIImage *lemon = [UIImage imageNamed:#"lemon.png"];
UIImage *seven = [UIImage imageNamed:#"seven.png"];
for (int i = 1; i <= 5; i++) {
UIImageView *appleView = [[UIImage alloc] initWithImage:apple];
UIImageView *bananaView = [[UIImage alloc] initWithImage:banana];
UIImageView *cherryView = [[UIImage alloc] initWithImage:cherry];
UIImageView *crownView = [[UIImage alloc] initWithImage:crown];
UIImageView *lemonView = [[UIImage alloc] initWithImage:lemon];
UIImageView *sevenView = [[UIImage alloc] initWithImage:seven];
NSArray *imageViewArray = [[NSArray alloc] initWithObjects:appleView, bananaView, cherryView, crownView, lemonView, sevenView, nil];
NSString *fieldName = [[NSString alloc] initWithFormat:#"column%d", i];
[self setValue: imageViewArray forKey:fieldName];
[fieldName release];
[imageViewArray release];
[appleView release];
[bananaView release];
[cherryView release];
[crownView release];
[lemonView release];
[sevenView release];
I've been looking around for typos quite some time but didn't find any. It would be really nice if someone could give me a hint. If the supported code isn't enough, feel free to ask for more.(Just copied the section where the error occurred) Sorry for my bad english but it's not my native language :)
/edit: I should've said, that the original error had been: SIGABRT, but it looks like this error seems to mean a lot without any context :)
You need to create your image views with
[[UIImageView alloc] initWithImage: ...]
NOT
[[UIImage alloc] initWithImage: ...]
I'm getting a really bizarre output from that contructor. It does not actually store any of the objects. I debugged the method and the objects being stored are initialized properly.
I use this array to set the vc's on a UITabBarController and the tab bar is empty. Here's the code
-(void)initBarItemsWithAllFeatures {
/*
Issues
*/
UIImage *issuesImage = [UIImage imageNamed:#"issues_on.png"];
UITabBarItem *issuesTabBarItem = [[UITabBarItem alloc]initWithTitle:NSLocalizedString(#"IssuesTabBarTitle",#"") image:issuesImage tag:0];
[issuesImage release];
issuesNavigationController.tabBarItem =issuesTabBarItem;
[issuesTabBarItem release];
/*
thumbs
*/
ThumbsViewController *thumbsViewController = [[ThumbsViewController alloc]initWithNibName:#"ThumbsViewController" bundle:nil];
UIImage *thumbsImage = [UIImage imageNamed:#"thumbs_on.png"];
UITabBarItem *thumbsTabBarItem = [[UITabBarItem alloc]initWithTitle:NSLocalizedString(#"ThumbsTabBarTitle",#"") image:thumbsImage tag:1];
[thumbsImage release];
thumbsViewController.tabBarItem = thumbsTabBarItem;
[thumbsTabBarItem release];
/*
contents
*/
ContentsViewController *contentsViewController = [[ContentsViewController alloc]initWithNibName:#"ContentsViewController" bundle:nil];
UIImage *contentsImage = [UIImage imageNamed:#"contents_on.png"];
UITabBarItem *contentsTabBarItem = [[UITabBarItem alloc] initWithTitle:NSLocalizedString (#"ContentsTabBarTitle",#"") image:contentsImage tag:2];
[contentsImage release];
contentsViewController.tabBarItem = contentsTabBarItem;
[contentsTabBarItem release];
/*
search
*/
SearchViewController *searchViewController = [[SearchViewController alloc]initWithNibName:#"SearchViewController" bundle:nil];
UIImage *searchImage = [UIImage imageNamed:#"search_on.png"];
UITabBarItem *searchTabBarItem = [[UITabBarItem alloc] initWithTitle:NSLocalizedString (#"SearchTabBarTitle",#"") image:searchImage tag:3];
[searchImage release];
searchViewController.tabBarItem = searchTabBarItem;
[searchTabBarItem release];
/*
favourites
*/
FavouritesViewController *favouritesViewController = [[FavouritesViewController alloc]initWithNibName:#"FavouritesViewController" bundle:nil];
UIImage *favouritesImage = [UIImage imageNamed:#"favourites_on.png"];
UITabBarItem *favouritesTabBarItem = [[UITabBarItem alloc] initWithTitle:NSLocalizedString (#"FavouritesTabBarTitle",#"") image:contentsImage tag:4];
[favouritesImage release];
favouritesViewController.tabBarItem = favouritesTabBarItem;
[favouritesTabBarItem release];
/*
contact
*/
ContactViewController * contactViewController = [[ContactViewController alloc] initWithNibName:#"ContactViewController" bundle:nil];
UIImage *contactImage = [UIImage imageNamed:#"contact_on.png"];
UITabBarItem *contactTabBarItem = [[UITabBarItem alloc] initWithTitle:NSLocalizedString (#"contactTabBarTitle",#"") image:contactImage tag:5];
[contactImage release];
contactViewController.tabBarItem = contactTabBarItem;
[contactTabBarItem release];
/*
add to an array
*/
allFeaturesAvailableTabBarItemArray = [[NSArray alloc] initWithObjects:
issuesNavigationController,
thumbsViewController,
contentsViewController,
searchViewController,
favouritesViewController,
contactViewController, nil];
/*
release objects
*/
[thumbsViewController release];
[contentsViewController release];
[searchViewController release];
[favouritesViewController release];
[contactViewController release];
}
Thanks in advance!
I think you may be over releasing the tab bar images (FWIW).
I ended up removing one by one the objects in the array to see which one was causing issues. the first object added was 0x0 (nil) so it didn't add anything to the array. The strange thing is that
on
issuesNavigationController.tabBarItem =issuesTabBarItem;
I'm calling properties on an nil object and fired no alarms. Is this "expected" or is it kind of a bug I should report?
Thank you very much to all of you for your quick answers.
I'm going to take care of the overrelease as well Thanks!
I have the following un my applicationDidFinishLaunching method
UIImage *image2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"image2.jpg" ofType:nil]];
view2 = [[UIImageView alloc] initWithImage:image2];
view2.hidden = YES;
[containerView addSubview:view2];
I'm simply adding an image to a view. But because I need to add 30-40 images I need to wrap the above in a function (which returns a UIImageView) and then call it from a loop.
This is my first attempt at creating the function
-(UIImageView)wrapImage:(NSString *)imagePath
{
UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]
pathForResource:imagePath
ofType:nil]];
UIImageView *view = [[UIImageView alloc] initWithImage:image];
view.hidden = YES;
return view;
}
And then to invoke it I have the following so far, for simplicity I am only wrapping 3 images
//Create an array and add elements to it
NSMutableArray *anArray = [[NSMutableArray alloc] init];
[anArray addObject:#"image1.jpg"];
[anArray addObject:#"image2.jpg"];
[anArray addObject:#"image3.jpg"];
//Use a for each loop to iterate through the array
for (NSString *s in anArray) {
UIImageView *wrappedImgInView=[self wrapImage:s];
[containerView addSubview:wrappedImgInView];
NSLog(s);
}
//Release the array
[anArray release];
I have 2 general questions
Is my approach correct?, ie following best practices, for what I am trying to do (load a multiple number of images(jpgs, pngs, etc.) and adding them to a container view)
For this to work properly with a large number of images, do I need to keep my array creation separate from my method invocation?
Any other suggestions welcome!
Just a note, in function declaration you should return pointer to UIImageView, not an UIImageView itself (i.e. add an asterisk).
Also, when returning the view from the function you should autorelease it. Otherwise it will leak memory. So initialization should look something like this:
UIImageView *view = [[[UIImageView alloc] initWithImage:image] autorelease];
Everything else seems to look good.