-오늘 한일
# 컴퓨터 응용 설계 팀프로젝트
1. 어제 못한 캐시 이용한 이미지 불러오기 공부
캐시를 하는 방법으로 두가지가 존재한다.
- 메모리 캐시
- 디스크 캐시
메모리 캐시 | 디스크 캐시 | |
특징 | - 앱의 메모리 일부분을 캐싱하는 곳에 사용한다. - 앱이 종료되면 사용하던 메모리를 OS에 반납하여 메모리 캐시가 되어 있던것들이 반납된다. |
- 데이터 형태로 파일에 저장하는 방식 - 디스크 캐시를 이용하면 이용할 수 록 앱의 용량이 커지게 된다. - 앱을 종료해도 캐시되었던 것이 삭제되지 않는다. |
이미지를 불러올 때 당연하겠지만 불러오는 속도는 메모리캐시 > 디스크 캐시 > 네트워크 통신 순으로 메모리 캐시가 가장 빠르다.
애플에서는 메모리 캐시를 지원하는 NSCache 클래스를 지원해 준다. 👍
class NSCache<KeyType, ObjectType>: NSObject where KeyType: AnyObject, ObjectType: AnyObject
NSCache 특징 |
- NSCache를 이용하면 메모리 캐시를 사용할 수 있고 thread-safeness를 지원해서 여러 쓰레드들에서 접근해도 개발자가 직접적으로 lock 할 필요가 없다. - NSCache는 NS Dictionary와 다르게 key객체를 복사하지 않는다고 합니다..? -> 공부를 더 해야할 것 같다. |
- 참조한 블로그에서는 NSDictionary의 경우 아래 사진과 같이 NSCopying을 따른다고 한다.
NSDictionary는 Key가 수정되었을 때 그에 해당하는 value를 찾기 위해 NSCopying을 했다면
NSCache의 경우에는 Cache된 데이터가 있을 때 서버에서 key값을 변경한 경우 해당 key값이 클라이언트에서도 변경이 되어야 하는데 변경이 되지 않으면 오류가 발생해서 NSCopying을 하지 않는 것 같다 (내 생각)
을 하자마자 블로그 글 아래부분에 써있었다...;;
팀 프로젝트에 적용 !
a. 메모리 캐시 적용
- 캐싱하는 부분
//메모리 캐시를 이용하기 위한 캐시key값 설정 여기서는 이미지 url을 사용하였다.
let cacheKey = NSString(string: "\(url)")
//메모리에 캐시된 이미지가 있는 경우
if let cacheImage = ImageCacheManager.shared.object(forKey: cacheKey){
img.image = cacheImage
return
}
- ImageCacheManger class
import UIKit
class ImageCacheManager{
static let shared = NSCache<NSString , UIImage>()
private init() {}
}
이미지 파일 로딩되는 시간이 매우 단축되었다!! 😀😀😀
메모리 캐시가 잘되고 있나보다 ㅎㅎㅎ
b. 디스크 캐시 적용
디스크 캐시 특징 |
- 휴대폰의 디스크에 파일로 이미지를 저장해 두었다가 불러오는 기능이다. - 메모리 캐시보다 속도가 상대적으로 느리기 때문에 메모리 캐시를 먼저 시도하고 이미지가 없는 경우 디스크 캐시를 시도한다. - FileManager를 사용하여 파일을 관리한다. (이름이 직관적이라 좋다 ㅎㅎ) Filemanager.default를 기본으로 사용한다고 한다. |
디스크 캐시를 사용하기 위해서 다음과 같은 변수가 필요하다.
guard let path = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first else {
return
} //파일의 경로를 표시하는 변수
var filePath = URL(fileURLWithPath: path)
filePath.appendPathComponent(url.lastPathComponent)
- 파일을 저장할 경로를 가져온다
- lastPathComponent를 이용하여 실제 이미지의 이름 (예시 dog.png) 만 사용한다.
- 파일이 있는지 확인하는 구문
if FileManager.default.fileExists(atPath: filePath.path) {
guard let imageData = try? Data(contentsOf: filePath) else {
return
}
guard let image = UIImage(data: imageData) else {
return
}
img.image = image
- 파일이 있는지 확인한다.
- imageData에 filepath를 이용해서 Data를 가지고 온다. 이때 Data는 실제 data형태
- 가져온 Data를 UIImage타입으로 변경시킨다.
- 그 후 이미지를 띄운다.
- 파일이 없는 경우 파일 생성하는 구문
if !FileManager.default.fileExists(atPath: filePath.path) {
FileManager.default.createFile(atPath: filePath.path, contents: resizeImg.pngData(),
attributes: nil)
img.image = resizeImg
}
- 파일이 없는 경우 파일을 생성하기 위해 png파일의 형태로 저장해 주었다.
- 실행 화면
- 디스크 캐시를 적용해서 앱 종료 후에 실행해도 이미지를 빠르게 불러온다.
c. 전체 코드
func load(img:UIImageView, url: URL, screenWidth: CGFloat) {
let cacheKey = NSString(string: "\(url)") //메모리 캐시를 이용하기 위한 캐시key값 설정 여기서는 이미지 url을 사용하였다.
//디스크 캐시에 필요한 변수
guard let path = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first else { return }
var filePath = URL(fileURLWithPath: path) //파일 경로
filePath.appendPathComponent(url.lastPathComponent) //이미지 실제 이름을 사용하는 lastPathComponent 사용
//메모리에 캐시된 이미지가 있는 경우
if let cacheImage = ImageCacheManager.shared.object(forKey: cacheKey){
img.image = cacheImage
}
else if FileManager.default.fileExists(atPath: filePath.path) { //디스크에 이미지가 히트된 경우 실행
guard let imageData = try? Data(contentsOf: filePath) else { return } //저장된 이미지 Data를 가져옴
guard let image = UIImage(data: imageData) else { return } //Data를 UIImage타입으로 변경
let resizeImg = image.resize(newWidth: screenWidth,newHeight: (screenWidth / 2))
img.image = resizeImg
}
else{ // 메모리 or 디스크에 캐시된 이미지가 없는 경우 네트워크 통신이 이루어진다.
DispatchQueue.global().async {
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
DispatchQueue.main.async {
//네트워크 통신을 하고 메모리와 디스크에 저장시킴
let resizeImg = image.resize(newWidth: screenWidth,newHeight: (screenWidth / 2)) //이미지 크기 조절
ImageCacheManager.shared.setObject(resizeImg, forKey: cacheKey) //메모리 캐시에 사용할 수 있게끔 올림
//디스크에 저장하기 위해 파일을 만들어서 디스크에 저장
if !FileManager.default.fileExists(atPath: filePath.path) {
FileManager.default.createFile(atPath: filePath.path, contents: resizeImg.pngData(), attributes: nil)
img.image = resizeImg
}
}
}
}
}
}
}
- 최대한 주석으로 설명을 써보았다.
# 참조한 블로그
1. https://beenii.tistory.com/187
'매일 공부 일기' 카테고리의 다른 글
(2022-11-14) 소소한 개발 일기 (0) | 2022.11.14 |
---|---|
(2022-11-13) 하루쯤은 공부말고 정보검색은 괜찮겠지 (0) | 2022.11.13 |
(2022-11-12) 소소한 코딩 공부 (0) | 2022.11.12 |
(2022-11-10) 소소한 개발 공부 (0) | 2022.11.10 |
(2022-11-09) 소소한 개발 공부 (0) | 2022.11.10 |