1

Когда пользователь запускает приложение в первый раз, он получает всплывающее окно и должен сохранить изображение. Он работает на симуляторе и на 4S. Но когда я начинаю с моего 3G, он дает мне ошибку SIGABRT, как только я выбрал картинку. Я предполагаю, что из-за размера изображения, которое слишком подбирается и, следовательно, требует всего барана, - но это довольно странно, потому что я делаю его намного меньше. Вот код:Приложение работает отлично на 4S, но падает на 3G, из-за SIGABRT

- (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]; 
} 

Я получаю ошибку SIGABRT на этой линии ImageData = [NSKeyedArchiver archivedDataWithRootObject: yourUIImage];

Следует ли использовать другой способ для изменения размера изображения? Или я должен сохранить его как локальный файл и получить его каждый раз, когда приложение начнется? (Если возможно)

ответ

6

Вы используете NSCoding для архивирования UIImage в объект NSData.
До того, как iOS5 UIImage не реализовал методы NSCoding. Вы просто не можете использовать archivedDataWithRootObject: с UIImages до iOS5.
Вот почему вы получаете исключение на iPhone 3G.

Это всего лишь очень образованное предположение, потому что я не могу подтвердить это с документацией или тестом на устройстве, но есть много вопросов и сообщений на форуме, которые спрашивают, как реализовать NSCoding в UIImage.


и весь этот блок кода не вызывается вообще, потому что [info objectForKey:@"bild"] вернется nil. Словарь информации не содержит объекта для ключевого билда. Документация для UIImagePickerControllerDelegate_Protocol содержит 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); 
} 

вы, вероятно, хотите использовать что-то вроде этого:

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 
} 
+0

Спасибо за ваш ответ. Я пробовал это так, но, похоже, он не работает. Он не увольняет сборщика. Но может быть, потому что я, возможно, внедрил это неправильно? – Blade

3

Редактировать: Еще одна ошибка, вероятно, в том, что вы ищете объект для ключевого слова «bild» в словаре информации, которое вы передали из контроллера выбора изображения. У этого не будет такого ключа. Вы должны передать ключ UIImagePickerControllerOriginalImage, чтобы получить изображение.

-

Вы не выбрасывая старую imageData. Если ваша проблема связана с высоким потреблением памяти, вам придется покончить с данными изображения, когда вы постепенно уменьшаете изображение.

Кроме того, изображение может быть слишком большим, чтобы соответствовать 5000 байт. Ваш текущий код не обрабатывает это изящно. В конце концов, коэффициент сжатия будет превышать 1.0, после чего функция, вероятно, вызовет исключение.

Я предлагаю изменить размер изображения, прежде чем пытаться его сжать.

Независимо от того, как вы уменьшаете данные изображения, ваш текущий код хранит все старые копии до тех пор, пока в следующий раз пул авторасчетов не будет исчерпан. Поскольку данные, возвращаемые с UIImageJPEGRepresentation, автореализовываются, вы можете попробовать использовать встроенный пул автозапуска вокруг каждой итерации цикла, чтобы немедленно слить данные.

+0

Эй, спасибо за ваш быстрый ответ. Я использую ARC. Итак, как я могу использовать данные дренажа немедленно, так как autorelease, выпуск и т. Д. Не работают с ARC? – Blade

+0

Измените цикл while на цикл do-while и измените imageData на локальную переменную блока в '@autoreleasepool {...}'. Когда вы найдете что-то, что собираетесь сохранить, назначьте его реальным imageData. – Jesper

1

Если SIGABRT последовательно происходит в imageData = [NSKeyedArchiver archivedDataWithRootObject:yourUIImage]; тогда мое чувство было бы, что это, скорее всего, быть конкретной линией, а не проблемой памяти.

UIImage никогда не использовался для соответствия NSCoding, но текущие документы говорят, что это так. Возможно, что 3G, который будет ограничен iOS 4.2.1, использует несоответствующую версию и поэтому сбой при попытке архивирования, тогда как 4S на iOS 5 использует новую совместимую версию.

Попробуйте добавить категорию для NSCoding в UIImage, а затем снова запустить 3G. Пример: http://iphonedevelopment.blogspot.com/2009/03/uiimage-and-nscoding.html

+0

Спасибо, я сделаю это :) – Blade