[iOS] Realm (4) 이미지 사용하기

린다·2021년 11월 3일
4

Learning iOS

목록 보기
12/13
post-thumbnail

✔️ 이미지 저장하기

이미지를 저장하는 방식은 크게 두 가지가 있다고 볼 수 있다.
첫번째는 사진을 데이터 타입으로 변환해서 Realm에 저장하는 것 인데 Realm 뿐만 아니라 다른 DB에서도 권장하지 않는 방법이다.
두번째는 애플이 관리하고 있는 Document 폴더 내에 저장하는 것 이다. 따라서 이번에는 Realm을 이용하여 원하는 이미지를 Document 폴더 내에 저장하는 과정을 구현해보았다.

현재는 사진을 단 한 장만 저장하기 때문에 테이블에 column을 더 추가하지 않고 유니크한 키를 이용하여 경로를 설정하여 저장하기로 했다.

먼저 사진을 저장하는 과정의 단계가 꽤나 되기 때문에 사진 저장하는 과정을 별도의 함수로 구현한다.

    func saveImageToDocumentDirectory(imageName: String, image: UIImage) {
        // 1. 이미지를 저장할 경로를 설정해줘야함 - 도큐먼트 폴더,File 관련된건 Filemanager가 관리함(싱글톤 패턴)
        guard let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {return}
        
        // 2. 이미지 파일 이름 & 최종 경로 설정
        let imageURL = documentDirectory.appendingPathComponent(imageName)
        
        // 3. 이미지 압축(image.pngData())
        // 압축할거면 jpegData로~(0~1 사이 값)
        guard let data = image.pngData() else {
            print("압축이 실패했습니다.")
            return
        }
        
        // 4. 이미지 저장: 동일한 경로에 이미지를 저장하게 될 경우, 덮어쓰기하는 경우
        // 4-1. 이미지 경로 여부 확인
        if FileManager.default.fileExists(atPath: imageURL.path) {
            // 4-2. 이미지가 존재한다면 기존 경로에 있는 이미지 삭제
            do {
                try FileManager.default.removeItem(at: imageURL)
                print("이미지 삭제 완료")
            } catch {
                print("이미지를 삭제하지 못했습니다.")
            }
        }
        
        // 5. 이미지를 도큐먼트에 저장
        // 파일을 저장하는 등의 행위는 조심스러워야하기 때문에 do try catch 문을 사용하는 편임
        do {
            try data.write(to: imageURL)
            print("이미지 저장완료")
        } catch {
            print("이미지를 저장하지 못했습니다.")
        }
    }

해당 함수를 저장 버튼을 클릭했을 때 실행해주면 되는데 이때 이미지 파일 이름은 해당 row의 PK값으로 설정해준다.

@objc func saveButtonClicked() {
        let task = UserDiary(diaryTitle: titleTextField.text!, content: contentTextView.text, writeDate: Date(), regDate: Date())
        try! localRealm.write {
            localRealm.add(task)
            saveImageToDocumentDirectory(imageName: "\(task._id).png", image: diaryImageVIew.image!)
        }
        dismiss(animated: true, completion: nil)
    }

저장이 완료된다면 다음과 같이 Documents 폴더 안에 이미지가 저장되는 것을 확인할 수 있다.

✔️ 이미지 불러오기

저장되어있는 이미지를 불러오는 과정은 도큐먼트 폴더 경로 구성 ➡️ 이미지 찾기 ➡️ UIImage로 불러오기 ➡️ UIImageView에 구성하기 단계로 나눠서 생각해볼 수 있다.

    func loadImageFromDocumentDirectory(imageName: String) -> UIImage? {
        
        // 1. 도큐먼트 폴더 경로가져오기
        let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
        let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
        let path = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
        
        if let directoryPath = path.first {
        // 2. 이미지 URL 찾기
            let imageURL = URL(fileURLWithPath: directoryPath).appendingPathComponent(imageName)
            // 3. UIImage로 불러오기
            return UIImage(contentsOfFile: imageURL.path)
        }
        
        return nil
    }

위의 메서드로 UIImage를 받아온 뒤 cellForRowAt 메서드에서 cell내의 UIImageView를 업데이트시켜주면 저장돼있는 이미지를 불러올 수 있다

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: searchTableViewCell.identifier, for: indexPath) as? searchTableViewCell else {
            return UITableViewCell()
        }

        let task = tasks[indexPath.row]
    
        cell.titleLabel.text = task.diaryTitle
        cell.contentLabel.text = task.content
        cell.diaryImageView.image = loadImageFromDocumentDirectory(imageName: "\(task._id).png")
        return cell
    }

✔️ 이미지 삭제하기

이미지를 삭제하는 코드는 처음에 이미지를 저장하는 코드와 거의 동일하다.
이미지를 삭제하고자 하는 해당 URL에 이미지가 저장돼있다면 FileManager를 이용하여 삭제하면 된다.

func deleteImageFromDocumentDirectory(imageName: String) {
        guard let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {return}

        let imageURL = documentDirectory.appendingPathComponent(imageName)
    
        if FileManager.default.fileExists(atPath: imageURL.path) {
            do {
                try FileManager.default.removeItem(at: imageURL)
                print("이미지 삭제 완료")
            } catch {
                print("이미지를 삭제하지 못했습니다.")
            }
        }
    }

0개의 댓글