UIImagePicker crashing after selection - iphone

I'm using ELCImagePickerController so I can select multiple photos and import them. It works fine when I select a few photos, but if I select over around 25, I get a crash. Here's the code that runs after I hit done selecting photos:
-(void)selectedAssets:(NSArray*)_assets {
NSMutableArray *returnArray = [[NSMutableArray alloc] init];
int count=0;
for(ALAsset *asset in _assets) {
NSMutableDictionary *workingDictionary = [[NSMutableDictionary alloc] init];
[workingDictionary setObject:[asset valueForProperty:ALAssetPropertyType] forKey:#"UIImagePickerControllerMediaType"];
UIImage *image=[UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage]];
[workingDictionary setObject:image forKey:#"UIImagePickerControllerOriginalImage"];
[workingDictionary setObject:[[asset valueForProperty:ALAssetPropertyURLs] valueForKey:[[[asset valueForProperty:ALAssetPropertyURLs] allKeys] objectAtIndex:0]] forKey:#"UIImagePickerControllerReferenceURL"];
NSLog(#"%i", count);
count++;
[returnArray addObject:workingDictionary];
}
[self popToRootViewControllerAnimated:NO];
[[self parentViewController] dismissModalViewControllerAnimated:YES];
if([delegate respondsToSelector:#selector(elcImagePickerController:didFinishPickingMediaWithInfo:)]) {
[delegate performSelector:#selector(elcImagePickerController:didFinishPickingMediaWithInfo:) withObject:self withObject:[NSArray arrayWithArray:returnArray]];
}
}
I selected 80 photos, and the NSLog statement displays up to 45, but then it just crashes with no message, just (gdb).
The images I'm selecting are iPhone 4 images captured with the rear camera. I've tried resizing the images too upon importing, but even then the app still crashes. Any ideas of what could be the problem?

I'm going to put that as an answer if you don't mind.
There are few solutions to this problem. First you might want to restrict user from selecting more than something like 5 photos. Second you might want to resize your images and make them really small before putting them into an array or something. Or if you need them all in the original size, you can copy them upon selection to your ~/tmp directory and instead store the links to them in your NSArray, so that you could load them dynamically from disk instead of keeping them all in memory.
Sorry if it doesn't helps since I don't really know your ultimate goal in using such amount of images at the same time.

Related

Would like to keep cache data when changing to other UIView

i would love to have some help or any keyword that i can use to search for.
My problem is I have one UIView, called "UpdateViewController.xib" that load 20 small images and text below those images by programmatically.
and when user click on those images it will change to next view that i created by IB, called "imageSumVuew.xib" and i have a button to link back to UpdateViewController.
#import "imageSumView.h" // next view that i wanna load//
// the transition to next view
imageSumView *nextView = [[imageSumView alloc]init];
self.modalPresentationStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:nextView animated:YES completion:NULL];
[nextView release];
in the nextView i have code similar to this which come back to this view
#import "UpdateViewController.h" // old that i wanna load back//
// the transition to old view
UpdateViewController *oldView = [[UpdateViewController alloc]init];
self.modalPresentationStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:oldView animated:YES completion:NULL];
[oldView release];
the problem is when it did load back to UpdateViewController, all my images and text has to reload all over again.
The question is " how can i keep cache of the UpdateViewController view?", i don't want user to reload images all over again because they have to go back and forth between this page for several times to see which image that they wanna pick.
Think of Instragram that you see list of your friends images then you wanna check your first friends's photo and after that you come back to overall image of your friends without loading and choose second friends.
Store image data with unique id to temporary directory once it is downloaded for the first time. For the next time check for that user id's image in your directory, if it is there then load image from there. For example :
#define TMP NSTemporaryDirectory()
NSString *filename=[NSMutableString stringWithFormat:#"userimage_%#",userId];
NSString *uniquePath = [TMP stringByAppendingPathComponent:filename];
NSData *dataImage = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]]
UIImage *image = [[UIImage alloc] initWithData: dataImage];
[UIImageJPEGRepresentation(image, 1.0f) writeToFile: uniquePath atomically: YES];
[image release];
To get ur image you can do something like below:
- (NSData *) getImage: (NSString *)userId
{
NSString *filename=[NSMutableString stringWithFormat:#"userimage_%#,userId];
NSString *uniquePath = [TMP stringByAppendingPathComponent: filename];
if([[NSFileManager defaultManager] fileExistsAtPath: uniquePath])
{
return [[NSData alloc] initWithContentsOfFile:uniquePath];
}
return nil;
}

MPNowPlayingInfoCenter defaultCenter will not update or retrieve information

I'm working to update the MPNowPlayingInfoCenter and having a bit of trouble. I've tried quite a bit to the point where I'm at a loss. The following is my code:
self.audioPlayer.allowsAirPlay = NO;
Class playingInfoCenter = NSClassFromString(#"MPNowPlayingInfoCenter");
if (playingInfoCenter) {
NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:#"series_placeholder"]];
[songInfo setObject:thePodcast.title forKey:MPMediaItemPropertyTitle];
[songInfo setObject:thePodcast.author forKey:MPMediaItemPropertyArtist];
[songInfo setObject:#"NCC" forKey:MPMediaItemPropertyAlbumTitle];
[songInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];
}
This isn't working, I've also tried:
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:nil];
In an attempt to get it to remove the existing information from the iPod app (or whatever may have info there). In addition, just to see if I could find out the problem, I've tried retrieving the current information on app launch:
NSDictionary *info = [[MPNowPlayingInfoCenter defaultCenter] nowPlayingInfo];
NSString *title = [info valueForKey:MPMediaItemPropertyTitle];
NSString *author = [info valueForKey:MPMediaItemPropertyArtist];
NSLog(#"Currently playing: %# // %#", title, author);
and I get Currently playing: (null) // (null)
I've researched this quite a bit and the following articles explain it pretty thoroughly, however, I am still unable to get this working properly. Am I missing something? Would there be anything interfering with this? Is this a service something my app needs to register to access (didn't see this in any docs)?
Apple's Docs
Change lock screen background audio controls
Now playing info ignored
I finally figured out the problem, I was not prompting my app to receive remote control events, simply adding this line fixed the problem:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
I use the code below and it always works. I'm also using MPMoviePlayer like you. Have you checked whether NSClassFromString(#"MPNowPlayingInfoCenter") ever actually returns YES? Have you set you app play audio in background key in your plist?
- (void) loadMPInformation
{
NSDictionary *mpInfo;
if([savedTrack.belongingAlbum.hasAlbumArt boolValue] == NO){
mpInfo = [NSDictionary dictionaryWithObjectsAndKeys:savedTrack.belongingAlbum.album, MPMediaItemPropertyAlbumTitle,
savedTrack.belongingArtist.artist, MPMediaItemPropertyArtist, savedTrack.name, MPMediaItemPropertyTitle, nil];
} else {
UIImage *artImage = [UIImage imageWithData:savedTrack.belongingAlbum.art];
MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:artImage];
mpInfo = [NSDictionary dictionaryWithObjectsAndKeys:savedTrack.belongingAlbum.album, MPMediaItemPropertyAlbumTitle,
savedTrack.belongingArtist.artist, MPMediaItemPropertyArtist, savedTrack.name, MPMediaItemPropertyTitle, artwork, MPMediaItemPropertyArtwork, nil];
}
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = mpInfo;
}

Multiple NSThreads running simultaneously causing app freezes

I am developing an application in which I have a display a lot of images in my table view.These images has to come from server, so I have create another thread in which the image get processed and then set on table view cell to make our table view scrolls smoothly and properly.
My problem is when I scrolls my table view to a number of times, the app get freezes and after some time the xcode shows the message shown in below image:-
My table view cell code :-
id object = [imageDictFunctionApp objectForKey:[NSString stringWithFormat:#"%d",functionAppButton.tag]];
if(!object){
NSArray *catdictObject=[NSArray arrayWithObjects:[NSNumber numberWithInt:functionAppButton.tag],indexPath,[NSNumber numberWithInt:i],nil];
NSArray *catdictKey=[NSArray arrayWithObjects:#"btn",#"indexPath",#"no",nil];
NSDictionary *catPassdict=[NSDictionary dictionaryWithObjects:catdictObject forKeys:catdictKey];
[NSThread detachNewThreadSelector:#selector(displayingSmallImageForFunctionsApps:) toTarget:self withObject:catPassdict];
}
else
{
if(![object isKindOfClass:[NSNull class]]){
UIImage *img = (UIImage *)object;
[functionAppButton setImage:img forState:UIControlStateNormal];
}
-(void)displayingSmallImageForFunctionsApps:(NSDictionary *)dict
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSIndexPath *path=[dict objectForKey:#"indexPath"];
NSArray *catArray=[self.functionDataDictionary objectForKey:[self.functionsKeysArray objectAtIndex:path.row]];
int vlaue=[[dict objectForKey:#"no"] intValue];
NSDictionary *dict1=[catArray objectAtIndex:vlaue];
NSString *urlString=[dict1 objectForKey:#"artwork_url_large"];
NSURL *url = [NSURL URLWithString:urlString];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if(image){
[imageDictFunctionApp setObject:image forKey:[NSString stringWithFormat:#"%d",[[dict objectForKey:#"btn"] intValue]]];
NSMutableDictionary *dict2=[NSMutableDictionary dictionaryWithCapacity:4];
[dict2 setObject:image forKey:#"imageValue"];
[dict2 setObject:[dict objectForKey:#"btn"] forKey:#"tag"];
[dict2 setObject:[dict objectForKey:#"indexPath"] forKey:#"indexPath"];
[self performSelectorOnMainThread:#selector(setImageInCellDictCategroryTable:) withObject:dict2 waitUntilDone:NO];
}
else{
[imageDictFunctionApp setObject:[NSNull null] forKey:[NSString stringWithFormat:#"%d",[[dict objectForKey:#"btn"] intValue]]];
}
[pool drain];
}
- (void)setImageInCellDictCategroryTable:(NSDictionary *)dict{
UITableViewCell *myCell = (UITableViewCell *)[categoriesAndFunctionsTableView cellForRowAtIndexPath:[dict objectForKey:#"indexPath"]];
UIButton *myBtn = (CustomUIButton *)[myCell viewWithTag:[[dict objectForKey:#"tag"] intValue]];
if ([dict objectForKey:#"imageValue"]) {
[myBtn setImage:[dict objectForKey:#"imageValue"] forState:UIControlStateNormal];
}
}
I have posted all my code that might be linked with this error.Please anyone suggest me how to solve this issue.
Thanks in advance!
I would suggest not to use threads and move you code to GCD, looks like what you want to use is a serial queue.
So what I would guess is happening is that you are running out of Mach ports. It looks to me like you are starting a thread for every single cell in your table and then they are all trying to schedule tasks to run on the main runloop when they are done. This is going to stress your system.
I would create an NSOperation for each image and schedule them all on the same NSOperationQueue. The runtime will use a pool of threads tuned to the specific system to run all of the operations.
For a simple thing like this, you can also use GCD as Oscar says, but I recently read on the Apple list that NSOperationQueue is preferred because it is higher level. It gives you more options for controlling what happens to your background tasks.

release NSMutable array in obj-c

where to dealloc/ release my NS-mutable array a1 ??
see this
- (void)viewDidLoad {
[NSThread detachNewThreadSelector:#selector(loadImage) toTarget:self withObject:nil];
}
- (void) loadImage
{
NSLog(#" THREAD METHOD");
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSUserDefaults *imgg = [NSUserDefaults standardUserDefaults];
myimg= [imgg stringForKey:#"keyToimg"];
NSLog(#"RES image sssssssss is = %#",myimg);
a1 = [[NSMutableArray alloc] init];
[a1 addObjectsFromArray:[myimg componentsSeparatedByString:#"\n\t"]];
//[a1 removeAllObjects];
////
//[myimg release];
[pool release];
}
and in table cell of secition 3 i am displaying image
switch(indexPath.section)
{
NSString *urlE=[a1 objectAtIndex:1];
NSLog(#"url is %#",urlE);
NSData *backgroundData = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlE]];
image = [UIImage imageWithData:backgroundData];
myImageView= [[UIImageView alloc] initWithImage:image];
[myImageView setUserInteractionEnabled:YES];
CGRect rect=CGRectMake(20 ,10, 270, 180);
myImageView.frame = rect;
myImageView.tag = i;
[cell.contentView addSubview:myImageView];
}
and based on tap images are changing
pragma mark working image tap
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#" life count %d",[myimg retainCount]);
NSLog(#" life array count %d",[a1 retainCount]);
//NSLog(#" GITSHffffffffffffffffffffffffffffffC");
NSUInteger sections = [indexPath section];
//NSLog(#"row is %d",sections);
if (sections == 3)
{ //Its either 1 or 0 I don't remember, it's been a while since I did some tableview
if(tap<[a1 count]-1) {
NSLog(#" life array count %d",[a1 retainCount]);
tap++;
NSString *sa=[a1 objectAtIndex:tap];
//////////////////////
image= [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat: sa,[a1 objectAtIndex:tap ]]]]];
NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0)];
myImageView.image = image;
//[myimg release];
//[a1 release];
}
else {
tap=1;
//[myimg release];
//[a1 release];
}
}
//[a1 release];
}
so where should i release my a1 and myimg
a1 will never be released using this code.
You should put it on a member variable or add autorelease after init.
By the way, your myImageView should be released after you add it to the cell view.
It is possible because of the retain/release logic: when you alloc the myImageView the retain count is +1, once you add it to cell view,it is now +2, you should then release it so that the retain comes back to +1 and then when cell view will be further deallocated, it will decrement the retain count to 0.
The same logic for the variable image in the last function
Regards
Meir assayag
Instead of :
a1 = [[NSMutableArray alloc] init];
[a1 addObjectsFromArray:[myimg componentsSeparatedByString:#"\n\t"]];
Consider:
a1 = [NSMutableArray arrayWithArray:[myimg componentsSeparatedByString:#"\n\t"]];
That'll initialize your a1 with an autoreleased NSMutableArray object, and then you don't have to worry about manually releasing it.
The thing I don't know is whether your [pool release] will release it, but... I'd really prefer you NOT put that business in a background thread, but rather use asynchronous network methods to get your image data.
By the way, as I was learning iPhone development, I went through three or four levels of "aha moments" about backgrounded networking. One of them had to do with running selectors on background threads. That lasted about a week until I discovered ASIHttpRequest, which is how I do it now. MUCH simpler way to put network interactions in the background without having to mess with threading or any of that nonsense. See http://allseeing-i.com/ASIHTTPRequest/
If you look at my answers, every time HTTP client networking comes up I recommend ASI. I really don't mean to be a shill for it--it's just made my life so much easier I think everyone needs to know about it.

UIIMageView, warning: check_safe_call: could not restore current frame

I am changing the image in UIImageView based on accelerometer input. The images are stored in an array.
The application runs fine for a while and then crashes.
warning: check_safe_call: could not restore current frame
I am not using "UIImage ImageNamed" method when populating the array.
The total size of all images is around 12 Mb. But individual images are very light (<100 kb) and i am using only one image at a time from the array.
Just in case there are any autoreleases, I have allocated a NSAutoreleasePool in view did load and am draining it in the didReceiveMemoryWarning method (which does get called 2, 3 times before the app crashes?).
Following is the code that creates images array:
//create autorelease pool as we are creating many autoreleased objects
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *finalarr = [[NSMutableArray alloc] initWithCapacity:9];
NSLog(#"start loading");
for(int y = 0; y < 100; y+=10)
{
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:10];
for(int x = 0; x < 10; x++)
{
NSString *imageName = [[NSString alloc] initWithFormat:#"0%d",y + x];
UIImage *img = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:imageName ofType:#"png"]];
[arr addObject:img];
[imageName release];
[img release];
}
[finalarr addObject:arr];
[arr release];
}
NSLog(#"done loading");
// Override point for customization after app launch
viewController.imagesArray = finalarr;
[finalarr release];
//retain the array of images
[viewController.imagesArray retain];
//release the aurtorelease pool to free memory taken up by objects enqued for release
[pool release];
As the app runs smoothly for a while, which means array creation is definitely not the problem.
After this the following method is called from [accelerometer didAccelerate]
-(BOOL)setImageForX:(int)x andY:(int)y
{
[self.imageView setImage:(UIImage*)[(NSArray*)[self.imagesArray objectAtIndex:y] objectAtIndex:x]];
return TRUE;
}
So the only code being executed is the "UIImageView setImage". But no objects are being created here.
Please let me know if the code seems to have any leaks or i am doing something wrong.
Thanks,
Swapnil
NSAutoreleasePool should be allocated and released in the same method. Allocating it in one place and releasing it in another is usually very bad (the example code you pasted uses it correctly however)
Loading images into memory will decompress them; a 100KB compressed PNG could easily be 2MB uncompressed.
You also seem to have an extra retain call that shouldn't be there: [viewController.imagesArray retain]; (I assume the imagesArray property is marked copy or retain and not assign)