[iOS] Making a PhotoFrameApp
- 7 minsJack’s PhotoFrame
- https://github.com/somedd/swift-photoframe/tree/somedd
- Contents To Learn
- Tapped App 템플릿
- IBOutlet
- IBAction
- Scene과 Segue
- ViewController 프로그래밍
- Container ViewController
- Second Scene
- UIImagePickerController
Step1. 시작하기 (Tabbed App 템플릿)
- 요구사항 : 자동 생성된 ViewController 클래스 viewDidLoad() 함수에서 print(#file, #line, #function, #column) 코드를 추가하고 실행하면 콘솔 영역에 무엇이 출력되는지 확인한다.
- 실행화면
-
- 애플 UIKit View Management 클래스 중에서 UITabBarController 와 UITabBar에 대해 학습한다.
- 각 클래스 역할(및 UITabBar과 UITabBarController의 차이점)은 무엇인가?
- UITabBarController : Tab에 대한 Action을 담당(즉, 무엇을 보여주고, 무엇을 할지)
- UITabBar : Tab의 전체적인 View구조를 담당(보여지는 부분, 즉. 어떻게 보이고 어떻게 반응할것인지)
- 각 클래스 역할(및 UITabBar과 UITabBarController의 차이점)은 무엇인가?
Step2. IBOutlet
- First Scene에 만들어져 있는 레이블을 IBOutlet으로 연결한다.
- 실행화면
-
- UILabel 클래스 속성(Property)는 어떤게 있는지 학습한다.
- Attributes Inspector 활용
Step3. IBAction
- Main.storyboard 에서 First Scene에 UIButton을 추가하고, IBAction으로 연결한다.
- 실행화면
-
- IBAction 과 IBOutlet 연결 구조에 대해 이해한 내용을 정리한다.
- IBOutlet : 연결통로라는 의미, 인터페이스빌더에서 프로그램과의 연결통로
- IBAction : 조작과 메서드를 연결, 사용자가 부품을 조작했을 때 실행할 일을 지정
- 버튼에 IBAction을 추가할 때 이벤트(Event) 종류에는 어떤 것들이 있는지 학습한다. 를 추가한다.
- 실행화면
-
- Segue에 액션에 있는 여러 항목들은 어떤 효과가 있는지 값을 바꿔보며 실행해서 학습한다.
- Segue의 종류
- show : 새화면으로 이동. 스택구조로 원래 화면위를 덮는다.
- show detail : split view구조에서 원래 화면을 Master, 새 화면을 Detail로 표시한다. (교체) 아이패드에서만 의미가 있다.
- present modally : 새 화면이 모달처럼 원래 화면 위를 덮는다.(기존 화면은 새화면 뒤에 그대로 존재한다.)
- popover presentation : 팝업창을 띄움. 아이패드에만 의미가 있다.
- custom
- Segue의 종류
Step5. ViewController 프로그래밍
- 스토리보드 구성 요소와 클래스 코드와 연결해서 동작을 확장한다.
- 기존 실행화면
- 화면 전환이 이루어지는 사이에 뷰컨트롤러 라이프사이클이 어떻게 변화하는지 학습한다.
- ViewDidLoad - 해당 뷰컨트롤러 클래스가 생성될 때(ViewWillAppear전에 실행) 실행된다. Low memory와같은 특별한 경우가 아니라면 딱 한번만 실행되기 때문에 초기화 할 때 사용 할 수 있다.
- ViewWillAppear - 뷰 컨트롤러가 화면에 나타나기 직전에 실행된다. 뷰 컨트롤러가 나타나기 직전에 항상 실행되기 때문에 해당 뷰 컨트롤러가 나타나기 직전마다 일어나는 작업들을 여기에 배치 시킬 수 있다.
- ViewDidAppear - 뷰 컨트롤러가 화면에 나타난 직후에 실행된다. 화면에 적용될 애니메이션을 그리거나 API로 부터 정보를 받아와 화면을 업데이트 할 때 이곳에 로직을 위치시키면 좋다. 왜냐하면 지나치게 빨리 애니메이션을 그리거나 API에서 정보를 받아와 뷰 컨트롤러를 업데이트 할 경우 화면에 반영되지 않기 때문에.
- ViewWill/DidDisappear - 뷰 컨트롤러가 화면에 나타난 직전/직후에 실행된다.
-
뷰컨트롤러와 관련된 새로운 용어들에 대해 학습한다.
- YellowViewController에서 Segue를 제거하고 다음 화면을 보여줄 때 코드로 보여주는 방법을 찾아보고 적용해본다.
- 뷰 컨트롤러 직접 호출에 의한 화면 전환 (내가선택한 방법)
let ViewController인스턴스 = self.storyboard?.instantiateViewController(withIdentifier: “Storyboard ID값”) ViewController인스턴스?.modalTransitionStyle = UIModalTransitionStyle.coverVertical self.present(ViewController인스턴스!, animated: true, completion: nil)
- 위 방법을 반영한 실행화면
- 내비게이션 컨트롤러를 사용하여 화면 전환하기
let ViewController인스턴스 = self.storyboard?.instantiateViewController(withIdentifier: “Storyboard ID값”) self.navigationController?.pushViewController(ViewController인스턴스!, animated: true)
- 뷰 컨트롤러 직접 호출에 의한 화면 전환 (내가선택한 방법)
Step6. Container ViewController
- 내비게이션 컨트롤러(Navigation Controller)를 Embed 시켜서 동작하도록 개선한다.
- 실행화면
-
- 뷰컨트롤러 컨테이너 동작을 이해한다.
- 컨테이너 뷰 컨트롤러는 한 개의 view와 여러 개의 child ViewController를 다루고, ViewController에 의지할 수 있다는 것이 장점.
- 뷰컨트롤러 컨테이너는 또 어떤 클래스가 있는지 찾아보고 학습한다.
- UINavigationController, UISplitViewController(아이패드 한정), UITabBarController
- 내비게이션 컨트롤러가 있을 경우와 없을 경우 화면 전환 동작이 어떻게 다른지, 화면들 포함관계가 있는지 학습한다.
- IB 사용 시 vs. 코드로 작성 시
- IB 사용 시: 세그로 연결하면 자동으로 코드 작성 없이 화면 전환 가능하며, Back 버튼이 자동으로 생성됨
- 코드 작성 시: push, pop을 이용하여 내비게이션 스택에 쌓아야 함. Back 버튼은 push된 뷰컨트롤러엔 자동으로 생김
- IB 사용 시 vs. 코드로 작성 시
- 내비게이션 컨트롤러 관련 메서드가 왜 push / pop 인지 학습한다.
- UINavigationController : 계층적인 성격을 띄는 콘텐츠 구조를 관리하기 위한 뷰컨트롤러.
- 화면 전환이 발생하는 뷰 컨트롤러들의 포인터를 스택으로 관리하기 때문이다.
- 즉, 최상위 뷰 컨트롤러는 화면에 표시되므로, 스택의 최상위 뷰 컨트롤러를 더하거나 빼는 것은 화면을 전환하는 것과 같다.
Step7. Second Scene 화면
- 탭바의 두 번째 화면 (Second Scene) 디자인을 변경하고 액자 앱을 동작을 구현한다.
- 실행화면
- 이미지뷰의 속성을 조정해서 이미지가 비율에 맞춰서 표시되도록 조정한다.
- 내부 UIImageView의 Inspector를 이용해, CurrentMode - Aspect Fit으로 조정
- UIImageView 와 UIImage 클래스는 각각 어떤 역할을 담당하는지 학습한다.
- UIView -> UIImageView(뷰) -> UIImage(파일)
- UIImageView : 단일이미지 혹은 움직이는 복수이미지의 표시를 담당하는 객체, 즉 이미지를 보여주는 View
- UIImage : 이미지데이터를 관리하는 객체, 즉 이미지파일에 대한 접근을 담당한다.
- UIView -> UIImageView(뷰) -> UIImage(파일)
- 이미지 뷰의 속성은 어떤 것들이 있는지 애플 개발자 문서를 참고한다.
- 애플 개발자 문서
- Image View: 이미지
- Image : 표시할 이미지
- Hilighted : 해당 이미지가 강조되었을 때의 이미지
- State : 이미지 상태, Hilighted 이미지를 표시할 때 사용한다.
- xcode 내부 인스펙터 설정(View - contentMode)
- Scale To Fill: 이미지를 이미지뷰에 맞는 크기로 확대, 축소한다. 가로세로 비율이 변경될 수 있기 때문에 이미지가 수직이 되거나 수평이될 수 있다.
- Aspect Fit: 이미지의 가로세로비율은 변경하지 않고 이미지가 모두 표시되도록 확대, 축소한다. 이미지뷰의 상하좌우에 틈새가 날 수 있다.
- Aspect Fill: 이미지 가로세로 비율은 변경하지 않고 이미지뷰에 틈새가 나지 않도록 확대, 축소한다. 이미지 상하 좌우가 이미지뷰에서 벗어날 수 있다.
- Image View: 이미지
Step8. 추가 구현사항
-
이미지 테두리 액자 화면을 추가한다. - 실행화면 -
-
사진 앨범에서 사진을 가져와서 보여줄 수 있도록 개선한다. - selectButtonTouched에서는 UIImagePickerController로 사진 앱 - 카메라롤에서 사진을 가져오도록 구현한다. - 실행화면 -
- 선택한 사진을 받기 위해서 구현해야 하는 메서드는 어떤게 있는지 찾아 구현한다.
- UIImagePickerController 인스턴스 생성과 UIImagePickerController 델리게이트 구성
```swift @IBAction func selectButtonTouched(_ sender: Any) { let imagePicker = UIImagePickerController() //UIImagePickerController 인스턴스 생성 imagePicker.sourceType = .photoLibrary //sourceType 설정 imagePicker.delegate = self //UIImagePickerController의 델리게이트 구성 present(imagePicker, animated: true, completion: nil) } ```
-
사용자가 UIImagePickerController의 인터페이스에서 이미지를 선택할 때, delegate는
UIImagePickerController(_:didFinishPickingMediaWithInfo:)
메세지를 받고, 취소를 누르면imagePickerControllerDidCancel(_:)
메세지를 받는다. 지금과 같은 경우에는,SecondViewController
인스턴스가 이미지피커의 델리게이트가 된다.( 위 코드에서imagePicker.delegate = self
부분) -
추가적으로,
SecondViewController
는UINavigationController
과UIImagePickerControllerDelegate
프로토콜을 적용해주어야 한다.UIImagePickerControllerDelegate
이 필요한 이유 :UIImagePickerController
의 delegate프로퍼티는 실제로 그 상위 클래스인UINavigationController
로부터 상속된 것이다. 하지만,UIImagePickerController
는 자기 소유의 델리게이트 프로토콜을 가진다.ㅏ 그 상속된 delegate프로퍼티는UINavigationControllerDelegate
를 따르는 객체를 참조하도록 선언되어 있다.
- 이미지 저장하여 넘겨주기
```swift func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { if let image = info[UIImagePickerControllerOriginalImage] as? UIImage { let imagePickerView = UIImageView.init(image: image) imagePickerView.contentMode = .scaleAspectFit self.photoImageView.image = imagePickerView.image dismiss(animated: true, completion: nil) } } ```
- 위에서
UIImagePickerController
의 인터페이스에서 이미지를 선택할 때, delegate가 받는UIImagePickerController(_:didFinishPickingMediaWithInfo:)
메세지를 수정한다. 이미지뷰로 선택한 사진을 불러온 후, 기존 설정에 맞게contentMode
를 AspectFit으로 설정해준 후, 액자의 이미지에 넣어준다. 그 후, dismiss를 통해 화면을 닫아준다.
- 학습꺼리
- 화면 요소들을 겹쳐서 디자인 하는 경우 z축으로 위-아래를 구분해서 학습한다.
- UIImagePickerController처럼 이미 만들어놓은 시스템 컨트롤러들에 대해 학습한다.
- https://developer.apple.com/documentation/uikit/view_controllers
- 델리게이트(Delegate)와 프로토콜(Protocol) 상관 관계에 대해 학습한다.
- 델리게이트란? : 어떤 객체가 해야 하는 일을 부분적으로 확장해서 대신 처리하는 것. *정의 : 대리자, 위임자
-
델리게이트의 용도 : 대신 처리 해줄 객체 와 처리하라고 시키는 객체
- 이번 미션에서의 경우, 대신 처리 해줄 객체는
SecondViewController
이고, 처리하라고 시키는 객체는 select버튼이다. 위 코드에서imagePicker.delegate = self
부분에 해당하고,SecondViewController
가imagePickerController
이 해야할 일을 대신 처리하는 것이다. 대신 처리하기 위해서 2개의 Protocol(UIImagePickerControllerDelegate
,UINavigationControllerDelegate
)을 적용시켜주는 것이고, 필요한 이유는 위 1번의 내용을 참고.
- 이번 미션에서의 경우, 대신 처리 해줄 객체는