ipfs + AsyncImage(with LazyStack, Nuke, Kingfisher)

EN·2023년 3월 31일
post-thumbnail

ipfs의 존재와 그리고 SwiftUI에서 URLSession을 활용한 AsyncImage를 연계해서 사용했을 때 마주쳤던 이슈에 대해서 정리해보고자 한다.

ipfs는 "Interplanetary file system"의 약자이다. 분산형 파일 시스템에 데이터를 저장하고 인터넷으로 공유하기 위한 프로토콜이다.

문제 상황:
Moralis API의 'get NFT by wallet'이라는 API를 사용해서 얻어온 json 파일의 image라는 key값의 url을 사용.
SwiftUI의 AsyncImage를 써서 보여주려고 했지만 한가지 문제가 생겼다.
1. 사진이 안뜸
2. 1번의 해결방법으로 해결했지만, 뜨는 시간이 매우 불규칙함.(늦게 뜨는것들은 8~10초 정도가 걸렸음)

해결 방법:
1. ipfs 주소 앞에 https://ipfs.io/ 라는 키워드를 붙여서 url로 만드는 방법
2. 이미지 캐싱

추가적인 이슈:
1. 스크롤을 할 때마다 비동기 이미지를 계속 불러오는 이슈
2. 만약 ipfs에서 저장하고 있는 이미지가 바뀐다면.. 이미지 캐싱을 수정해야 할 필요가 있을거같은데? 이건 무슨 방법으로 해야할까?
3. 만약 NFT가 굉장히 많은 지갑이라면?
4. 앱을 끌때 메모리를 해제? 킬때 해제?

해결 방법 1
일단 Moralis 사이트로 이동하자.
거기서 0x222cA2731e7677ce7A6Bdc7cA3273e144CD2941a <- 이 지갑 주소를 통해 조회해보자.

여기다가 입력하고 실행하면
컨트롤 + F를 눌러 'image'라는 키워드를 찾으면 나올것이다.

자 일단 코드를 보자.

그 실행 결과는 이렇게 나온다.

두번째, 네번째, 일곱번째에 대한 사진의 AsyncImageUrl에 뭔가 에러가 있는 것 같다.
참고로 AsyncImage를 표시하는 코드는 아래와 같다.

자 그럼 본론으로 들어가서,
ipfs를 어떻게 AsyncImage에서 보여줄지를 생각해보자.
구글링을 하면 간단하게 나온다.
ipfs://으로 시작하는 키워드를 https://ipfs.io/ipfs/로 대체하면 된다.
그럼 붙여보자.


이걸 실행하면

3초 안으로 모든 사진들이 나오는 것 같다.
하지만 8초가 지나서야 가운데 사진이 떴다.

근데 여기서 끝이 아니다. 또 한번 앱을 실행시켜주었다. 그리고 실행한 뒤 3초마다 스크린 샷을 찍은 결과 몇장을 보여주겠다.


저게 뜨기까지 8~10초가 걸렸다.


이건 또 이상이 없이 잘 뜬다.


이번엔 마지막 사진이 8초가 걸렸다.

원인을 알아보니 ipfs의 특성상 이런 문제가 발생할 수도 있다고 한다.

요러한 이슈들이 있을 수도 있다고 하네..

그래서 내 앱과 유사한 앱을 살펴봤었다. pado라는 앱인데, 이건 내 NFT자산을 조회하는 앱이다. 하지만 이 앱에서는 내 NFT이미지가 굉장히 빨리 뜬다. 그래서 좀 의아했었다. 어떻게했을까?

일단 이미지 캐싱을 써야할 것 같았다.

보통 캐싱 과정은
1. memory caching
2. disk caching -> 캐시 미스면? 3번으로
3. 서버 통신
아래와 같이 이루어진다.

memory caching는 NSCache를 사용하고,
disk caching은 UserDefaults(AppStorage), CoreData등을 사용한다.

Kingfisher라는 이미지 캐싱 방법이 있다고 해서, 한번 사용해보았다.

첫번째 이미지에 대해서 킹피셔를 적용해봤다.

다시 한 번 실행한 결과, 바로 뜨는것을 확인할 수 있다.

이제 모두 다 적용하니 잘 되는것을 볼 수 있었다.

추가적인 이슈에 대해서..
1. LazyVStack과 AsyncImage를 썼을 때, 스크롤할때마다 이미지를 다시 불러오는 문제가 있다.
이건 여기서 확인 가능하다. 나도 어플을 구현하다가 스크롤을 할 때마다 초기화가 되길래, 엥 뭐지 ? 싶었다. 스택오버플로우에서 어떤분이 해결하신 코드를 보고 내 코드에 적용해봤는데, 난 다행히 잘 해결되었다. LazyVStack을 쓰는 이유가 스크롤 할때 보이지 않는 뷰를 없애는 이유로 알고 있는데, 이 셀들이 또 보이면 비동기 이미지를 다시 호출해서 이런 이슈가 생기는 것 같다.

하나의 가설을 떠올렸는데, 킹피셔도 스크롤 할 때마다 계속 메모리를 참조하지 않을까? 라는 가설이 얼핏 스쳤다.

나의 생각을 직접 겪고, kingfisher에다가 이슈로 남기신 분이 있다.


이 사람은 LazyVStack안에 ForEach로 KFImage를 사용하였다.

심지어 엄청 천천히 스크롤 하셨는데도 이렇게 돼셨다고.. 아직 저런 경우를 겪지 않아서 잘 모르겠지만, SwiftUI4.0부터는 해결된 문제인 것 같다.

  1. NFT이미지가 변경될 경우
    다행히 특정 조건에서 메모리 캐시와 디스크 캐시를 지울 수 있는 기능이 있다.
    뭐 만약에 로그아웃을 했을 때나 앱을 종료했을 때 다시 캐싱된 이미지를 지워주면 다시 호출할 때 시간은 좀 걸리겠지만 앱을 사용하는 동안에는 잘 보일것이다!

  2. 너무 많은 NFT를 갖고있는 지갑일 경우
    이것도 Kingfisher에서 메모리 limit을 걸어놓을 수 있다고 한다.

  3. 앱을 끌때 메모리를 해제.. 하는 방법은 못찾아서 그냥 킬때 메모리를 해제하는 방법을 사용했다.

추가적으로..
Nuke라는게 있는데 이분 블로그를 우연히 들어가서 알게되었다.
메모리 효율이 더 좋다는데 이것도 나중에 써봐야겠다.

profile
iOS/JUJITSU

0개의 댓글