ukSeung iOS

[Swift] 메모리 관리 이미지 리사이징 ImageIO, VM: ImageIO_PNG_Data 본문

iOS/Swift

[Swift] 메모리 관리 이미지 리사이징 ImageIO, VM: ImageIO_PNG_Data

욱승 2023. 2. 19. 18:02

안녕하세요 욱승입니다.

요새 토이 프로젝트를 진행중인데 메모리 관련해서 이슈가 생겼는데 남겨두면 좋을것 같아서 포스팅 해봅니다! (태클 환영)

 

그럼

 

우선 결과부터 보면 이러함

이미지 리사이징 전
Xcode Memory Graph
이미지 리사이징 후

프로젝트 진행중 메모리가 기하급수적으로 증가하는걸 볼수 있는데 이것은 서버에서 불러오는 이미지 크기 및 해상도와 ImageView의 해상도 이미지 크기 및 해상도가 맞지않아 억지로 끼워넣고 원본이미지는 파일 크기가 너무 커 메모리가 기하급수적으로 증가하는 것.

그래서 이미지 리사이징이 필요한데

이미지 리사이징이란?

이미지가 커서 메모리를 많이 잡아먹다보면 메모리 부족으로 앱이 죽어버리는 경우가 생긴다고해요.

이러한 현상을 줄이고자 이미지 사이즈를 줄여 다시 만들어내는데 이것을 이미지 리사이징이라고 해요!

이미지작업을 위해서 사용할 클래스는 UIGraphicsBeginImageContext, UIGraphicsImageRenderer가 있는데 이둘의 차이는 구버전과 신버전의 차이라고 하네요

WWDC18에서는 UIGraphicsImageRenderer을 권장 하고있음 ! 

이미지 리사이징에 다양한 방법이 있겠지만 이 두가지 버전을 소개해볼까함

 

UIGraphicsBeginImageContext

// UIGraphicsBeginImageContext
func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage {

    let scale = newWidth / image.size.width
    let newHeight = image.size.height * scale
    UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
    image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage!
}

 

UIGraphicsImageRenderer

// UIGraphicsImageRenderer
func resize(image: UIImage, newWidth: CGFloat) -> UIImage {
    let scale = newWidth / image.size.width
    let newHeight = image.size.height * scale

    let size = CGSize(width: newWidth, height: newHeight)
    let render = UIGraphicsImageRenderer(size: size)
    let renderImage = render.image { context in
        image.draw(in: CGRect(origin: .zero, size: size))
    }
    
    return renderImage
}

 

사용법

func setProfileImage(_ imageView: UIImageView,_ urlString: String?) {
        guard let urlString = urlString else {
            imageView.image = UIImage(named: "NonProfile")
            return
        }
        let url = URL(string: urlString)
        //DispatchQueue를 쓰는 이유 -> 이미지가 클 경우 이미지를 다운로드 받기 까지 잠깐의 멈춤이 생길수 있다. (이유 : 싱글 쓰레드로 작동되기때문에)
        //DispatchQueue를 쓰면 멀티 쓰레드로 이미지가 클경우에도 멈춤이 생기지 않는다.
        DispatchQueue.global().async {
            DispatchQueue.main.async {
                imageView.kf.indicatorType = .activity
                imageView.kf.setImage(
                  with: url,
                  placeholder: nil,
                  options: [.transition(.fade(1.2))],
                  completionHandler: { result in
                  switch(result) {
                      case .success(let imageResult):
                      // UIGraphicsImageRenderer 방식
                      let resized = resize(image: imageResult.image, newWidth: 40)
                      imageView.image = resized
                      imageView.isHidden = false
                      case .failure(let error):
                          imageView.isHidden = true
                      }
                  })
            }
        }
    }

 

728x90
반응형