Pregunta

When the user starts the app for the first time he gets a pop up and has to save an image. It works on the simulator and on the 4S. But when I start it with my 3G it gives me a SIGABRT error as soon as I chose a picture. I assume its because of the size of the picture which is too pick and therefore claiming all of the ram - But that is rather weird, because I make it much smaller. Here is the code:

- (void)viewDidLoad
{ 
    [super viewDidLoad];
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"bild"] == nil) { 
        picker = [[UIImagePickerController alloc] init];
        picker.delegate = self;
        picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        [self presentModalViewController:picker animated:YES];
    }
}

- (void)imagePickerController:(UIImagePickerController *) Picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    double compressionRatio=1;
    NSData *imageData=UIImageJPEGRepresentation([info objectForKey:@"bild"],compressionRatio);
    while ([imageData length]>5000) { 
        compressionRatio=compressionRatio*0.20;
        imageData=UIImageJPEGRepresentation([info objectForKey:@"bild"],compressionRatio);
    }

    UIImage *yourUIImage;
    yourUIImage = [info objectForKey:UIImagePickerControllerOriginalImage];
    imageData = [NSKeyedArchiver archivedDataWithRootObject:yourUIImage];
    [[NSUserDefaults standardUserDefaults] setObject:imageData forKey:@"bild"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    [self dismissModalViewControllerAnimated:YES];
}

I get the SIGABRT error at this line imageData = [NSKeyedArchiver archivedDataWithRootObject:yourUIImage];

Should I use another method to resize the image? Or should I save it as a local file and retrieve it everytime the app starts? (If its possible)

¿Fue útil?

Solución

You are using NSCoding to archive an UIImage into a NSData object.
Before iOS5 UIImage didn't implement the methods for NSCoding. You simply can't use archivedDataWithRootObject: with UIImages before iOS5.
That's why you get an exception on the iPhone 3G.

This is just a very educated guess because I can't confirm that with documentation or a test on a device but there are a lot of questions and forum posts around that ask how to implement NSCoding on UIImage.


and this whole block of code isn't called at all because [info objectForKey:@"bild"] will return nil. The info dictionary does not contain an object for the key bild. Documentation for UIImagePickerControllerDelegate_Protocol contains a List of valid keys

NSData *imageData=UIImageJPEGRepresentation([info objectForKey:@"bild"],compressionRatio);
while ([imageData length]>5000) { 
    compressionRatio=compressionRatio*0.20;
    imageData=UIImageJPEGRepresentation([info objectForKey:@"bild"],compressionRatio);
}

you probably want to use something like that:

NSData *data;
if ([[UIImage class] conformsToProtocol:@protocol(NSCoding)]) {
    // >= iOS5
    data = [NSKeyedArchiver archivedDataWithRootObject:image];
    // save so you know it's an archived UIImage object
}
else {
    // < iOS5
    data = /* your UIImageJPEGRepresentation method but this time with the key UIImagePickerControllerOriginalImage instead of "bild" */
    // save so you know it's raw JPEG data
}

Otros consejos

Edit: Another error is probably that you're looking for an object for the key "bild" within the info dictionary you're passed from the image picker controller. It will have no such key. You should pass the key UIImagePickerControllerOriginalImage to get at the image instead.

--

You're not throwing away the old imageData. If your problem is high memory consumption, you'll have to do away with the image data as you progressively shrink the image.

Additionally, an image may be too big anyway to fit within 5000 bytes. Your current code doesn't handle this gracefully. Eventually, the compression ratio will grow beyond 1.0 at which point the function will probably throw an exception.

I'd suggest resizing the image before trying to compress it heavily.

No matter how you make the image data smaller, your current code keeps all the old copies around until the next time the autorelease pool is drained. Since the data returned from UIImageJPEGRepresentation is autoreleased, you may try using an inline autorelease pool around every loop iteration to drain the data immediately.

If the SIGABRT is consistently happening at imageData = [NSKeyedArchiver archivedDataWithRootObject:yourUIImage]; then my feeling would be that it is likely to be that specific line, rather than a memory issue.

UIImage never used to conform to NSCoding, but the current docs say that it does. It could be that the 3G, which will be limited to iOS 4.2.1 is using a non-conformant version and so crashes when you try to archive, whereas the 4S on iOS 5 uses the new conformant version.

Try adding a category for NSCoding to UIImage and then rerun on the 3G. Example at http://iphonedevelopment.blogspot.com/2009/03/uiimage-and-nscoding.html

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top