[도서] App development with Swift

Unit 4 - Lesson 8: System View Controllers

DesignThinker 2021. 11. 6. 15:25

목표

  • alert contoller를 표시하고 사용자 선택에 반응하는 것을 사용하며 설명할 수 있다.
  • activity view controller를 사용하며 설명할 수 있다.
  • mail compose view controller를 사용하며 설명할 수 있다.
  • image picker view controller와 선택된 사진을 사용하는 법을 설명할 수 있다. 
  • Safari view controller를 통해 웹사이트를 표시하고 설명할 수 있다.

Vocabulary

handler

어떤 이벤트에 대해 대응하는 함수

클로져(코드블럭)이다.

 

 

UIKit에 포함된 빌트인 된 UIViewController의 서브클래스들을 잘 활용한다면 편하게 앱 콘텐츠를 보여주고 접근하고 공유하는 등 여러가지 기능을 붙일 수 있게 된다.

 

Apple system view controllers의 예

  1. 사진 공유 (activity controller)
  2. 카메라 접근
  3. 앨범 접근 (image picker)
  4. 알림 (alert controller)
  5. 웹페이지 접근 (Safari view controller)
  6. 기타 등등

 

UIActivityController

콘텐츠를 다른 앱에 공유할 수 있다

파라미터 중 applicationActivities 의 경우 UIActivity를 서브클래스로 만들어서 custom activity를 제공할 때 사용하게 되는데, 이게 뭐냐면 가령 다른 sns 계정을 받아서 해당 sns에 공유할 때 사용되는 그런 종류의 것이라 이해하면 되겠다. 그외 보통의 경우 nil 입력.

//1 
guard let image = imageView.image else {return}
//2
let activityController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
//3
activityController.popoverPresentationController?.sourceView = sender
//4
present(activityController, animated: true, completion: nil)

//3

아이패드에서 실행될 코드. sender는 버튼이고, 그 버튼 위치에서 실행(팝오버)된다는 의미

//4

이 중 completion이 핸들러이다. 본 함수가 실행 된 후 실행할 함수를 지정할 수 있다.

 

 

SFSafariViewController

앱을 빠져나가지 않고 인터넷에서 가져온 정보를 표시할 수 있다

사용자가 주소창 편집을 할 수 없다. 주어진 링크의 페이지 읽기만 가능하게 해줌.

SafariServices 프레임워크를 import해야 쓸 수 있다.

if let url = URL(string: "https://designthinker.tistory.com") {
	let safariViewController = SFSafariViewController(url: url)
	present(safariViewController, animated: true, completion: nil)
}

해야할 3가지

  1. 문자열로부터 URL만들기 URL(string:)함수 사용.
  2. SFSafariViewController를 만들어서 앞서 만든 URL을 넘겨줘야함
  3. 사파리 뷰컨트롤러를 사용자에게 present하기 (UIActivityContoller에서 한것과 동일)

UIAlertController

경고창, 액션을 받는 액션시트

let alertController = UIAlertController(title: "Choose Image Source", message: nil, preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
alertController.popoverPresentationController?.sourceView = sender
		
present(alertController, animated: true, completion: nil)

UIImagePickerViewController

포토라이브러리 또는 카메라에 접근할 수 있다. 이때 반드시 아래 두개의 프로토콜을 따라야한다.

  • UIImagePickerControllerDelegate
  • UINavigationControllerDelegate

디바이스에 따라, 또는 시뮬레이터에서 실행 시 카메라에 접근할 수 없는 경우도 있으므로, UIImagePickerController.isSourceTypeAvailable(_:) 메소드를 사용하여 크래시를 막도록 한다.

또한, 사용자 민감정보에 접근하기 위해 접근 요청 메세지를 plist에 넣어두어야 한다.

NSPhotoLibraryUsageDescription (Privacy - Photo Library Usage Description)

NSCameraUsageDescription (Privacy - Camera Usage Description)

접근 요청 메세지의 예: "To share photos from the camera or photo library"

 

if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
	let photoLibraryAction = UIAlertAction(title: "Photo library", style: .default, handler: { action in imagePicker.sourceType = .photoLibrary
		self.present(imagePicker, animated: true, completion: nil)
	})
	alertController.addAction(photoLibraryAction)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
	guard let selectedImage = info[.originalImage] as? UIImage else {return}
	imageView.image = selectedImage
	dismiss(animated: true, completion: nil)
}

MFMailComposeViewController

앱 안에서 메일을 보낼 수 있다

MessageUI 프레임워크를 import해야함

MFMailComposeViewContorllerDelegate 프로토콜 준수.

canSendMail() 함수를 통해 메일을 보낼 수 있는 상황인지 먼저 확인한다. (계정 연동 등)

if !MFMailComposeViewController.canSendMail() {
	print("Can not send mail")
	return
}

let mailComposer = MFMailComposeViewController()
mailComposer.delegate = self
mailComposer.setToRecipients(["mail@address.com"])
mailComposer.setSubject("Title")
mailComposer.setMessageBody("BodyText", isHTML: false)

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

delegate로 사용할 수 있는 함수

func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
	dismiss(animated: true, completion: nil)
}