2012-08-27 4 views
1

업데이트 :이 문제는 또한 원인에 대한 자세한 치료, 여기에보고했다 : 내 경우목표 - C : UIImageWriteToSavedPhotosAlbum() + 비동기 = 문제

UIImageWriteToSavedPhotosAlbum saves only 5 image out of 10. Why?

뿐만 아니라의 오류 : "쓰기 사용 중"-이 문제는 장치 속도와 관련이있는 것으로 보입니다. 아마도 수동으로 스레딩이나 이와 유사한 방법을 다루는 몇 가지 해결책이있을 수 있습니다.하지만 아래의 Tommy의 답변에서 영감을 얻어 이미지 저장을 연재했습니다.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

상황 :

for-loop를 사용하여 이미지의 큰 컬렉션을 카메라 롤에 저장하려고합니다 (이미지 수는 사용자 입력에 따라 다르며 1, 2, 3 또는 이론적으로 수백 일 수 있음). 이미지는 NSSet으로 지정되며 for 루프가 완료된 후에 NSSetnil으로 설정됩니다 (다만 NSArray을 쉽게 수행 할 수 있음). 나는 분리 된 스레드에서 이미지를 저장 UIImageWriteToSavedPhotosAlbum()을 사용하고

은 (NSThreaddetachNewThreadSelector:toTarget:withObject: 클래스 메소드를 사용하여), 메인 스레드에서 UIActivityIndicator 회를 시작.

문제 :

내가 ~ 5 ~ 5가 출력 로그에서이 오류가 발생한 후 모든 이미지보다 더 밖으로 저장하려고 : 예를 들어

*** -[NSKeyedUnarchiver initForReadingWithData:]: data is NULL

이하자를의 9 개의 이미지를 내보냈다 고합니다. for-loop는 NSLogging에 의해 확인 된 9 개의 이미지를 모두 통과하지만 위의 오류를 약 4 회 반복하고 카메라 롤에 5 개의 이미지 만 저장합니다.

루프에 중단 점을 추가하고 각 반복 사이에 두 번째 또는 두 번 대기하면 불만없이 올바르게 저장됩니다. 그래서 ..

이론 : 내 기록과 관찰을 바탕으로

, UIImageWriteToSavedPhotosAlbum() 명확하게 비동기 적으로 실행하고 내 응용 프로그램과 함께 계속 어떻게 든 '너무 느리다'이다.

동 기적으로 (주 스레드에서 이상적으로) 실행되도록하는 간단한 방법이 있습니까? 내가 저장하려고하는 이미지에 참조 횟수를 추가하는 실험을 해봤지만 (1) 해커가 느껴진다. (2) 관계없이 문제를 해결하지 못했다.

조언이 도움이 될 것입니다. 감사!

+0

메인 스레드 잠금이 의미 활동 표시하지 않습니다 생명 있는. 앱이 멈춘 것처럼 보입니다. – danielbeard

+1

예, 'UIImageWriteToSavedPhotosAlbum'은 (는) 비동기 적으로 실행됩니다. 오류 로그는 저장하려는 이미지가 Null 인 것처럼 들립니다. 이미지 데이터를 확인하십시오. – fannheyward

+0

@danielbeard - 네, 맞습니다, 죄송합니다 - ** 상황 ** – toblerpwn

답변

3

여러 이미지를 동시에 작성하지 않으려면 UIImageWriteToSavedPhotosAlbum의 완료 대상 및 선택기를 사용하여 꼬리 재귀 양식을 구현할 수 있습니다.

- (void)writeSetToSavedPhotosAlbum:(NSMutableSet *)images 
{ 
    if(![images count]) return; 

    UIImage *imageToSave = [[[images anyObject] retain] autorelease]; 
    [images removeObject:imageToSave]; 
    NSLog(@"I shall now write image %@", imageToSave); 

    UIImageWriteToSavedPhotosAlbum(
      imageToSave, 
      self, 
      @selector(writeSetToSavedPhotosAlbum:), 
      images); 
} 

편집 : 같은 뭔가 또한 매우 더 간단한 작업을하는 것입니다 당신이 ALAssetsLibrary-writeImageToSavedPhotosAlbum:orientation:completionBlock:, 완료 블록을 걸립니다과 같은 결과를 얻을 수 있는지 볼 가치가있을 수 있습니다.

+0

나는 이걸 약간 실험 할 것이지만 확인 만하면됩니다. ** 나는 모두를 쓰면서 100 % OK입니다. 즉시 이미지 **. 귀하의 대답은 이것을 할 수있는 방법이있을 수 있음을 의미합니다. 이 루프는 모든 이미지를'UIImageWriteToSavedPhotosAlbum()'에 넘기는 것에 대한 나의 구현 일뿐입니다 .. – toblerpwn

+0

죄송합니다.'UIImageWriteToSavedPhotosAlbum'가 원하는 경우에도 작업을 병렬 처리하지 못하도록 여러 이미지를 한꺼번에 쓰지 않기로했습니다. 그래서 꼬리 재귀 응답은 강제로 직렬 변환을하고 관계없이 쓸 수 있습니다. 따라서 Apple 코드에 문제가있는 경우 해결 방법이 될 수 있습니다. 자산 라이브러리에 일련의 이미지 세트를 직접 전달하고 선호하는 일정대로 모든 이미지를 쓰도록 요청하는 방법은 없습니다. – Tommy

+0

나는 너의 것과 비슷한 방법을 사용하여 문제를 다소 해결했다. (나는 질문을 세부 사항으로 업데이트 할 것이다). mainthread가 실제 이미지를 작성하기 전에 이제 '완료'되었기 때문에 현재 활동 표시기에 혼란을 야기하고 있지만 이제는 해결할 수없는 별도의 문제가 있습니다. :) – toblerpwn

0

문서에서 비동기 적으로 알림을 받겠습니다. 이게 효과가 있을지 궁금해 : 저장하려는 각 이미지에 대해 블록 작업을 만들고 기본 작업 큐에 추가하십시오. 종류 :

for (UIImage *toSave in imagesToSave) 
{ 
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
     UIImageWriteToSavedPhotosAlbum(toSave, target, selector, ctx); 
    }]; 
} 

도움이 될만한 가치가있을 수도 있습니다.

+0

좋은 생각, Carl, 내 시도에 대한 주사위 없음 (몇 군데에서 이것을 테스트 함). – toblerpwn

+0

예, 이것은 아마도 좋은 생각이 아니었을 것입니다. 그러나 동시 NSOperation 하위 클래스를 구현하는 것이이 작업에 적합합니다. –

+0

말하기 힘들다 - 애플의 방법 (또는이 경우 함수인가?)은 그 자체의 마음을 가지고 있으며, 불행히도 그 마음은 한 번에 몇 가지 요청 만 처리 할 수있다 :) 내 앱의 다음 버전 , 나는 이것을 실험 할 것이다. (동시에 2의 시리얼 세트를 실행한다. - 만약 그것이 작동한다면, 3을 시도하고, 그것이 작동한다면, 4 등을 시도한다.)하지만 나는 몇 주간 떨어져있다. 그 순간부터, 연속적으로, 한 번에 하나씩 절약하는 것은해야 할 것입니다. – toblerpwn

6

나는 확실히 이미지가 저장됩니다 순차적으로 만들기 위해 ALAssetsLibrary과 dispatch_queue을 사용하여이 코드 워크 이미지 저장에

ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; 
dispatch_queue_t queue = dispatch_queue_create("com.myApp.saveToCameraRoll", NULL); 

[images enumerateObjectsUsingBlock:^(UIImage *image, NSUInteger idx, BOOL *stop) { 

    dispatch_async(queue, ^{ 

     dispatch_semaphore_t sema = dispatch_semaphore_create(0); 

     [library writeImageToSavedPhotosAlbum:image.CGImage metadata:metaData completionBlock:^(NSURL *assetURL, NSError *writeError) { 

      if (writeError) { 
       // handle the error 
      } 
      else { 
       if (image == [images lastObject]) { 
        dispatch_async(dispatch_get_main_queue(), ^{ 
         // perhaps indicate to the user that save has finished 
        }); 
       } 
      } 

      dispatch_semaphore_signal(sema); 

     }]; 

     dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 
     dispatch_release(sema); 
    }); 
}]; 
0

을 :

UIImageWriteToSavedPhotosAlbum([self screenshot], nil, nil, nil); 

UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"Save" message:@"Photo saved to album" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; 
[alert show];