iOS는 가상 메모리 시스템을 통해 각 앱에 독립된 메모리 공간을 제공한다. 메모리는 크게 세 가지 유형으로 나눌 수 있다.
iOS의 메모리 관리는 ARC를 기반으로 합니다.
주요 특징:
ARC의 한계:
Xcode는 다양한 메모리 분석 도구를 제공합니다:
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// 캐시 데이터 제거
imageCache.removeAllObjects()
// 불필요한 리소스 해제
temporaryData = nil
// 재생성 가능한 데이터 정리
recreatableResources.removeAll()
}
func loadOptimizedImage(from url: URL) -> UIImage? {
let options: [CFString: Any] = [
kCGImageSourceShouldCache: false,
kCGImageSourceShouldCacheImmediately: false
]
guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, options as CFDictionary) else {
return nil
}
// 이미지 속성 확인
guard let image = CGImageSourceCreateImageAtIndex(imageSource, 0, options as CFDictionary) else {
return nil
}
return UIImage(cgImage: image)
}
고해상도 이미지의 메모리 사용량을 줄이는 핵심 기술입니다.
func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat) -> UIImage? {
// 기본 옵션 설정
let options = [kCGImageSourceShouldCache: false] as CFDictionary
guard let source = CGImageSourceCreateWithURL(imageURL as CFURL, options) else {
return nil
}
// 최대 차원 계산
let maxDimension = max(pointSize.width, pointSize.height) * scale
// 다운샘플링 옵션 설정
let downsampleOptions = [
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceShouldCacheImmediately: true,
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceThumbnailMaxPixelSize: maxDimension
] as CFDictionary
guard let image = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions) else {
return nil
}
return UIImage(cgImage: image)
}
class ImageCache {
static let shared = ImageCache()
private let cache = NSCache<NSString, UIImage>()
func setImage(_ image: UIImage, forKey key: String) {
cache.setObject(image, forKey: key as NSString)
}
func image(forKey key: String) -> UIImage? {
return cache.object(forKey: key as NSString)
}
func removeImage(forKey key: String) {
cache.removeObject(forKey: key as NSString)
}
func clearCache() {
cache.removeAllObjects()
}
}
클로저에서 순환 참조를 방지하는 방법:
class DataManager {
var completionHandler: (() -> Void)?
func fetchData() {
// [weak self] 사용으로 순환 참조 방지
completionHandler = { [weak self] in
self?.processData()
}
}
private func processData() {
// 데이터 처리 로직
}
}
// Weak 참조 예시
class Parent {
weak var child: Child?
}
// Unowned 참조 예시
class Customer {
unowned let creditCard: CreditCard
init(creditCard: CreditCard) {
self.creditCard = creditCard
}
}
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationDidEnterBackground(_ application: UIApplication) {
// 이미지 캐시 정리
ImageCache.shared.clearCache()
// 임시 데이터 정리
TemporaryStorage.shared.clearAll()
// 메모리 집중적인 리소스 해제
ResourceManager.shared.releaseMemoryIntensiveResources()
}
}
class ExampleViewController: UIViewController {
private var timer: Timer?
private var dataTask: URLSessionDataTask?
override func viewDidLoad() {
super.viewDidLoad()
setupTimer()
fetchData()
}
private func setupTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
self?.updateUI()
}
}
private func fetchData() {
dataTask = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
self?.handleResponse(data, response, error)
}
dataTask?.resume()
}
deinit {
timer?.invalidate()
dataTask?.cancel()
print("ExampleViewController deallocated")
}
}
iOS 앱 개발에서 메모리 최적화는 앱의 성능과 안정성에 직접적인 영향을 미치는 중요한 요소다.
이 글에서 다룬 내용들을 실제 프로젝트에 적용하면서, 지속적인 모니터링과 최적화를 통해 더 나은 앱을 만들어야겠다.