IOS

[iOS] Filemanager with Image Download

   안녕하세요 이번에는 이미지를 다운받아 파일 디렉토리에 저장한후 불러오는 것을 해보겠습니다.

이번에 날씨 어플을 만들면서 API에서 제공하는 아이콘이 없으면 한번에 다 내려받아 디렉토리에 저장하고 다음에는 저장할 필요가 없도록 구현했었는데요 사용한 방법을 공유해 보겠습니다.

이미지를 다운받을때 사용한것은 URL Session이 아니라 Alamofire를 사용했습니다.

  • 먼저 파일매니저를 사용할때는 UserDefault와 비슷하게 FileManager.default를 기본으로 사용합니다.
  • 그리고 파일이 저장될 경로인 도메인을 설정해 주어야하는데 이 디렉토리는 종류가 많으니 원하시는 디렉토리를 지정해서 사용하면됩니다.
  • 일단 제가 구현한 방법을 먼저 말씀드리고 코드를 보여드리겠습니다.
    1. 날씨 정보를 API를 통해 요청할때 들어오는 이미지의 이름을 받아 파일매니저가 일치하는 이미지가 있는지 검사합니다.
    2. 검사한후 이미지가 없다면 이미지를 모두 (약 14개정도)를 다운로드 하고 파일매니저에 저장합니다.
    3. 이미지가 있다면 불러와서 UIImage로 변환후 데이터를 넘겨줍니다.

#FileManager Save

func saveImage(_ image: UIImage,_ name: String) {
        let url = "http://openweathermap.org/img/wn/\(name)@2x.png"

        guard let path = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first else { return }

        var filePath = URL(fileURLWithPath: path)
        filePath.appendPathComponent((url as NSString).lastPathComponent)

        if !fileManager.fileExists(atPath: filePath.path) {
            fileManager.createFile(atPath: filePath.path,
                                   contents: image.pngData(),
                                   attributes: nil)
        }
    }
  • 여기서 url은 이미지를 받을 주소를 의미합니다.
  • path는 저장될 경로를 지정하고, filePath.appendPathComponent 는 경로에 생성될 파일이름을 나타냅니다. 여기서 lastPathComponent는
    let url = "http://openweathermap.org/img/wn/\(name)@2x.png" 이 주소에서 마지막 / 의 뒷부분 즉
    (name)@2x.png 를 말합니다
  • if 문은 파일이 이미 존재하는지 확인하고 없다면 파일을 생성합니다. atPath는 장소, contents는 타입을 의미합니다.

#FileManager Load

func loadImage(_ name: String) -> UIImage {
        let url = "http://openweathermap.org/img/wn/\(name)@2x.png"
        guard let path = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first else { return UIImage() }

        var filePath = URL(fileURLWithPath: path)
        filePath.appendPathComponent((url as NSString).lastPathComponent)

        if fileManager.fileExists(atPath: filePath.path) {
            guard let imageData = try? Data(contentsOf: filePath) else {
                return UIImage()
            }
            guard let image = UIImage(data: imageData) else {
                return UIImage()
            }
            return image
        }
        return UIImage()
    }
  • FileManager에서 파일을 불러올때 가장 중요한것은 파일의 존재여부를 체크하는 fileExists와 데이터를 가져오는 Data(contentsOf: filePath) 이부분입니다.
    여기서 Data 메서드는 지정한 데이터를 말그대로 data형태로 가져옵니다. 여기서 가져온 데이터를 변환해주어야 원하는 타입의 데이터를 얻을수 있습니다
  • let image = UIImage(data: imageData) 이부분이 Data를 → Image로 변환하는 부분입니다.

#Download Image

func downloadWeatherIcon(_ name: String, completion: @escaping (UIImage?, String, Error?) -> Void) {
            let url = "http://openweathermap.org/img/wn/\(name)@2x.png"
            AF.download(url)
                .downloadProgress { progress in
                    print("Download Progress: \(progress.fractionCompleted)")
                }.response { response in
                    if response.error == nil, let imagePath = response.fileURL?.path {
                        let image = UIImage(contentsOfFile: imagePath)
                        completion(image, name, nil)
                    } else {
                    print(ServiceError.impossibleToGetImageData)
                    completion(nil, name, nil)
                }
            }
        }
  • 처음으로 이미지를 다운로드 할때 어려웠던 것은 그냥 일반적으로 JSON데이터를 받을때와 똑같이 요청했더니 받을수 없었던 것입니다... 그래서 아 이방법이 아니구나 하고 찾아보니 downloadProgress가 있었고 다음과 같이 작성하였습니다. 방법은 url을 지정하고 response를 체크하고 데이터를 컴플리션을 통해 처리하면 됩니다.

Image를 체크하는 것은 위의 코드를 살펴보면 fileExists를 이용해 간단히 체크할수 있기때문에 넣지 않겠습니다.

'IOS' 카테고리의 다른 글

[iOS] Google Place Autocompletion ( 검색 자동완성 )  (0) 2021.01.11
[iOS] CoreData C.R.U.D  (0) 2021.01.11
[TIP] iOS, Swift 개발자 Road Map  (0) 2020.09.29