开发者

UIImage Causing Views All Throughout the iPhone to Turn Black

开发者 https://www.devze.com 2023-03-20 07:23 出处:网络
Alright, this problem is rather bizarre, and I\'m 99% positive at this point it\'s not a retain/release error.Basically I\'m using UIImagePickerController to grab an image from either the library or t

Alright, this problem is rather bizarre, and I'm 99% positive at this point it's not a retain/release error. Basically I'm using UIImagePickerController to grab an image from either the library or the camera, but the resulting image causes some... strange things to happen. Though it's laggy to pull the image up in a detail view controller containing a UIImageView, the real problem is that if I repetitively pull up the view controller and dismiss it, eventually parts of the image will have disappeared!!! More disturbingly, if I attempt to pull it up again after this has happened, the whole image will have turned black, and other UIViews throughout both my App AND the iPhone itself will either flicker wildly or have turned black!!!! For example, both the iPhone wallpaper and the initial "slide to unlock" panel turn black and flicker, respectively... It makes no difference whether the photo came from the library or the camera. The problem is entirely averted (no lag, no blackness) if I do something like this:

//UIImage* image = (UIImage*)[info objectForKey:UIImagePickerControllerOriginalImage];

UIImage* image = [[UIImage alloc] initWithData:
                  [NSData dataWithContentsOfURL:
                   [NSURL URLWithString:
                    @"http://wild-facts.com/wp-content/uploads/2010/07/Diving_emperor_penguin.jpg"]]];

Thus I can't imagine the problem having to do with anything other than the UIImagePickerController. Note that I'm still creating and dismissing it-- I'm just not grabbing the image out of it.

At first I thought the image was simply being overreleased, and the disappearing black chunks were parts of memory being overwritten. However, changing the image's retain count makes no difference. Then I thought, maybe the image is too large and somehow not getting properly released when I dismiss the UIImageView! Yet downloading a several MB image from the internet will not replicate the error. Then I thought, maybe the UIImagePickerController is disposing of the image, regardless of retain count! But copying the image failed as well. Furthermore, how could any of these things effect views that exist as deep as the iOS level?! I've researched, experimented, and Googled and no one has encountered this problem except for me... yet I'm not doing particularly strange! Is this an Apple issue? Did I forget something obvious? I've scanned up and down the documentation and guides to no avail, but perhaps I missed something.

None of this has worked:

  • Incrementing the retain count
  • Using [image copy]

None of this has replicated the problem with the downloaded image:

  • Decrementing the retain count
  • Downloading an image of size greater than 1 MB with large dimensions

I'm using the latest Verizon iPhone with iOS 4.2.8 (base SDK "overriden" to 4.3, whatever that means). 4.2.8 is the latest possible one for Verizon, though 4.3 is available for iPhones using AT&T.

Here's the code in glorious detail. I'm not yet checking for device compatibility, but it shouldn't matter concerning this. Perhaps I forgot some setting with the UIImagePickerController?

Quick Overview: I display an action sheet, then based on the user's input, display the image picker. I save the image as a transformable attribute on a Core Data object (delivery) using a custom transformer. I later hand the image to a detail view controller to display to the user.

IGDeliveryVC.m (parts of it, anyways. It's a tableview displaying the delivery's added media)

- (void)refresh
{
    [mediaDisplayArray release];

    NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"displayIndex" ascending:YES];

    mediaDisplayArray = [[NSMutableArray alloc] initWithArray:
                         [delivery.deliveryMedia sortedArrayUsingDescriptors:
                          [NSArray arrayWithObject:sortDescriptor]]];

    if (mediaDisplayArray == nil)
        mediaDisplayArray = [[NSMutableArray alloc] init];

    [self.tableView reloadData];
}

- (void)onAddMedia:(id)sender
{
#if TARGET_IPHONE_SIMULATOR

    UIImage* image = [[UIImage alloc] initWithData:
                      [NSData dataWithContentsOfURL:
                       [NSURL URLWithString:
                        @"http://wild-facts.com/wp-content/uploads/2010/07/Diving_emperor_penguin.jpg"]]];
    [delivery addImage:image];
    [self refresh];
    [image release];
    return;

#endif

    UIActionSheet *options = [[UIActionSheet alloc] initWi开发者_开发问答thTitle:@"Add Media from..." 
                                                         delegate:self 
                                                cancelButtonTitle:@"Cancel"
                                           destructiveButtonTitle:nil
                                                otherButtonTitles:@"Camera", @"Library", nil];
    [options showFromToolbar:self.navigationController.toolbar];
    [options release];
}

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex 
{
    if (buttonIndex != 0 && buttonIndex != 1)
        return;

    UIImagePickerController* picker = [[UIImagePickerController alloc] init];
    picker.delegate = self;
    picker.allowsEditing = NO;

    picker.mediaTypes = [NSArray arrayWithObjects:@"public.image",@"public.movie", nil];

    switch (buttonIndex)
    {
        case 0:
            picker.sourceType = UIImagePickerControllerSourceTypeCamera;
            break;

        case 1:
            picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
            break;
    }

    [self presentModalViewController:picker animated:YES];
}

- (void) imagePickerControllerDidCancel: (UIImagePickerController *) picker
{    
    [[picker parentViewController] dismissModalViewControllerAnimated:YES];
    [picker release];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    NSString* mediaType = (NSString*)[info objectForKey:UIImagePickerControllerMediaType];

    if ([mediaType isEqualToString:@"public.image"])
    {
        UIImage* image = (UIImage*)[info objectForKey:UIImagePickerControllerOriginalImage];
        //UIImage* image = [[UIImage alloc] initWithData:
        //                  [NSData dataWithContentsOfURL:
        //                   [NSURL URLWithString:
        //                    @"http://wild-facts.com/wp-content/uploads/2010/07/Diving_emperor_penguin.jpg"]]];

        [delivery addImage:image];
    }
    else if ([mediaType isEqualToString:@"public.movie"])
    {
        NSString* videoURL = (NSString*)[info objectForKey:UIImagePickerControllerMediaURL];
        [delivery addVideo:videoURL];
    }
    else
    {
        NSLog(@"Error: imagePickerController returned with unexpected type %@", mediaType);
    }

    [[picker parentViewController] dismissModalViewControllerAnimated:YES];
    [picker release];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    IGMedia* media = [mediaDisplayArray objectAtIndex:indexPath.row];

    UIViewController* detailViewController = 
                [media isMemberOfClass:[IGMediaImage class]]
                ? [[IGMediaImageDetailVC alloc] initWithImage:((IGMediaImage*)media).image]
                : nil;

    if (detailViewController != nil)
        [self.navigationController pushViewController:detailViewController animated:YES];

    [detailViewController release];
}

IGMediaImageDetailVC.h (I use a xib :P )

#import <UIKit/UIKit.h>


@interface IGMediaImageDetailVC : UIViewController {

}

@property (nonatomic, retain) UIImage* image;
@property (nonatomic, retain) IBOutlet UIImageView* imageView;

- (id)initWithImage:(UIImage*)anImage;

@end

IGMediaImageDetailVC.m

#import "IGMediaImageDetailVC.h"


@implementation IGMediaImageDetailVC

@synthesize image;
@synthesize imageView;

- (id)initWithImage:(UIImage*)anImage
{
    self = [super initWithNibName:@"IGMediaImageDetailVC" bundle:nil];
    if (self)
    {
        self.image = anImage;
    }
    return self;
}

- (void)dealloc
{
    [image release];

    [super dealloc];
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.imageView.image = self.image;
}

- (void)viewDidUnload
{
    [super viewDidUnload];

    [imageView release];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end

If there's anything I can do to make this post more legible, please let me know. I'll add things that don't work/replicate the problem to the appropriate list. Thanks for taking the time to read this!


I just figured out the problem, had to do with excessive memory use. Thanks goes to this amazing post: https://stackoverflow.com/questions/1282830/uiimagepickercontroller-uiimage-memory-and-more Basically, before ever displaying the image, I divide each dimension by 4, resulting in a total 1/16th of the memory I was using before. Here's the method I used (as per the awesome post):

+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize;
{
    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

In the method call, I pass in CGSizeMake(image.size.width/4, image.size.height/4)

Hope this was helpful!

0

精彩评论

暂无评论...
验证码 换一张
取 消