티스토리 뷰

반응형

안녕하세요 :) Zedd입니다.

오늘 해볼거는 내 사진앨범에 있는 이미지를 가져오거나, 카메라로 찍은 이미지를 가져올거에요.


너무 잼나겠다 그쵸 ㅎㅎ

오늘 우리가 만들어볼거는 



바로 요런거 입니다 ㅎㅎ (아 ㅠㅠ 매일 gif올리기만 하면 이렇게 느리게 재생되는지 모르겠어요 ㅠㅠㅠㅠ이거 해결법 아시는분....)

지금은 제 사진앨범에가서 이미지를 가져오기만 했지만, 폰으로 하면 카메라도 사진을 찍어서 이미지를  이미지뷰에 놓는 것도 가능합니다 :)


자. 그럼 시작해봅시다 XD



내 사진앨범/카메라에서 이미지 가져오기




1. 프로젝트를 생성한다.


2. main 스토리보드로 간다.


우리가 최종적으로 만들고 싶은 화면은

저렇게 위에 Navigation bar가 있고, 아래에는 image View가 있는 구성이죠?


3. Navigation bar, image View 추가해주기


하나하나 추가해줘봅시다.  오른쪽 인스펙터 부분에서 찾아서 추가해주세요.

Navigation Bar를 추가하고싶지 않으면, Navigation Controller를 임베디드 해주세요 :)







자, 그리고 



Navigation Bar는 이렇게 이루어져있는데요, 지금 우리가 추가한 Navigation Bar는



이렇게 되어있죠? 저 Title부분을 더블클릭하면, 



이렇게 편집이 가능하게 바뀐답니다. 자신이 원하는 제목으로 해주세요.

그리고 이제 오른쪽에 "버튼"을 추가할 차례에요.



4. Navigation Bar오른쪽에 버튼추가하기



Button을 추가하셔도 됩니다. 똑같아요. 

저는 이건 Navigation Bar니까 Bar Button Item을 추가해줄게요.

그리고 이 버튼역시 더블클릭하면 편집이 가능해집니다.

이렇게 더블클릭해서 +모양을 직접 쳐서 편집해도되지만,


버튼을 클릭하고, 오른쪽 Attribute Inspector에 가보면,



이렇게 기본적인 액션에 대한 것들이 있는데, 저기서 Add를 누르시면 



이렇게 +모양으로 바뀌는 것을 볼 수 있습니다. 직접 키보드로 치는 것 보다 훨씬 크게 나오죠?

하나하나 눌러보시면, 아이폰에서 많이 본 아이콘?들이 많은 것을 볼 수 있습니다 :)


이제 기본적인 구성은 끝난 것 같네요 XD

그럼 이제 뭘해야 할까요?


네. IBOulet과 IBAction을 추가해줄 차례네요. 

음..image View는 이미지를 바꿔줄 때를 생각하여 IBOulet변수가 있으면 좋겠지만, 

Button은 딱히 IBOulet가 필요없을 것 같아요.


대신 Button은 눌렀을 때, 어떤 액션(Action Sheet가 뜨는 액션)이 나와야하니까, IBAction은 필요하겠죠?


그럼, image View - IBOulet, Button - IBAction을 추가해줘봅시다.


5. Button과 image View의 IBOulet과 IBAction추가하기



컨트롤을 누른채, View Controller로 가져오시면 추가가 되는 건 다들 아시죠?ㅎㅎ

자, 이제 다음 스텝으로 넘어가봅시다. 

IBAction에 액션을 추가해주는 작업이요 ㅎㅎ


+버튼을 누르면, 이렇게 Action Sheet가 떠야겠죠? 


6. Add Button에 액션 추가하기 - Action Sheet


저번에 alert View에 대해 글을 썼었는데, Alert View를 잘 모르시는 분은 읽고오는 것을 추천드립니다. 간단한 Alert 예제가 있어요 :)

Action Sheet도 완전히 똑같아서 읽고오시면 쉽게 하실 수 있을거에요


왕초보를 위한 Alert View사용해보기


@IBAction func addAction(_ sender: Any) {

let alert =  UIAlertController(title: "원하는 타이틀", message: "원하는 메세지", preferredStyle: .actionSheet)

let library =  UIAlertAction(title: "사진앨범", style: .default) { (action) in self.openLibrary()

}

let camera =  UIAlertAction(title: "카메라", style: .default) { (action) in

self.openCamera()

}

let cancel = UIAlertAction(title: "취소", style: .cancel, handler: nil)

alert.addAction(library)

alert.addAction(camera)

alert.addAction(cancel)

present(alert, animated: true, completion: nil)

}


저기 UIAlertAction의 원형 기억나시나요?


세번째 파라미터는 handler였죠?

이 Action Sheet가 클릭되었을 때 할 행동을 클로져로 만들어준거랍니다. :)

Openlibrary와 OpenCamera는 제가 따로 만들어준 함수에요. 만약에 사진앨범 Action Sheet를 클릭하면, 저 클로져가 수행되고, 최종적으로 Openlibrary()함수가 실행되겠죠?ㅎㅎ


본격적으로 Openlibrary와 OpenCamera를 구현하기전에, 해야할 작업이 있어요. 


7. Delegate채택과 UIImagePickerController인스턴스 생성


class ViewController: UIViewController {


let picker = UIImagePickerController()

...

override func viewDidLoad() {

super.viewDidLoad()

picker.delegate = self

}

...

extension ViewController : UIImagePickerControllerDelegate,

UINavigationControllerDelegate{


}

Xcode안에 자체적으로 이미지를 선택을 더 수월하게 할 수 있게 Delegate를 만들어놨어요. UIImagePickerController. 이름만 들어도 이미지를 픽?하는 컨트롤러인게 감이 오시죠?


근데 갑자기 무슨 UINavigationControllerDelegate?

이건 왜해준걸까요? 


저도 궁금해서 찾아봤는데, 저랑 똑같은 궁금증을 가지신 분이 계시더라구요.

여기에 가시면, 질문과 답변을 영어로 볼 수 있습니다 ^^..


Q : UIImagePickerControllerDelegate를 선언 할 때 UINavigationControllerDelegate를 선언해야하는 이유를 분명히 알 수 있을까? 

A : 정확하게 번역을 못하겠어서, 여기저기서 찾은것을 종합했어요 ㅠㅠ

 UIImagePickerControllerDelegate의 delegate 속성은 UIImagePickerControllerDelegate와 UINavigationControllerDelegate 프로토콜을 모두 구현하는 객체로 정의되어있다. 

(위에서 해준 picker.delegate =  self) self를  picker.delegate에 할당하려면 self는 UINavigationControllerDelegate 타입이어야 한다. 

지금, picker의 델리게이트를 UINavigationControllerDelegate에 위임해준 것인데, 대리자는 사용자가 이미지나 동영상을 선택하거나 picker화면을 종료할 때, 알림을 받는다. 


조금 아시겠나요?ㅎㅎ

저도 더 공부해야할 것 같습니다....ㅎㅎ


자! 아무튼 Delegate채택 작업과 대리자위임 과정을 마치셨다면, 다음 스텝으로 넘어가죠.  


추가로, 아니 갑자기 웬 extension..? 그냥 


이렇게 한꺼번에 ViewController에서 채택하면 안되나..? 

==> 이렇게 해도 됩니다!! 하지만, Swift 컨벤션에 따르면, 이런 Delegate채택작업은 extension으로 빼는게 좋다고 해요 :)



8. info.plist에서 권한 설정해주기.


애플이 프라이버시에 굉장히 민감한 것. 다들 잘 알고계시죠? 

사용자의 정보에 접근할 때는 항상 권한요청이 필요합니다.

info.plist에 가셔서,



Privacy - Photo Library Usage Description(사진앨범 권한), Privacy - Camera Usage Description(카메라 권한)을 추가해주세요!


9. openLibrary(), openCamera()구현.


위의 Action Sheet에서, 사진앨범을 누르면 openLibrary()함수를 호출하고, 카메라를 누르면  openCamera()가 나오게했죠?

지금은 openLibrary(), openCamera()가 구현이 안되어있어서 오류가 날거에요.

이걸 얼른 구현해줍시다.


func openLibrary(){

picker.sourceType = .photoLibrary

present(picker, animated: false, completion: nil)

}

func openCamera(){

picker.sourceType = .camera

  present(picker, animated: false, completion: nil)

}


위 코드가  오늘의 핵심?코드라고 할 수 있겠네요. 

picker는 UIImagePickerController였죠? 사진앨범을 누르면, picker의 소스타입을 사진 라이브러리로, 카메라를 누르면 소스타입을 카메라로 지정해주고,

picker를 present해준 코드에요. UIImagePickerController이기 때문에 present의 파라미터로 들어갈 수 있는거겠죠?

이까지 하고 실행시키면..! 

사진앨범을 누르니, 이 사진앨범에 대한 권한을 요청하는 것을 볼 수 있어요. OK를 눌러주시면,

사진앨범은 잘 실행되는 것을 볼 수 있습니다.

카메라를 실행해볼까요? 

....

그러면 에러를 내게 됩니다.

이건 당연한 건데요, 지금은 "시뮬레이터"죠? 시뮬레이터로 카메라를 실행시킬 수 없어서 나는 에러에요! 

만약에 지금 아이폰으로 테스트를 하고 계시다면, 카메라도 정상적으로 작동할거에요.

그러면 시뮬레이터에서 카메라 선택하면, 항상 오류가 나야하냐...


아닙니다! 에러처리하러 가봅시다. openCamera()함수로 가주세요. 


func openCamera(){

        if(UIImagePickerController .isSourceTypeAvailable(.camera)){

picker.sourceType = .camera

            present(picker, animated: false, completion: nil)

        }

        else{

            print("Camera not available")

        }

    }


그리고 저 if문을 넣어주세요. 지금 해당 소스타입을 사용할 수 있으면 나타내주고, 아니면 print를 찍어주었습니다.

다시 실행시켜서 (시뮬레이터에서) 카메라를 선택해볼까요? 



이렇게 뜨는 것을 볼 수 있습니다 :)


이렇게 오류처리는 끝냈는데...카메라는 둘째치고, 사진앨범에서 사진을 선택하면 그냥 imagePickerController가 Dismiss되는 것을 볼 수 있습니다. 


 

바로 이렇게 말이죠. 


우리가 바라는 건 뭐였죠? 

네! 우리가 선택한 이미지가 ViewController의 imageView에 추가되는 것이었죠? 


하지만 지금 그런 설정을 해준적이 없으니 당연히 안되겠죠? 

이 설정은 아까 채택한 UIImagePickerControllerDelegate에 정의되어있는 메소드들을 이용하면 된답니다. 

extension한 부분에,

위 메소드 를 추가해주세요. 위 메소드는  UIImagePickerControllerDelegate정의 부분에서 복사해서 붙혀넣기 해주시면 된답니다 :)


자, 메소드 파라미터를 볼까요? didFinishPickingMediaWithInfo.. 미디어 pick이 끝났다..뭐 이런말 같죠? 여기서 미디어는 사진이 될 수 있겠네요.


사진을 선택하고, 끝나고 뭘 할거냐? 라는 메소드인거에요.

우리는 사진을 선택하고, 그 선택한 사진을 imageView에 넣을거죠? 그 작업을 이 메소드 안에서 해주면 된답니다 XD 


저기서 info라는 곳에 우리가 선택한 미디어의 정보가 담겨져있는데요, 그 info는 Dictionary로 이루어져 있네요! info를 print해볼까요?

프로젝트 실행 > 사진추가 버튼 > 사진앨범 > 아무 사진을 누르면 그 사진에 대한 info가 나오게 됩니다. 

info는 3쌍으로 이루어져있는 Dictionary네요. 

type은 image이고, url도 있네요! 또, UIImage를 값으로 가지는 originalImage라는 것도 있습니다.

자~~ 여기서 우리는 뭘 쓰면 image를 가져올 수 있을까요? 


네! 정답은 맨 마지막쌍인 "UIImagePickerControllerOriginalImage"를 키를 가지는 값을 가져오면, UIImage를 얻을 수 있게됩니다.

Dictionary의 값을 가져오는 방법은 다 아시죠? 

Swift3 ) Collection - Dictionary사용해보기를 참고해주세요!


func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

   if let image = info[UIImagePickerControllerOriginalImage] as? UIImage{

            imageView.image = image

            print(info)

        }

        dismiss(animated: true, completion: nil)

    }

바로 이렇게  info의 값을 UIImage로 가져올 수 있습니다! 그리고 그 가져온 image를 우리의 imageView에 넣어줘야 합니다.

그리고! 우리가 이 메소드를 구현하지 않았을 때는, 자동으로 이미지를 선택하면 imagePickerController가 Dismiss됐었어요. 

하지만, 이 메소드를 구현하는 순간, 따로 dismiss처리를 하지 않으면, imagePickerController가 dismiss안됩니다...

꼭 dismiss처리를 해주세요!


자..한번 실행해볼까요?

짠 ㅎㅎㅎ

잘 실행되는 것을 볼 수 있습니다XD

어렵지 않죠? 차근차근 따라하시면 쉬울거에요!

오늘의 소스코드는 github에 올려놓을테니, 참고하시길 바랄게요 :)

도움이 되었으면 좋겠어요 💕


질문이나 지적할점은 댓글이나 PC화면 오른쪽 하단의 채널서비스를 이용해주세요!


반응형