Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- UITextView
- ribs
- UICollectionView
- 리펙터링
- SWIFT
- HIG
- Human interface guide
- Observable
- uiscrollview
- tableView
- Clean Code
- 스위프트
- Refactoring
- Xcode
- swiftUI
- MVVM
- uitableview
- 클린 코드
- combine
- Protocol
- collectionview
- 애니메이션
- ios
- map
- 리펙토링
- swift documentation
- rxswift
- clean architecture
- RxCocoa
- 리팩토링
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 8. Memory Deep Dive - 이미지 리사이징, 이미지 다운 샘플링 (ImageIO, ImageSource) 본문
iOS 응용 (swift)
[iOS - swift] 8. Memory Deep Dive - 이미지 리사이징, 이미지 다운 샘플링 (ImageIO, ImageSource)
jake-kim 2023. 12. 15. 01:06
1. Memory Deep Dive - iOS 메모리 운영체제 기초 (가상 메모리, 페이징, clean memory, dirty memory, compressed memory)
2. Memory Deep Dive - Memory를 줄여야 하는 이유 (+ 앱 메모리 사용량 아는 방법)
3. Memory Deep Dive - Memory Footprint (페이징, Compressed 메모리)
4. Memory Deep Dive - Memory Footprint 프로파일링 방법 (Allocation, Leaks, VM Tracker, Virtual memory trace)
5. Memory Deep Dive - Memory Footprint 프로파일링 방법 (2) (Xcode Memory Debugger, Memory Graph, Memgraph)
6. Memory Deep Dive - Memory Footprint 프로파일링 방법 (3) (vmmap, leaks, heap, malloc_history)
8. Memory Deep Dive - 이미지 리사이징, 이미지 다운 샘플링 (ImageIO, ImageSource)
9. Memory Deep Dive - 백그라운드에서 메모리 최적화하는 방법
ImageIO - 다운 샘플링
- UIImage는 resizing하기에는 많은 비용이 필요
- 메모리에 original image를 그대로 저장하기에는 위험이 있어서 메모리에서 decode하기전에 다운 샘플링이 필요 (decode관련 개념은 이전 포스팅 이미지 로드 매커니즘 글 참고)
- ImageIO는 image 사이즈와 메타 데이터를 dirty memory로 사용하지 않고 읽기가 가능
- dirty memory 개념은 이전 포스팅 글, iOS 메모리 운영체제 기초 (가상 메모리, 페이징, clean memory, dirty memory, compressed memory) 참고
- 메모리에 original image를 load하기전에 imageIO를 통해서 사이즈를 파악하는것이 핵심
- UIGraphics와 같은 UIImage API를 사용하면 메모리에 이미지 전체를 적재하므로 상당히 비효율적
- ImageIO를 사용하여 다운 샘플링된 결과 이미지만 dirty memory에 올리는것이 목적
ImageIO를 안쓰는 일반적인 방식
- 보통 ImageIO를 사용하지 않으면, 이전 포스팅 글에서 알아보았듯이 UIGraphicsBeginImageContextWithOptions가 아닌 UIGraphicsImageRenderer를 사용하여 이미지 렌더링을 수행
import UIKit
class ViewController: UIViewController {
private let imageView = UIImageView()
override func viewDidLoad() {
...
}
func downloadWithResizeV1() {
guard let url = URL(string: "https://cdn.pixabay.com/photo/2023/11/30/07/51/bridge-8420945_1280.jpg") else { return }
downloadImageData(from: url) { [weak self] data in
guard let data, let image = UIImage(data: data) else { return }
DispatchQueue.main.async {
self?.imageView.image = image
}
// resizing image
let scale = 0.2
let size = CGSize(width: image.size.width * scale, height: image.size.height * scale)
let renderer = UIGraphicsImageRenderer(size: size)
let renderedImage = renderer.image { _ in
image.draw(in: .init(origin: .zero, size: size))
}
DispatchQueue.main.async {
self?.imageView.image = renderedImage
}
}
}
}
private extension ViewController {
func downloadImageData(from url: URL, completion: @escaping (Data?) -> Void) {
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else {
completion(nil)
return
}
completion(data)
}.resume()
}
}
- 위 코드의 문제점: url로부터 가져온 이미지 원본 자체를 dirty memory에 올려서 메모리 효율이 매우 안좋아짐 (dirty memory 개념은 이전 포스팅 글 참고)
ImageIO를 통한 이미지 리사이징 최적화
- CGImageSourceCreateWithURL로 인스턴스 획득
let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)!
- 이미지의 크기 설정 및 몇개의 파라미터를 통해 리사이징된 이미지 획득
let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)
let options: [CFString : Any] = [
kCGImageSourceThumbnailMaxPixelSize: 100,
kCGImageSourceCreateThumbnailFromImageAlways: true
]
let scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)
- 얻어진 CGImage를 UIImage로 감싸서 사용
- dirty memory에 이 scaledImage만 올리게 되어 메모리 효율이 높고 이전 코드보다 50%더 빠른 이점
완성 코드)
func downloadWithResizeV2() {
let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)!
let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)
let options: [CFString : Any] = [
kCGImageSourceThumbnailMaxPixelSize: 100,
kCGImageSourceCreateThumbnailFromImageAlways: true
]
let scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)!
let image = UIImage(cgImage: scaledImage)
imageView.image = image
}
cf) 이 이미지 다루는 것들을 백그라운드에서 최적화 할 수 있는데 이 내용은 다음 포스팅 글에서 계속...
* 전체 코드: https://github.com/JK0369/ExImageIO
* 참고
'iOS 응용 (swift)' 카테고리의 다른 글
Comments