UIKit
에서 앱 컨텐츠를 보여주고, 접근하고, 공유하는 기능을 제공하는 UIViewController
subclass들
ex) 프로필 사진을 설정하기 위해 카메라 앱 사용, 메세지 앱을 통해 기사 공유, 앱스토어 구매 시 패스워드 입력
UIActivityViewController
@IBAction func shareButtonTapped(_ sender: UIButton) {
guard let image = imageView.image else { return }
let activityController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
activityController.popoverPresentationController?.sourceView = sender
present(activityController, animated: true, completion: nil)
}
UIActivityViewController(activityItems:applicationActivities:)
let activityController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
activity view controller의 initializer
activityItems
[Any]
typeapplicationActivities
popoverPresentationController
activityController.popoverPresentationController?.sourceView = sender
UIActivityViewController
는 특정 view에서 퍼져나오는 형태의 popover 창에 표시된다.sender
)SFSafariViewController
앱 내부에서 Safari를 띄워 웹페이지를 여는 기능
SafariService
framework에 정의되어 있다.
import SafariServices
@IBAction func safariButtonTapped(_ sender: UIButton) {
// URL(string:) initializer: optional 반환
if let url = URL(string: "https://www.apple.com") {
let safariViewController = SFSafariViewController(url: url)
present(safariViewController, animated: true, completion: nil)
}
}
SFSafariViewController(url:)
let safariViewController = SFSafariViewController(url: URL(string: "https://www.apple.com"))
url
UIAlertController
사용자의 주위를 끌고, 여러가지 선택지를 제공하는 기능
ex) 배터리 부족 알람, 소프트웨어 업데이트 알람
UIAlertController(title:message:preferredStyle:)
let alertController = UIAlertController(title: "Choose Image Source", message: nil, preferredStyle: .actionSheet)
preferredStyle
.alert
: 화면의 가운데에 알람을 띄움.actionSheet
: 화면의 아래에 알람을 띄움UIAlertAction(title:style:handler:)
let cameraAction = UIAlertAction(title: "Camera", style: .default, handler: { action in
print("User selected Camera action")
})
handler
// 사용자에게 갤러리의 사진을 가져올지 새로운 사진을 찍을지 선택지 제공
@IBAction func cameraButtonTapped(_ sender: UIButton) {
let alertController = UIAlertController(title: "Choose Image Source", message: nil, preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let cameraAction = UIAlertAction(title: "Camera", style: .default, handler: { action in
print("User selected Camera action")
})
let photoLibraryAction = UIAlertAction(title: "Photo Library", style: .default, handler: { action in
print("User selected Photo Library action")
})
alertController.addAction(cancelAction)
alertController.addAction(cameraAction)
alertController.addAction(photoLibraryAction)
alertController.popoverPresentationController?.sourceView = sender
present(alertController, animated: true, completion: nil)
}
UIImagePickerController
사용자의 카메라 또는 갤러리에 접근하는 기능
ex) 사용자가 프로필 사진을 선택하는 앱, 사진 공유 앱
2개의 protocol을 차용해야 한다.
UIImagePickerControllerDelegate
UINavigationControllerDelegate
class ViewController: UIViewController,
UIImagePickerControllerDelegate, UINavigationControllerDelegate
{...}
delegate
@IBAction func cameraButtonTapped(_ sender: UIButton) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
//...
}
isSourceTypeAvailable(_:)
현재 디바이스에서 해당 source type이 사용될 수 있는지 여부를 Bool
형태로 반환
시뮬레이터의 경우 카메라를 지원하지 않는다.
해당 메서드를 통해 확인함으로써, 시뮬레이터에선 카메라 선택지를 보여주지 않을 수 있다.
앱이 fatal error와 함께 충돌하는 것을 막는다.
if UIImagePickerController.isSourceTypeAvailable(.camera) {
let cameraAction = UIAlertAction(title: "Camera", style: .default, handler: { action in
imagePicker.sourceType = .camera
self.present(imagePicker, animated: true, completion: nil)
})
alertController.addAction(cameraAction)
}
NSCameraUsageDescription
앱은 카메라와 같은 사용자의 개인정보에 접근을 시도하기 전 허가를 요청해야 한다.
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an
NSCameraUsageDescription key with a string value explaining to the user how
the app uses this data.
OS는 사용자에게 접근을 허락할 것인지 묻는 창을 띄운다.
NSCameraUsageDescription
key는 왜 앱이 카메라에 접근을 원하는지 이유를 사용자에게 설명하는데 쓰인다.
Info
file에서 NSCameraUsageDescription
key를 생성하고, 어떻게 사용자의 데이터를 사용할 것인지 입력한다.
ex) "To share photos from camera."
imagePickerController(_:didFinishPickingMediaWithInfo:)
사용자가 사진 또는 다른 미디어를 선택하는 경우 실행되는 delegate method
info
info
dictionary에 사진이 저장되어 있어 해당 parameter를 통해 미디어에 접근할 수 있다.
dictionary key는 UIImagePickerController.InfoKey
type으로 이루어져 있어 사용자가 세션에서 선택한 이미지에 관한 정보에 접근할 수 있게 한다.
.originalImage
: 사용자가 선택한 image를 가져오는 key[UIImagePickerController.InfoKey: Any]
type으로 해당 value값을 이용하기 위해선 타입을 변환해주어야 한다.
UIImage
로 타입을 변환해주어야 한다.dismiss(animated:completion:)
@IBAction func cameraButtonTapped(_ sender: UIButton) {...}
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)
}
@IBAction func cameraButtonTapped(_ sender: UIButton) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
let alertController = UIAlertController(title: "Choose Image Source", message: nil, preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
if UIImagePickerController.isSourceTypeAvailable(.camera) {
let cameraAction = UIAlertAction(title: "Camera", style: .default, handler: { action in
imagePicker.sourceType = .camera
self.present(imagePicker, animated: true, completion: nil)
})
alertController.addAction(cameraAction)
}
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)
}
alertController.popoverPresentationController?.sourceView = sender
present(alertController, animated: true, completion: nil)
}
MFMailComposeViewController
앱 내부에서 이메일을 전송할 수 있게 해주는 기능
이메일, 문자메세지 전송에 관한 인터페이스가 있는 MessageUI
framework에 속해있다.
import MessageUI
mailComposer.setToRecipients(["example@example.com"])
mailComposer.setSubject("Look at this")
// plain text or HTML
mailComposer.setMessageBody("Hello, this is an email from the app I made.", isHTML: false)
if let image = imageView.image, let jpegData =
image.jpegData(compressionQuality: 0.9) {
mailComposer.addAttachmentData(jpegData, mimeType: "image/jpeg", fileName: "photo.jpg")
}
present(mailComposer, animated: true, completion: nil)
canSendMail()
@IBAction func emailButtonTapped(_ sender: UIButton) {
guard MFMailComposeViewController.canSendMail() else {
print("Can not send mail")
return
}
}
실제 환경에서는 false
를 return 했을 때 다음과 같은 조치를 취해야한다.
mailComposeDelegate
mailComposeDelegate
를 세팅하기 위해 MFMailComposeViewControllerDelegate
protocol을 차용해야 한다.class ViewController: UIViewController, MFMailComposeViewControllerDelegate {...}
mailComposeDelegate
로 설정한다.@IBAction func emailButtonTapped(_ sender: UIButton) {
guard MFMailComposeViewController.canSendMail() else { return }
let mailComposer = MFMailComposeViewController()
mailComposer.mailComposeDelegate = self
}
mailComposeController(didFinishWith:)
func mailComposeController(_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult, error: Error?) {
dismiss(animated: true, completion: nil)
}