2014-10-03 5 views
13

iOS 8에 새로운 PHAssetChangeRequest 클래스를 사용하여 사진 라이브러리에 큰 사진 배치를 저장하려고합니다. 문제는 사진을 저장하는 데몬이 다소 많은 수의 사진으로 예기치 않게 충돌하는 것 같습니다 (나는 대략 500를 시도하고있다). 누구든지이 한계를 극복하는 방법을 알고 있습니까? 데몬 자체의 메모리 사용 문제입니까? 아래의 첫 번째 두 개의 로그 문 사이에 이 아니기 때문에이 없으므로 변경 블록의 제한 시간 제한이 될 수도 있습니다. 이 같은 거의 새로운 사진 프레임 워크에서 슈퍼 복잡한 모델과 디자인을 처리 할 수 ​​있었어야 무엇 때문에새 사진 프레임 워크를 사용하여 큰 사진 배치를 저장 하시겠습니까?

assetsd 데몬은 이미 사용 사례를 차지하지할까요? 설명서 샘플 자체는 사진을 저장하는 기능을 보여줍니다.

여기 내 코드 예제입니다 :

[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ 
    for (NSURL * url in fileURLs) { 
     PHAssetChangeRequest * assetReq = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:url]; 
    } 
    NSLog(@"Added %d assets",fileURLs.count); 
} completionHandler:^(BOOL success, NSError *error) { 
    if (!success){ 
     NSLog(@"%@",error); 
    } 
}]; 

그리고 이것은처럼 내 출력 모습입니다 :

... Added 501 assets 
... Connection to assetsd was interrupted or assetsd died 
... Error Domain=NSCocoaErrorDomain Code=-1 "The operation couldn’t be completed. (Cocoa error -1.) 

나는 심지어 PHPhotoLibrary에 동기 performChangesAndWait 방법을 시도했지만이 같은 문제가 있습니다.

나는 제안/아이디어에 열려있어 붙어있다! :(

+0

비슷한 문제가 발생합니다. 4 개의 이미지를 저장하고 작동하지만 이전 이미지를 대체하기 위해 4 개의 이미지를 다시 저장하려고하면이 오류가 발생합니다. 내가 해결책을 찾았을 때 나는 당신에게 돌아갈 것이다. – Aggressor

+0

@Aggressor 사진 라이브러리에서 기존 사진을 "대체"하는 방법을 정말로 모르겠다. 당신은 그들을 삭제하고 다시 추가 할 수 있습니다. –

+0

이 오류는 메모리 과부하로 인한 것 같습니다. 나는 UIImage의 파일 크기를 줄 였고 문제가 해결되었습니다. 보고 싶다면 코드를 게시 할 수 있습니다. – Aggressor

답변

-1

이 그러나 그것은 해결하고, 진정으로이 문제에 대한 해결책이 아니다. 당신은 여전히 ​​성공적으로 카메라 롤/사진 응용 프로그램에 파일을 저장하기 위해 이전 ALAssetsLibrary를 사용할 수 있습니다.

ALAssetsLibrary* lib = [[ALAssetsLibrary alloc] init]; 
[lib writeImageDataToSavedPhotosAlbum:imageData metadata:nil 
         completionBlock:^(NSURL *assetURL, NSError *error) 
{ 
    // start saving your next image 
}]; 

이 저장하려는 모든 사진을 반복 할 때 AssetsLibrary의 단일 인스턴스를 사용하는 것이 좋습니다. 첫 번째 이미지 저장이 완료 될 때까지 기다렸다가 다음 저장을 기다리는 것이 좋습니다.

필요한 경우 assetURL을 PHAsset에 연결합니다.

+ (PHFetchResult *)fetchAssetsWithALAssetURLs:(NSArray *)assetURLs 
            options:(PHFetchOptions *)options 
0

이미지를 대량으로 처리 할 때 ARC의 최신 시대에도 메모리 관리에 매우주의해야합니다. 처리 할 이미지가 많았으며 (크기 조정시 50+) CGImageSourceCreateThumbnailAtIndex() as suggested by the answer here을 선택했습니다. 매우 효율적인 ImageIO를 사용합니다. 나는 나머지 한 유일한 문제는 내가 creationRequestForAssetFromImageAtFileURL

for (ALAsset *asset in assets) { 
     @autoreleasepool { 
      resizedImage = [self thumbnailForAsset:asset maxPixelSize:JPEG_MAX_DIMENSION]; 
     // do stuff here 
    } 
} 
1

대신 @autoreleasepool {} 내에 대한 루프를 포장하지 않는 한 어떤 이유로 여전히 메모리에 꽉 것이라고, 나는이 방법을 사용하고 완벽했다 10 개 이미지

UIImage *thisImage=[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@",serverInfo,self.URLs[indexPath.row]]]]]; 
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ 
     PHAssetChangeRequest * assetReq = [PHAssetChangeRequest creationRequestForAssetFromImage:thisImage]; 
     NSLog(@"Added %ld assets",(long)indexPath.row); 
    } completionHandler:^(BOOL success, NSError *error) { 
     if (!success){ 
      NSLog(@"%@",error); 
     } 
}]; 
0

이 아이디어는 작은 일괄를하고있다 (이 코드 부분은 tableView:cellForRowAtIndexPath: 반복된다). PHPhotoLibrary::performChanges은 변경 요청을 한 번 모두 제출하므로 완료 할 수 있어도 대리인이나 차단의 진행 상황에 대한 업데이트를 얻을 수 없습니다. 2017 WWDC 세션 "What's New in Photos APIs"에는 정확하게 수행되는 샘플 응용 프로그램 "Creating Large Photo Libraries for Testing"이 함께 제공됩니다. 각 performChanges에는 10 개의 이미지가 제출되고 UI 업데이트는 performChanges의 완료 블록에서 이루어지며 하나의 배치가 처리 될 때까지 스레드를 차단하는 세마포어가 있습니다.나는 여기에 중요한 코드 조각을 게시하도록하겠습니다 : generateImagesAndWriteToDisk

private func addPhotos() { 
    let batchSize = min(photosToAdd, maxBatchSize) 
    if batchSize <= 0 || !active { 
     isAddingPhotos = false 
     active = false 
     return 
    } 

    workQueue.async { 
     let fileURLs = self.generateImagesAndWriteToDisk(batchSize: batchSize) 
     self.createPhotoLibraryAssets(with: fileURLs) 

     DispatchQueue.main.async { 
      self.addPhotos() 
     } 
    } 
} 

private func createPhotoLibraryAssets(with imageFileURLs: [URL]) { 
    photoLibrarySemaphore.wait() // Wait for any ongoing photo library 

    PHPhotoLibrary.shared().performChanges({ 
     let options = PHAssetResourceCreationOptions() 
     options.shouldMoveFile = true 
     for url in imageFileURLs { 
      let creationRequest = PHAssetCreationRequest.forAsset() 
      creationRequest.addResource(with: .photo, fileURL: url, options: options) 
     } 
    }) { (success, error) in 
     if !success { 
      print("Error saving asset to library:\(String(describing: error?.localizedDescription))") 
     } 
     self.photoLibrarySemaphore.signal() 
    } 
} 

당신이 10 개 사진 URL을 정도의 배치를 반환 할 무엇도 당신의 방법으로 교체해야하는 방법입니다. 나는 개인적으로 재귀 적 글쓰기를 좋아하지 않는다. 코드는 비 재귀 스타일로 쉽게 변경할 수 있습니다.