2013-03-03 3 views
2

Я пишу приложение, которое займет несколько изображений из URL, превратит их в UIImage, а затем добавит их в библиотеку фотографий, а затем в пользовательский альбом. Я не думаю, что его можно добавить в альбом, не имея их в Camera Roll, поэтому я принимаю его как невозможное (но было бы идеально, если это возможно).Сохранение нескольких изображений быстро в iOS 6 (пользовательский альбом)

Моя проблема в том, что я использую код от this site, и он действительно работает, но как только он имеет дело с большими фотографиями, он возвращает несколько слов «Write Busy». Я успешно получил их все, чтобы сохранить, если я скопирую функцию внутри своего собственного кода завершения, а затем снова внутри следующего и так далее до 6 (наиболее я видел, что это было 3-4, но я не знаю размер изображения, и я мог бы получить некоторые действительно большие) - это привело к тому, что они не все были включены в пользовательский альбом, поскольку они ошибались на этом этапе, и не было никакого блока, чтобы заставить его повторять ,

Я понимаю, что фактическое сохранение изображения перемещается в фоновый поток (хотя я специально не устанавливаю это), так как мой код возвращается, как и все, до появления ошибок, но в идеале мне нужно ставить в очередь изображения, которые нужно сохранить на одном фоновом потоке, чтобы они происходили синхронно, но не замораживали пользовательский интерфейс.

Мой код выглядит следующим образом:

UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:singleImage]]]; 
    [self.library saveImage:image toAlbum:@"Test Album" withCompletionBlock:^(NSError *error) { 
     if (error!=nil) { 
      NSLog(@"Error"); 
     } 
    }]; 

Я удалил повторение кода в противном случае образец кода будет очень долго! Ранее существовал код NSLog.

Для моего тестового образца я имею дело с 25 изображениями, но это может быть легко 200 или около того, и может быть очень высоким разрешением, поэтому мне нужно что-то, что может надежно делать это снова и снова, не пропуская несколько изображений.

благодаря Роб

ответ

0

Если saveImage: toAlbum: withCompletionBlock он использует dispatch_async я боюсь, что для операций ввода/вывода слишком много потоков порождены: каждая задача записи вы вызываете заблокирован предыдущей (bacause все еще делает I/O в той же очереди), поэтому gcd создаст новый поток (обычно dispatch_async в global_queue оптимизируется gcd с помощью оптимизированного количества потоков).

Вы должны либо использовать семафоры, чтобы ограничить операцию записи фиксированным числом одновременно, либо использовать функции dispatch_io_, доступные из iOS 5, если я не ошибаюсь. Есть много примеров того, как это сделать с помощью обоих методов.

некоторые на лету код для придания идеи:

dispatch_semaphore_t aSemaphore = dispatch_semaphore_create(4); 
dispatch_queue_t ioQueue = dispatch_queue_create("com.customqueue", NULL); 

// dispatch the following block to the ioQueue 
// (for loop with all images) 
dispatch_semaphore_wait(aSemaphore , DISPATCH_TIME_FOREVER); 
[self.library saveImage:image 
       toAlbum:@"Test Album" 
    withCompletionBlock:^(NSError *error){ 
      dispatch_semaphore_signal(aSemaphore); 
    }]; 

поэтому каждый раз, когда вы будете иметь максимум 4 saveImage: toAlbum, как только один дополняет другой один заводится. , вам нужно создать пользовательскую очередь, например, выше (ioQueue), где нужно отправить код, который выполняет цикл for на изображениях, поэтому, когда семафор ожидает ожидания, основной поток не блокируется.

+0

Спасибо за ответ, к сожалению, я не знаком с семафорами, но я прочитаю их, поскольку они выглядят весьма полезными. Я только начал неделю назад! –

+0

Это хорошая ссылка, я думаю, http://mikeash.com/pyblog/friday-qa-2009-09-25-gcd-practicum.html, но она немного продвинута. – Ultrakorne

1

Мне удалось заставить его работать, удалив код сохраненного изображения и переместив его в свою собственную функцию, которая называет себя рекурсивно на массиве объектов, если он не работает, он повторно перебирает то же изображение обратно в функцию пока он не будет успешно работать и покажет «Готово» по завершении. Потому что я использую завершенный блок: от функции для завершения цикла, его единственный запуск одного файла за исключением.

Это код, который я использовал рекурсивно:

- (void)saveImage { 

if(self.thisImage) 
{ 
    [self.library saveImage:self.thisImage toAlbum:@"Test Album" withCompletionBlock:^(NSError *error) { 
     if (error!=nil) { 
      [self saveImage]; 
     } 
     else 
     { 
      [self.imageData removeObject:self.singleImageData]; 
      NSLog(@"Success!"); 
      self.singleImageData = [self.imageData lastObject]; 
      self.thisImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:self.singleImageData]]]; 
      [self saveImage]; 
     } 
    }]; 
} 
else 
{ 
    self.singleImageData = nil; 
    self.thisImage = nil; 
    self.imageData = nil; 
    self.images = nil; 
    NSLog(@"Done!"); 
} 

}

Чтобы установить это, я первоначально использовал массив UIImages годов, но это используется много памяти и очень медленно (я был тестирование до 400 фотографий). Я нашел гораздо лучший способ сделать это, чтобы сохранить NSMutableArray URL как NSString, а затем выполнить NSData GET внутри этой функции.

Следующий код - это то, что устанавливает NSMutableArray с данными, а затем вызывает функцию. Оно также устанавливает первый UIImage в память и сохраняет его под self.thisImage:

NSEnumerator *e = [allDataArray objectEnumerator]; 
NSDictionary *object; 

while (object = [e nextObject]) { 
    NSArray *imagesArray = [object objectForKey:@"images"]; 
    NSString *singleImage = [[imagesArray objectAtIndex:0] objectForKey:@"source"]; 
    [self.imageData addObject:singleImage]; 
} 

self.singleImageData = [self.imageData lastObject]; 
self.thisImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:self.singleImageData]]]; 
[self saveImage]; 

Это означает, что остальные геттеров для UIImage может содержаться в функции и единственный экземпляр UIImage можно контролировать. Я также регистрирую исходный URL-адрес в self.singleImageData, чтобы я мог удалить правильные элементы из массива, чтобы остановить дублирование.

Это переменные, которые я использовал:

self.images = [[NSMutableArray alloc] init]; 
self.thisImage = [[UIImage alloc] init]; 
self.imageData = [[NSMutableArray alloc] init]; 
self.singleImageData = [[NSString alloc] init]; 

Этого ответ должен работать для тех, кто с помощью http://www.touch-code-magazine.com/ios5-saving-photos-in-custom-photo-album-category-for-download/ для IOS 6 (проверено на прошивке 6.1) и должен привести все фотографии сохраняются корректно и без ошибок.

Смежные вопросы