[SeSAC] October 12, 2023

✔︎ 오늘의 정리

  • PopUpButton의 menu 선택하기
  • PHPicker에서 추가된 사진이 계속 추가될 때
  • CustomSegmentedControl

 


PopUpButton의 menu 선택하기

        if let menu = weightUnitButton.menu?.children {
            menu.forEach { action in
                print(action)
                if action.title == pet.weightUnit.rawValue {
                    let element = action as? UIAction
                    element?.state = .on
                }
            }
        }

찢었다...

ㅜㅜ

다운캐스팅이 맞는 거 같은데 순간 생각나서 이.. 이거되나???? 하고 해봤더니 진짜됨...

ㅁㅊ다......

 

아무튼 뭘 해냈냐면 기존에 popUpButton으로 kg / g / lb 같은 단위를 선택할 수 있도록 했다. 저장할 때도 단위에 따라서 다르게 저장했는데 아니~~ 생각해 보니까 그럼 수정할 때도 팝업 버튼에 그거랑 같은 단위가 자동으로 떠야 사용자가 편할 거아닝가?

내가 내 무덤을 판 느낌이었지만 포기할 수 없었다 ,,

누가 먼저 만든 거 없나 찾아보다가 없길래 그냥 쓰자!!!!! 하고 써봤다...

삽질을 좀 하긴 했지만 뿌듯허다

 

menu?.children으로 불러온 친구는 UIMenuElement라서 .state가 없다...

 

ㅇ_ㅇ

 

그래서 이 친구를 UIAction으로 바꿔줘야 내가 원하는 선택된 상태로 뜨게 된다.

생각해 보면 UIMenuElement에는 UIAction을 뭐 안 바꾸고 그냥 넣었지 않은가??

그럼 UIMenuElement가 더 넓은 개념이라 UIAction 말고도 다른 넘들을 포괄하여 받아들일 수 있을 것이다

글서 다운캐스팅을 했더니... 짜잔~~~~~~

하 ㅋㅋ 다운캐스팅......... 배우고 알기만 알았지 이럴 때 사용하는거구나.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ.ᐟ 싶다 ㅁㅊ다 ...

 

오늘 진짜 삽질만 해서 블로그 올릴 게 없지 않나 싶었는데 와 이건 블로그 올령야지 대박 ㅋㅋ 하고 바로 썼다...

잘 쓴 코드는 아닌 것 같지만..... 그래두~~~~~~

.. ...

대박이당...........................................

 

 

 

 

 

 

PHPicker에서 동일한 사진이 계속 추가될 때

글로 하니 되게 엥? 무슨 소리지? 싶은데... 명확히 상황을 보자면 위 gif와 같다.

그러니까, PHPicker에서 먼저 사진을 추가하고 난 이후에 다시 사진을 추가하려고 할 때, 이전의 사진들이 기본으로 선택되어 있다. 이거까지는 아주 좋은데 문제가 있다면 미리 추가되어 있던 사진들이 같이 새로운 사진과 함께 올라간다는 게 문제였다.

 

 

그래서 기존에 images.append만 있던 코드에서 로직을 좀 짜주었다.

 

extension DiaryViewController: PHPickerViewControllerDelegate, AddDelegate {
    func openPhotoAlbum(_ sender: PHPickerViewController) {
        // picker 기본 설정!!
        self.present(sender, animated: true, completion: nil)
    }
    
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        // 이미지 클릭 시 화면 dismiss
        picker.dismiss(animated: true)
        
        for result in results {
            if result.itemProvider.canLoadObject(ofClass: UIImage.self) {
                let type: NSItemProviderReading.Type = UIImage.self
                result.itemProvider.loadObject(ofClass: type) { (image, error) in
                    if let image = image as? UIImage {
                        DispatchQueue.main.async {
                            print(self.images.count)
                            if !(self.images.contains(image)) {
                                print(self.images)
                                // image가 저장되는 게 달라서 ㅠㅠ 같은 이미지여도 각각 같은 이미지로 인식댐
                                self.images.append(image)
                            }
                        }
                    } else {
                        // 다시 시도 Alert
                        print(error?.localizedDescription)
                        self.sendOneSidedAlert(title: "이미지를 저장할 수 없습니다.", message: "한 번 더 시도해 주세요!")
                    }
                }
            }
        }
    }
}

해당 코드는 이러하다.

하지만~~~!!! ㅠ_ㅠ 주석에서도 알 수 있듯이 데이터를 가지고 오게 된다면 같은 이미지라도 컴퓨터는 다르게 인식하여 암 생각 없이 추가하게 된다.

그 어떤 로직을 짜도 돌아가지 않고 추가만 되길래 뭐지??? 했다

다른 곳들은 대체 어떻게 구현하는 거냐... ... 하고 봤더니 당근마켓은 그냥 추가한 것을 또 추가할 수 있도록 했드라. (껐다가 다시 켰을 때)

 

사실 UIImagePicker를 이용하면 그렇게 그냥 간단하게 구현할 수도 있을 것 같은데 좀 열받기도 하고 관련하여 방법을 찾아서 정리해 봤다 ㅋㅋ

 

근데 결국에는 이걸루 안 씀......

카메라를 사용하는 UIImagePicker는 identifier가 없어서 둘이 동시 적용이 안 되더라

 

아무튼... 삽질 과정이라도 적어놓으려구 한다 ㅋㅋ 

 

 

https://ios-daniel-yang.tistory.com/83

 

[Swift/TIL #9] PHPickerViewController에 대하여

[TIL #9] 2023 / 04 / 03 ~ 2023 / 04 / 06 사진을 가져오려 하는데 iOS 14 이상부터는 UIImagePickerController 대신 PHPickerViewController를 사용하라고 하더라고요. 그래서 오늘은 PHPickerViewController에 대해서 알아보겠

ios-daniel-yang.tistory.com

참고한 블로그는 요기

 

 

원하는 결과는 나왔다!

다만 문제가 있다면 카메라로 찍었을 때 image들이 초기화된다는 점과 카메라 이미지와 사진 보관함 이미지가 중첩이 안 된다는 것, ,, ^^

더 찾아보면 할 수 있겠지만 일단 구현이 바쁘기에~~~~!!! ㅠㅠ

다른 곳도 보면 다들 이전에 선택했던 이미지를 보여주기보다는 그냥 새로운 이미지를 추가하는 식으로 구현했더라

나도 그렇게 해야댈 거 같다...

 

 

아무튼~!

 

 

위에 전역변수로

    private var selections = [String : PHPickerResult]()
    private var selectedAssetIdentifiers = [String]()

식별자들을 담을 배열을 하나 생성해 준다.

 

 

extension DiaryViewController: PHPickerViewControllerDelegate, AddDelegate {
    func openPhotoAlbum(_ sender: PHPickerViewController) {
        
        var config = PHPickerConfiguration(photoLibrary: .shared())
        
        config.filter = .images
        config.selectionLimit = 5
        config.selection = .ordered
        
        config.preferredAssetRepresentationMode = .current
        
        // 이 친구를 통해서 선택된 이미지의 identifier를 비교함
        config.preselectedAssetIdentifiers = selectedAssetIdentifiers
        
        let imagePicker = PHPickerViewController(configuration: config)
        imagePicker.delegate = self
        
        self.present(imagePicker, animated: true)
    }

    private func displayImage() {
        
        // 순서대로 안 들어가길래 dispatchGroup을 이용해서 넣어줬다 ,, ^_^
        let dispatchGroup = DispatchGroup()
        var imagesDict = [String: UIImage]()
        
        for (identifier, result) in selections {
            dispatchGroup.enter()
            let itemProvider = result.itemProvider
            if itemProvider.canLoadObject(ofClass: UIImage.self) {
                itemProvider.loadObject(ofClass: UIImage.self) { image, error in
                    
                    guard let image = image as? UIImage else { return }
                    imagesDict[identifier] = image
                    
                    dispatchGroup.leave()
                }
            }
        }
        
        dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
            
            guard let self = self else { return }
            
            self.images.removeAll()
            
            for identifier in self.selectedAssetIdentifiers {
                guard let image = imagesDict[identifier] else { return }
                self.images.append(image)
            }
        }
    }
    
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true)
        
        var newSelections = [String: PHPickerResult]()
        
        for result in results {
            let identifier = result.assetIdentifier!
            newSelections[identifier] = selections[identifier] ?? result
        }

        selections = newSelections
        selectedAssetIdentifiers = results.compactMap { $0.assetIdentifier }
        
        if !selections.isEmpty {
            displayImage()
        } else {
            self.images = []
        }
    }

^_^ ......

 

 

이후 수정한 코드는 아래와 같다......

 

 

    // 5개까지 사진을 등록할 수 있도록 제한하기 위해서 picCount 변수를 맹글어 주었다.
    var picCount: Int = 0
    
    // 선택한 이미지를 모으는 친구 ,, ^_^
    private var images: [UIImage] = [] {
        didSet {
            collectionView.reloadData()
        }
    }
extension DiaryViewController: PHPickerViewControllerDelegate, AddDelegate {
    func openPhotoAlbum(_ sender: PHPickerViewController) {
        
        if 5 - picCount < 1 {
        	// 선택한 사진이 5개가 되면 추가하는 셀이 사라지도록 구성해 놨지만 
            // 혹시 모르니까!! 일단 Alert을 추가해 놓았다 ,, :3
            self.sendOneSidedAlert(title: "사진은 5장까지 추가할 수 있습니다!")
        }
        var config = PHPickerConfiguration(photoLibrary: .shared())
        
        config.filter = .images
        // 이럼 매번 창이 띄워질 때 사진 limit 안에서 사진을 선택할 수 있당
        config.selectionLimit = 5 - picCount
        config.selection = .ordered
        
        let imagePicker = PHPickerViewController(configuration: config)
        imagePicker.delegate = self
        
        self.present(imagePicker, animated: true)
    }
    
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        picker.dismiss(animated: true)
        
        // 이전 코드에서 사용했던 disPatchGroup은 가지고 왔다 ,, ^_^
        // 사유: 이 친구가 비동기로 동작하기 때문에 비교적 크기가 작은 순서대로 착착 쌓이게 돼서~~!!
        let dispatchGroup = DispatchGroup()
        
        var images = [UIImage]()
        
        for result in results {
            dispatchGroup.enter()
            let itemProvider = result.itemProvider
            if itemProvider.canLoadObject(ofClass: UIImage.self) {
                let type: NSItemProviderReading.Type = UIImage.self
                itemProvider.loadObject(ofClass: type) { [weak self](image, error) in
                    guard let self = self else { return }
                    if let image = image as? UIImage {
                        images.append(image)
                        dispatchGroup.leave()
                    } else {
                        // 다시 시도 Alert
                        print(error?.localizedDescription)
                        self.sendOneSidedAlert(title: "이미지를 저장할 수 없습니다!", message: "한 번 더 시도해 주세요!")
                    }
                }
            }
        }
        
        dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
            guard let self = self else { return }
            if self.images.count + images.count > 5 {
            // 요기도 혹시 몰라서 Alert 추가
                self.sendOneSidedAlert(title: "사진은 5장까지 추가할 수 있어요!")
                return
            } else {
            	// 하 ... 첨부터 이렇게 할 걸 그랬다
                // 추가 가능할 경우에는 picCount에 이미지 갯수를 추가해 주고 넘겨줌
                picCount += images.count
                self.images.append(contentsOf: images)
            }
        }
    }
    
}


extension DiaryViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    func takePhoto(_ sender: UIImagePickerController) {
        present(sender, animated: true, completion: nil)
    }
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        
        if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
            self.images.append(image)
            picCount += 1
        }
        
        picker.dismiss(animated: true, completion: nil)
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }
    
    func selectFile() {
        
    }
    
}


extension DiaryViewController: DeleteDelegate {
    func deleteImages(image: UIImage) {
        if let firstIndex = self.images.firstIndex(of: image) {
            self.images.remove(at: firstIndex)
            self.picCount -= 1
        }
    }
}

PHPicker를 띄울 때 갯수 제한을 자체로 해주기 위해서 picCount라는 변수를 썼는데 이것 말고도 좀,,, 더 괜찮게 하는 방법이 있지 않을까???? 싶다......

근데 지금 너무 바뻐서 그냥 하려고 한다

 

 

 

 

왜 갑자기 이 노래가 생각낫지?

아무튼...........

 

 

 

원래 시도했던 방법은 선택된 이미지에서 더 추가되어도 이전에 선택했던 이미지가 또 추가되지 않는 방법이었는데

지금은 그냥 새 picker를 띄워서 선택된 이미지가 picker에서 보이지 않도록 맹글어 버렸다 ,, ^_^6

삭제나 카메라 적용까지 생각한다면 이 방법이 진짜훨나은거같다

 

 

 

 

https://ios-daniel-yang.tistory.com/83

 

[Swift/TIL #9] PHPickerViewController에 대하여

[TIL #9] 2023 / 04 / 03 ~ 2023 / 04 / 06 사진을 가져오려 하는데 iOS 14 이상부터는 UIImagePickerController 대신 PHPickerViewController를 사용하라고 하더라고요. 그래서 오늘은 PHPickerViewController에 대해서 알아보겠

ios-daniel-yang.tistory.com

https://developer.apple.com/videos/play/wwdc2021/10046/

 

Improve access to Photos in your app - WWDC21 - Videos - Apple Developer

PHPicker is the simplest and most secure way to integrate the Photos library into your app — and it's getting even better. Learn how to...

developer.apple.com

참고한 블로그와 WWDC 문서는 이쪽!!

 

 

 

 

 

CustomSegmentedControl

https://ios-development.tistory.com/963

 

[iOS - swift] 2. UISegmentedControl - 커스텀 방법, PageViewController와 사용 방법

1. UISegmentedControl - 기본 사용 방법 2. UISegmentedControl - 커스텀 방법, PageViewController와 사용 방법 UISegmentedControl 커스텀 방법 클래스 준비 import UIKit final class UnderlineSegmentedControl: UISegmentedControl { } UISeg

ios-development.tistory.com

https://stackoverflow.com/questions/42755590/how-to-display-only-bottom-border-for-selected-item-in-uisegmentedcontrol

 

How to display only bottom border for selected item in UISegmentedControl?

I'm extremely new to iOS development and ran into some trouble while building an app for a course. I created a segmented control and its init function (shown below) is being called in the view

stackoverflow.com

 

 

 

 

 

 

아오 맨날 다른 오류 있음 이거까지... 해서 올려야즤 ㅋ 하다가 미뤄진ㄷ ㅏ,,

8일부터 미뤘기 땜에 오늘이라도 올리려구 한다.

 

 

나 출시할수잇겟지......

젭알

'TIL' 카테고리의 다른 글

[SeSAC] October 19, 2023  (3) 2023.10.19
[SeSAC] October 15, 2023  (2) 2023.10.16
[SeSAC] October 7, 2023  (0) 2023.10.07
[SeSAC] October 3, 2023  (3) 2023.10.04
[SeSAC] September 17, 2023  (0) 2023.09.20