티스토리 뷰

반응형

 

안녕하세요 :) Zedd입니다.

기록용 글입니다!

 

PHImageRequestOptions에 있는 프로퍼티 쪼끔씩 정리하다 보니 분산되어서 보기가 힘들다.

생각난 김에 모든 프로퍼티 정리를 해놓으면 좋을 것 같다는 생각.

 

PHImageRequestOptions


PHImageRequestOptions은

 PHCachingImageManager.default().requestImage(for: asset,
                                              targetSize: targetSize,
                                              contentMode: .aspectFill,
                                              options: options, // 여기
                                              resultHandler: { (image, info) in { .. } 

requestImage에서 options에 들어가는 타입이다.

말 그대로 Image / request / options 이다.

image manager에게 요청한 사진 asset의 representations에 영향을 주는 옵션 Set이라고 보면 된다.

 

isSynchronous

Photos프레임워크에서 이미지 요청을 동기적으로 처리할지 여부를 묻는 프로퍼티.

false가 기본값.

false면 requestImage(for:targetSize:contentMode:options:resultHandler:)가 즉시 반환.

true면 requestImage(for:targetSize:contentMode:options:resultHandler:)는 이미지 데이터가 준비되거나 오류가 발생할때까지 호출 스레드 차단. true면 Photos는 result handler block을 정확히 한 번 호출. 

note : background 스레드에서만 동기 요청을 수행할 것.

 

deliveryMode

요청된 이미지 품질 및 delivery priority.

이렇게 3가지 케이스가 있으며 기본값은 opportunistic 이다.

위에서 언급한 isSynchronous와 deliveryMode는 상당히 밀접한 관계를 가지고 있다.

PHImageManager의 requestImage가 두번 호출되는 이슈글에 자세히 설명되어있긴 한데, 다시 하자면

1. 비동기 요청의 경우, Photos 프레임워크는 resultHandler블록을 2번 이상 호출 할 수 있다.

2. Photos는 블록을 호출하여 "고품질 이미지를 준비하는 동안" 일시적으로 표시하기에 적합한 저품질 이미지를 제공

3. 고품질 이미지가 준비되면, Photos프레임워크는 resultHandler를 다시 호출하여 이를 제공.

이 기본 메커니즘(?)이다.

resultHandler가 2번 이상 호출되기 때문에, resultHandler에서 전역변수에 append를 하거나 하면 

오른쪽처럼 같은 이미지가 2개 이상 들어갈 수 있다. (왼쪽이 정상)

1. isSynchronous false임 && deliveryMode 따로 설정 안함 → deliveryMode == opportunistic

2. isSynchronous false임 && deliveryMode 설정 함 → deliveryMode == 설정한 deliveryMode

3. isSynchronous true임 && deliveryMode 따로 설정 안함 → deliveryMode == highQualityFormat

4. isSynchronous true임 && deliveryMode 따로 설정 함(예를들어 fastFormat) → deliveryMode == highQualityFormat

deliveryMode의 기본값은  opportunistic이지만,

내가. isSynchronous를 true로 설정하면 deliveryMode의 기본값은 highQualityFormat이 된다.

 

Q : isSynchronous를 true로 했는데 왜 deliveryMode가 highQualityFormat이 돼..?

A :

1.  (비동기 상황 == isSynchronous가 false) Photos는 블록을 호출하여 "고품질 이미지를 준비하는 동안" 일시적으로 표시하기에 적합한 저품질 이미지를 제공

2. isSynchronous를 true로 설정

3. isSynchronous는 true면 (고품질) 이미지 데이터가 준비되거나 오류가 발생할때까지 호출 스레드 차단. 

4. "고품질 이미지를 준비하는 동안" 일시적으로 표시할 저품질 이미지를 받는건데, 나 그런거 필요없고 그냥 고품질 이미지 데이터 준비될 때 까지 기다릴게

5. 고품질 이미지 == highQualityFormat

그래서 isSynchronous가 true일 때 highQualityFormat가 기본값이 되는거고, 다른 deliveryMode를 설정해도 소용이 없는거다. 

왜냐? 난 고품질 이미지 데이터 받을때 까지 기다릴거고, 기다린 다음에 받을거거든

 

fastFormat은 고품질 이미지를 빠르게 로드 못하겠으면 저품질 그냥 받겠다는거다.

근데 잘 생각해보자.

1. isSynchronous가 true == 나 (고품질) 이미지 데이터가 준비되거나 오류가 발생할때까지 기다릴게.

2. 근데 deliveryMode는 fastFormat으로 지정 ^^! 고품질 이미지 빠르게 로드 안되면 저품질줘~~!!

뭔가 상반되는 걸 느낄 수 있는데, 맞다.

fastFormat은 isSynchronous프로퍼티가 false일 때만 사용이 가능하다.

 

resizeMode

요청된 이미지의 크기를 조정 방법을 지정하는 모드.

이렇게 3가지 case가 있고 기본값은 fast다. 

none : 응 resize안해

fast : 이미지 target Size와 비슷하거나 약간 더 큰 크기로 효율적으로 조정. 

여기서 target Size는

 PHCachingImageManager.default().requestImage(for: asset,
                                              targetSize: targetSize, // 여기
                                              contentMode: .aspectFill,
                                              options: options, 
                                              resultHandler: { (image, info) in { .. } 

 

fast를 사용하면 사진에서 이미지 서브 샘플링을 사용하여 target Size와 대략적으로 일치하는 크기로 이미지를 빠르게 제공 할 수 있다고 한다.

exact : target Size랑 정확하게 일치하도록 이미지 크기를 조정. fast보다 덜 효율적.

*normalizedCropRect를 사용하여 잘린 이미지를 요청하는 경우 exact를 선택해야한다.

 

normalizedCropRect

원본 이미지의 잘린 버전을 요청하기 위한 사각형. CGRect타입. 

기본값은 CGRectZero. 

origin은 왼쪽 상단 모서리. {0.0,0.0}

이미지 종횡비와 관계없이 반대쪽 모서리. {1.0,1.0} 

crop rectangle을 지정하는 경우, resizeMode를 exact으로 할 것. 

let options = PHImageRequestOptions()
options.resizeMode = .exact
options.normalizedCropRect = CGRect(x: 0.5, y: 0.5, width: targetSize.width, height: targetSize.height)

대충 이렇게 줬다.

왼쪽 상단 모서리가  {0.0,0.0}이고 반대편 모서리가 {1.0,1.0} 이므로 x와 y의 값은  0 ~ 1 사이어야 한다.

나는 x, y 둘다 0.5를 줬고, width랑 height은 알아서들 주셈ㅎ

0.5기 때문에 정확히 center를 중심으로 우하단에 사각형이 만들어질거다. 

원본, normalizedCropRect를 준 사진

아무튼 이렇게 쓰는거다.

한가지 참고할만한 사항은 이 normalizedCropRect은 원본사진에 적용된다는거다.

사실 가장 끝에 있는 어피치는 편집이 된 상태이다. normalizedCropRect은 편집된 이미지에 또 사각형을 만드는게 아니라 원본 이미지에 만든다는 점! 

그래서 정의도 다시 보면,

원본 이미지의 잘린 버전을 요청하기 위한 사각형. 

이다.

 

version

요청할 이미지의 버전이다.

이렇게 3가지 케이스를 가지고 있다.

기본값은 문서에 이게 기본값이다! 라고 나온게 안보이는데; 찍어보면 current로 나온다.

current : 모든 편집 내용을 반영한 최신 버전의 이미지 asset을 말한다.

unadjusted : 조정이 없는 원본 버전.  만약 이미지가 편집된 상태라면 이미지는 편집이 수행되기 전 asset의 상태를 반영한다.

original : 원본 버전. 편집 내용에 관계없음.이미지 asset에 여러 형식의 데이터가 포함된 경우, 결과 이미지 데이터는 최고 품질 형식(highest quality format)을 사용.

예를 들어 RAW 및 JPEG 데이터가 모두 포함 된 자산의 경우 Photos는 RAW 데이터를 반환. 

 

Q : unadjusted도 원본이고..original도 원본이다?

A :

둘다 원본을 주는건 맞는 것 같음. 다만 original이 최고 품질을 반환을 보장하는 듯. 

그래서 unadjusted나 original을 주면

이렇게 어피치가 편집된 이미지임에도 불구하고 불러오면 원본이미지를 가져오게 된다.

편집된 이미지를 보여주고 싶으면 기본값이 current니...아무것도 안해도 된다.

 

isNetworkAccessAllowed

사진이 iCloud에서 요청된 이미지를 다운로드 할 수 있는지 여부를 지정하는 값이다.

false가 기본값.

1. isNetworkAccessAllowed false && 만약 이미지가 로컬 기기에 없고 iCloud에만 있음 -> 못불러옴. 

* result handler의 PHImageResultIsInCloudKey 를 사용해서 네트워크 acess가 필요한 사진인지 아닌지를 볼 수 있음.

2. isNetworkAccessAllowed true && 만약 이미지가 로컬 기기에 없고 iCloud에만 있음 -> iCloud에서 이미지를 다운로드함.

다운로드 진행상황에 대해 알림을 받으려면 progressHandler 프로퍼티를 이용할 것. 

options.progressHandler = { (progress, error, stop, info) in
     print("progress: \(progress)")
}

대충 이런식으로 쓰는 듯.

반응형