포스트

3주차 과제 (7)

Lv4

Cell 클릭시 새로운 화면 띄우기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
extension TableViewController : UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        if let CellDetailVC = self.storyboard?.instantiateViewController(identifier: "CellDetailViewController") as? CellDetailViewController {
            
            CellDetailVC.titleString = lists[indexPath.row].title
            
            self.present(CellDetailVC, animated: true)
        }
        
        
    }
    
}

present를 사용하여 새로운 화면을 띄우는것으로 하였고, 이때 제목이 그대로 전달이 되게끔 구현해두었다.

아직 여기에 어느기능을 더 구현할지 생각중이다.

여기까진 Easy

새로운 VC에 간단한 일기형식으로 내용을 담게하는 기능을 구현할까 싶다.

아니면 이미지 업로드만 하는식으로 할지 고민중이다.

내일까지 Udemy공부를 끝마치고 생각해보자.

공부하면서 아이디어가 떠오를지도.

imageUpload 버튼 구현하기.

참고영상은 초반부 까지만,

구식 버전이긴 하지만 만드면서 전체적인 시퀀스를 이해하는데 도움이 되었다.

버튼을 하나 만들고 해당 버튼을 통해 이미지를 업로드 하려고 한다.

우선 UIImagePickerControllerDelegate, UINavigationControllerDelegate를 채택해주자.

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
31
32
33
34
extension CellDetailViewController : UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    @IBAction func uploadImageBtn(_ sender: UIButton) {
        
        var pickerController = UIImagePickerController ()
        
        pickerController.sourceType = .photoLibrary // 사진 라이브러리에서 선택
        pickerController.allowsEditing = true // 이미지를 선택하고 편집할수 있게
        
        pickerController.delegate = self // 델리게이트 위임
        
        self.present(pickerController, animated: true)
        
        
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        self.dismiss(animated: true)
        
        let selectedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage
        
        self.detailImageView.image = selectedImage

    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
       
        self.dismiss(animated: true)
        
    }
    
}

여기서 핵심은 2개의 프로토콜을 채택해줘야하며, pickerController를 객체화 하여 구현하는 것이다.

그리고 UIImagePickerController.InfoKey.editedImage 이부분에 editedImage는 위에

pickerController.allowsEditing = true이게 없으면 editedImage를 했을때 사진이 보이지 않는다.

그럴땐 originalImage로 바꿔서 설정하면 된다.

이젠 DB에 넣어보도록 해보자.

FireBase와 연동시켜보기

우선 FireBase Storage를 활성화 시킨다.

DB와는 다르다.

storage를 만들어 주었다.

Docs대로 하면 되기에 어려울 건 없을것 같다.

한번 만들어 보자.

참고영상참고자료 을 보고 참고하며 작성했다.

참고자료를 통해서 FireBase의 Storage에 어덯게 이미지를 업로드하고, 가져오는지에 대해서 알아보았다.

내가 원했던 자료가 그대로 있어서 좋았다.

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
func uploadImage(image: UIImage, completion: @escaping (URL?) -> Void) {
        guard let imageData = image.jpegData(compressionQuality: 0.4) else { return }
        let metaData = StorageMetadata()
        metaData.contentType = "image/jpeg"
        
        let imageName = UUID().uuidString + String(Date().timeIntervalSince1970)
        
        let firebaseReference = Storage.storage().reference().child("\(imageName)")
        firebaseReference.putData(imageData, metadata: metaData) { metaData, error in
            firebaseReference.downloadURL { url, _ in
            completion(url)
        }
    }
}
    
func downloadImage(urlString: String, completion: @escaping (UIImage?) -> Void) {
    let storageReference = Storage.storage().reference(forURL: urlString)
    let megaByte = Int64(1 * 1024 * 1024)
        
    storageReference.getData(maxSize: megaByte) { data, error in
        guard let imageData = data else {
            completion(nil)
            return
        }
        completion(UIImage(data: imageData))
    }
}

uploadImage함수의 가장 큰 특징은 UUID를 주었다는 점이다. 이전에 자바를 배울때 이미지를 업로드할때는 일반 이미지명이 아닌 UUID로 하여 하나의 고유 이미지 파일명을 주는게 포인트였다.

왜냐하면 어떤 중복된 이름이 나올지 모르기 때문이다.

그리고 downloadImage함수는 url주소에 있는것을 가져와서 이미지로 리턴하는 내용이다.

대부분은 Firebase Storage와 관련되어있다.

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
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

        guard let selectedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage else {
            return
        }
        
        imageManager.uploadImage(image: selectedImage) { url in
            if let url = url {
                self.dbManager.addImage(title: self.titleLabel.text!, imageTitle: url.absoluteString)
            }
        }

        self.detailImageView.image = selectedImage
        
        picker.dismiss(animated: true)
        
    }
    
    
func getImage() {
    guard let urlString = imageUrl else { return }
        
    imageManager.downloadImage(urlString: urlString) { [weak self] image in
        self?.detailImageView.image = image
    }
}

이미지를 선택하고 나면 위의 uploadImage함수가 작동이 되면서 이미지를 업로드하면서 handler를 통해 url을 가져온것을 absoluteString을 통해 절대주소로 반환을 하고 그값을 현재 화면에 표시되어있는 title과 같은 field의 imageTitle값을 변경하게 해주었다.

그리고 getImage에서는 해당 url을 받아 가져와서 ViewDidload에 넣음으로써 화면이 올라가자마자 이미지가 보이게 했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
extension TableViewController : UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        if let CellDetailVC = self.storyboard?.instantiateViewController(identifier: "CellDetailViewController") as? CellDetailViewController {
            
            CellDetailVC.titleString = lists[indexPath.row].title
            
            if lists[indexPath.row].imageTitle != "" { // 이미지 파일을 업로드 한 경우
                CellDetailVC.imageUrl = lists[indexPath.row].imageTitle
            } else { // 이미지 파일을 업로드 하지 않은 경우
                CellDetailVC.imageUrl = "https://firebasestorage.googleapis.com/v0/b/todolist-1a790.appspot.com/o/upload-image-icon.png?alt=media&token=52da5077-bebf-4f39-8692-14b376f6f7a6"
            }
            self.present(CellDetailVC, animated: true)
        }
        
        
    }
    
}

이때 새로 만들거나, 이미지를 업로드를 하지않은 Field의 경우 imageTitle이 ""으로 되어잇으므로,

그냥 클릭하면 에러가 발생하게 된다, 없는 url을 통해 값을 가져오려고 하기에 getImage와 충돌이 생겨버린다.

그래서 샘플 이미지를 하나 등록하여, 이미지를 업로드 하지 않은 경우엔 ImageView가 있다는것을 표시하기 위해 샘플이미지를 업로드하였고, 해당 이미지 주소를 적음으로써 예외 경우를 처리하였다.

작동화면은 다음과 같다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.