๐ SNS ์ฑ์ด๋ ์ฌ์ง์ ์ ๋ก๋ํ๋ ๊ธฐ๋ฅ์ด ์๋ ์ฑ์ด๋ผ๋ฉด ์ฌ์ฉ์ ๊ฐค๋ฌ๋ฆฌ์ ์ ๊ทผํ์ฌ ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์ค๋ ๊ธฐ๋ฅ์ด ํ์ํ๋ฐ์, ์ฌ์ค ์ ํ์์๋ ์ด๋ฏธ ์ด๋ฌํ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก UIImagePickerController์ PHPickerViewController์ ์ ๊ณตํ๊ณ ์์ต๋๋ค. ๋ ํด๋์ค์ ์ ๊ทผ ๊ถํ ์ฐจ์ด๊ฐ ์์ง๋ง ์ฌ์ฉ์๊ฐ ์ฌ์ง์ ์ ํํ๊ณ ์ด ์ฌ์ง ์ ๋ณด๋ฅผ ๋ฐ์ ์ฌ ์ ์์ฃ !
๐ ๊ทธ๋ฌ๋ UI/UX๊ฐ ๊ธฐ์กด iOS์์ ์ ๊ณตํด์ฃผ๋ ํํ์ ๋ฌ๋ผ์ผ ํ๋ค๋ฉด ์ง์ ๊ฐค๋ฌ๋ฆฌ๋ฅผ ๊ตฌํํด ์ฃผ๊ฑฐ๋ ์คํ ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์ด๋ฏธ OS์์ ์ ๊ณตํด ์ฃผ๋ ๊ฒ์ด ์๋ ์ง์ ๊ตฌํ์ ํด์ฃผ๊ฒ ๋๋ฉด ๊น๋ค๋กญ๊ธฐ๋ ํฉ๋๋ค. ํ์ง๋ง ๋ถ๊ฐ๋ฅํ ๊ฒ์ ์๋๋ผ์ ์ด์ ์ ์ปค์คํ ๊ฐค๋ฌ๋ฆฌ๋ฅผ ๋ง๋ค๊ฒ ๋์๋๋ฐ์, ์ด๋ฅผ ๊ตฌํํด ๋ณด๋ฉด์ ์๊ฒ๋ ์ ์ ๊ณต์ ํด ๋ณผ๊น ํฉ๋๋ค. ์๊ฐ๋ณด๋ค PhotoKit์ ๋ํ ๋ด์ฉ์ด ์์ด์ ํ๋ค์๋ ๊ธฐ์ต์ด ใ ใ
๐ ํํ ๋ฆฌ์ผ ํ์์ผ๋ก ๊ธ์ ์์ฑํด ๋ณผ๊น ํ๋๋ฐ PhotoKit๊ณผ UICollectionViewController๋ฅผ ์ฌ์ฉํ์๋ ๋ง์ ๋ถ๋ค์๊ฒ ๋์์ด ๋์์ผ๋ฉด ์ข๊ฒ ๋ค์~ ๋ง์ฝ ๋์์ด ๋์๋ค๋ฉด ์ฌ๊ธฐ์ ๊ธฐ ๊ณต์ ๋ถํ๋๋ฆฌ๊ณ ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์๋ค๋ฉด ๊ณต์ ๋ถํ๋๋ ค์!!
โญ๊ทธ๋ฆฌ๊ณ ์ธ์ ๋ ์ง ํ๋ฆฐ์ ์ด๋ ์ง์ ์ ํ์์ ๋๋คโญ
1. ํ๋ก์ ํธ ์์ฑํ๊ธฐ
๋ฒ์ ์ ๋ณด : Swift 5, Xcode 13.2.1
Xcode ๋ฅผ ์คํํ๊ณ ํ๋ก์ ํธ๋ฅผ ์์ฑํด ์ค์๋ค. ํ์ฌ ๊ธฐ์ค์ผ๋ก iOS 15 ๊น์ง ๋์์ผ๋ฏ๋ก 2๋จ๊ณ ๋ฎ์ถฐ 13.0์ผ๋ก Deployment Target์ ๋ฐ๊ฟ ์ฃผ๊ฒ ์ต๋๋ค.
์ค๋ ๊ณต๋ถํ๊ฒ ๋ ๊ฐค๋ฌ๋ฆฌ ์ ๊ทผ ๊ถํ์ iOS 14+ ๋ถํฐ ๋ณ๊ฒฝ๋ ์ฌํญ์ด ์์ต๋๋ค. ๊ธฐ์กด์ ๋ชจ๋ ์ฌ์ง์ ์ ๊ทผ์ ํ์ฉํ๊ฑฐ๋, ํ์ฉํ์ง ๋ชปํ๊ฒ ์ ํํ ์ ์์๋๋ฐ์, iOS 14+ ๋ถํฐ๋ ์ ํ๋ ์ฌ์ง๋ง ์ ๊ทผ ํ ์ ์๋ ๊ถํ์ด ์๋ก ์๊ฒผ์ต๋๋ค!
๋ณด์์ด ๊ฐํ๋์ด ์ฌ์ฉ์์๊ฒ ์ข๋ ํฅ์๋ ๋ณด์ ๊ธฐ๋ฅ์ ๊ฒฝํํ ์ ์๊ฒ ํด์ฃผ์ง๋ง ๊ฐ๋ฐ์์๊ฒ๋ ์ข๋ ๊ณ ํต์ค๋ฌ์ด ๊ฒฝํ์ ์ฃผ์ง ์์๊น ์ถ์ต๋๋ค ใ ใ ๊ทธ๋๋! ์ฌ์ฉ์ ๊ฒฝํ์ ์ํด ์์ฐ์ค๋ฝ๊ณ ๋ฉ์ง ์ปค์คํ ๊ฐค๋ฌ๋ฆฌ๋ฅผ ๊ตฌํํด ๋ด ์๋ค!
2. ํ๋ก์ ํธ ๊ตฌ์ฑํ๊ธฐ
(1) ๊ธฐ๋ณธ ์ธํ ํ๊ธฐ
ํฌ์คํ ์์๋ ์คํ ๋ฆฌ๋ณด๋๊ฐ ์๋๋ผ xib๋ฅผ ์ด์ฉํด์ ๊ตฌํํด ์ค ๊ฑด๋ฐ ๊ธฐ๋ณธ ์ธํ ์ ํ์ค ์ค ์์ ๋ค๋ฉด (2) ํ๋ก์ ํธ ๊ตฌ์ฑํ๊ธฐ๋ก ๋์ด ๊ฐ์๋ฉด ๋ฉ๋๋ค!
Directory ๊ตฌ์กฐ์์ Main.storyboard๋ฅผ ํ๋ฒ ํด๋ฆญํด ์ฃผ์๊ณ Delete ํค๋ฅผ ๋๋ฌ์ค๋๋ค. ์ ์ฌ์ง๊ณผ ๊ฐ์ ์ฐฝ์ด ๋จ๋ฉด Move to Trash๋ฅผ ๋๋ฌ์ฃผ์ธ์. ๊ทธ๋ฆฌ๊ณ ์ต์๋จ์ ์์นํด ์๋ ํ๋ก์ ํธ๋ฅผ ๋๋ฌ์ค๋๋ค.
Targets์ ํด๋ฆญํ์๊ณ Info ํญ์ ํด๋ฆญํด ์ฃผ์ธ์ Info.plist ๋ ์๋ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ์ ์์นํด ์์๋๋ฐ xCode๊ฐ ์ ๋ฐ์ดํธ ํ๋ฉด์ Targets > Info๋ก ์ฎ๊ฒจ ๊ฐ์ต๋๋ค. ์ด์ ํฌ์คํ ์ ๋ณด๊ณ ๊ธฐ๋ณธ ์ธํ ์ ํ์๋ ๋ถ๋ค์ ํท๊ฐ๋ฆฌ์ค ์๋ ์์ ๊ฒ ๊ฐ์์
Application Scene Mainfest > Scene Configuration > Application Session Role > Item 0 > Storyboard Name์ ํด๋ฆญํด ์ค๋๋ค (์ ์ด๋ฆฌ ๊ฝ๊ฝ ์จ๊ฒจ ๋์ ๊ฑฐ์ฃ ? ใ ใ ใ )
Delete ํค๋ฅผ ๋๋ฌ ์ง์์ฃผ์ธ์!
์ด์ General ํญ์ผ๋ก ์ด๋ํด ์ฃผ์ธ์. Deployment Info์ main interface๊ฐ Main์ผ๋ก ์ง์ ๋์ด ์์ ๊ฒ๋๋ค! ์ด ๋ถ๋ถ์ ์ง์ด ํ ์ํฐ ํ๋ฒ ์ณ์ฃผ์ธ์! ์ ์ฌ์ง์ฒ๋ผ ๊ณต๋์ผ๋ก ๋ง๋ค์ด ์ฃผ์ธ์! ๋ง์ฝ ํ๋ก์ ํธ๋ฅผ storyboard๋ก ์งํํ์ค ๋ Main.stroyboard ๋ง๊ณ ๋ฐ๋ฅธ ๊ฑธ ์ฌ์ฉํ๊ฒ ๋ค! ํ์๋ฉด ์ Main Interface์ ๊ฐ์ ์๋ก์ด ์คํ ๋ฆฌ๋ณด๋์ ์ด๋ฆ์ผ๋ก ๋ฐ๊ฟ ์ฃผ์๋ฉด ๋ฉ๋๋ค. ์ ํฌ๋ ์คํ ๋ฆฌ๋ณด๋ ์์ด ์งํ๋๋ฏ๋ก ์ง์ ์ฃผ๋ ๊ฑฐ์์!
์ด์ SceneDelegate๋ก ์ด๋ํด ์ฃผ์ธ์! ์ต์ ์ง์ ๋ฒ์ ์ด iOS 13 ์ด๋ฏ๋ก SceneDelegate๋ฅผ ์ง์ํฉ๋๋ค. ์ด์ ๋ฒ์ ์์๋ AppDelegate์์ windowViewController๋ฅผ ์ง์ ํด ์ฃผ๊ณค ํ๋๋ฐ ์ด๋ฒ์๋ SceneDelegate์์ ์์ฑํ๋๋ก ํ๊ฒ ์ต๋๋ค.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: windowScene)
self.window?.rootViewController = ViewController()
self.window?.makeKeyAndVisible()
}
}
์ฌ์ฉํ์ง ์๋ ์ฝ๋์ ์ฃผ์์ ์ง์ฐ๊ณ window๋ฅผ ์ง์ ํด ์ค๋๋ค. ๋ฌธ์ ์์ด ViewController๊ฐ rootVeiwController๋ก ์ง์ ๋์๋์ง ์๊ณ ์ถ๋ค๋ฉด ViewController๋ก ๊ฐ์ backgroundColor์ ๋ฐ๊ฟ์ฃผ์ธ์. ์ปค๋ฉ๋ + R์ ๋๋ฌ ๋น๋ํ๊ณ ์คํํด ์ค์๋ค
๋ฌธ์ ๊ฐ ์๋ค๋ฉด ๊ฒ์ ํ๋ฉด์ผ๋ก ๋์ค๊ณ , ๋ฌธ์ ๊ฐ ์๋ค๋ฉด ์ง์ ๋ ์์ผ๋ก ํ๋ฉด์ด ๋ํ๋๊ฒ ๋ฉ๋๋ค. ์ด์ ๊ธฐ๋ณธ์ ์ธ ์ธํ ์ ๋๋ฌ๊ณ ViewController์ ๊ตฌ์ฑํด ๋ณด๊ฒ ์ต๋๋ค
(2) ํ๋ก์ ํธ ๊ตฌ์ฑํ๊ธฐ
์๋ก์ด ํ์ผ์ ์ถ๊ฐํด ์ค๋๋ค. ํ๋ก์ ํธ ํด๋๋ฅผ ๋๋ฅด์๊ณ ์ปค๋ฉ๋ + n์ ๋๋ฅด๊ฑฐ๋ ์ค๋ฅธ์ชฝ ํด๋ฆญํด์ New File์ ์ ํํด ์ฃผ์๋ฉด ๋ฉ๋๋ค.
Also Create XIB file์ ์ฒดํฌ ํด์ฃผ์ธ์! Subclass of ๋ UIViewController๋ก ๋์ด ์๋์ง ํ์ธํ์๊ณ HomeViewController.swift์ HomeViewController.xib๋ฅผ ์์ฑํด ์ค๋๋ค.
๋ฒํผ ํ๋์ Collection View ํ๋๋ฅผ ์ ์ ํ ๋ฐฐ์นํด ์ค๋๋ค. ์ด๋ฏธ์ง ์ ํํ๊ธฐ ๋ฒํผ์ ๋๋ฅด๋ฉด ์ปค์คํ ๊ฐค๋ฌ๋ฆฌ๋ก ์ด๋ํฉ๋๋ค. ๊ทธ ํ ์ปค์คํ ๊ฐค๋ฌ๋ฆฌ์์ ์ ํํ ์ฌ์ง์ HomeViewController์ collection view์ ๋ฐฐ์น ์์ผ ์ฃผ๊ฒ ์ต๋๋ค.
HomeViewController.swift์ IBAction์ ์ฐ๊ฒฐํด ์ค๋๋ค. Collection View๋ ๋ค์์ ์ฐ๊ฒฐํด ์ฃผ๊ฒ ์ต๋๋ค.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: windowScene)
self.window?.rootViewController = HomeViewController()
self.window?.makeKeyAndVisible()
}
SceneDelegate์ rootViewController๋ฅผ HomeViewController๋ก ๋ณ๊ฒฝํด ์ค๋๋ค
3. Permission ์ค์ ํ๊ธฐ
์ฌ์ฉ์ ๊ฐค๋ฌ๋ฆฌ์ ์ ๊ทผํ๊ธฐ ์ํด์ ์ ๊ทผ ๊ถํ์ ์ป์ด ์์ผ ํฉ๋๋ค. Info.plist๋ก ๊ฐ์ค๋๋ค (Info๋ ํด๋ ๊ตฌ์กฐ์ ๊ฐ์ฅ ์๋จ์ ์๋ ํ๋ก์ ํธ๋ฅผ ํด๋ฆญํ์๊ณ Target์ ๋๋ฅด์๋ฉด Info ํญ์ด ๋ณด์ ๋๋ค! Info ํญ์ ๋๋ฌ ์ด๋ํด ์ฃผ์๋ฉด ๋ฉ๋๋ค.)
NSPhotoLibraryAddUsageDescription์ ์ถ๊ฐํด ์ฃผ์ ์ผ ํฉ๋๋ค
Key๋ Privacy - Photo Library Usage Description ์ด๊ณ value๋ ์ฌ์ง ๊ถํ์ ์ป์ด ์ฌ ๋ ๋์ค๋ OS ์ผ๋ฟ ์ฐฝ์ ํ์๋ ๋ฌธ๊ตฌ ์ ๋๋ค.
๋ง์ฝ ์๋ก์ด ํ๋๋ฅผ ์ถ๊ฐํ์๋ ๋ฐฉ๋ฒ์ ๋ชจ๋ฅด์๊ฒ ๋ค๋ฉด Key์ ์๋ ์๋ฌด ๊ฑฐ๋ ๋ง์ฐ์ค๋ฅผ ์ฌ๋ฆฌ์๋ฉด + ๋๊ทธ๋ ๋ฒํผ์ด ๋ณด์ผ ๊ฑฐ์์ ๋๋ฌ ์ฃผ์๋ฉด ์๋ก์ด ํ๋๊ฐ ์๊น๋๋ค!
import UIKit
import Photos
HomeViewController๋ก ๊ฐ์ Photos ๋ฅผ ์ํฌํธ ํด์ค๋๋ค!
๋ฒํผ์ ๋๋ฅด๋ฉด ์ฌ์ฉ์ ๊ถํ์ ์ป์ด์ผ ํ๋ฏ๋ก ์ฐ๊ฒฐํด์ค IBAction์ ์๋ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค
@IBAction func presentGallaryView(_ sender: UIButton) {
if #available(iOS 14, *) {
let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
} else {
let status = PHPhotoLibrary.authorizationStatus()
}
}
์์ ๋ง์ ๋๋ ธ๋ฏ์ด iOS 14+ ๋ถํฐ ์ ๊ทผ ๊ถํ์ด ๋ฌ๋ผ์ง๊ธฐ ๋๋ฌธ์ ๊ตฌ๋ถ์ง์ด ์์ฑํด ์ฃผ์๋ฉด ๋ฉ๋๋ค. iOS 14+ ์์ .readWrite๋ ์ ๊ทผ ๊ถํ ๋ ๋ฒจ์ ๋๋ค. ๋๊ฐ์ง๊ฐ ์๋๋ฐ ์ฌ์ฉ์ ๊ฐค๋ฌ๋ฆฌ์ ์ฝ๊ณ ์ธ ์ ์๋ .readWrite์ ์ญ์ ๊ฐ ๋ถ๊ฐ๋ฅํ .addOnly๊ฐ ์์ต๋๋ค
๋ ๊ฐ์ง PHPhotoLibrary ํจ์๊ฐ ๋ฐํํ๋ PHAuthorizationStatus ์๋ ์ฌ๋ฌ ์ข ๋ฅ๊ฐ ์๋๋ฐ ๋ค์๊ณผ ๊ฐ์ต๋๋ค
์ฐ์ ๋น๋ํ๊ณ ์คํ์ ํด๋ด ์๋ค.
๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ ๊ทผ ๊ถํ์ ์ป์ด ์ค๊ธฐ ์ํ ์ผ๋ฟ๋ทฐ๊ฐ ๋น๋๋ค! info.plist์ ์ ์ด์ค NSPhotoLibraryAddUsageDescription ์ ๋ฌธ๊ตฌ๊ฐ ์ผ๋ฟ ์ฐฝ์ ๋จ๋ ๊ฒ์ ํ์ธํ ์ ์์ด์
open class func authorizationStatus(for accessLevel: PHAccessLevel) -> PHAuthorizationStatus
์ฌ๊ธฐ์ PHAuthorizationStatus๊ฐ ๋ฐํ๊ฐ์์ ์ ์ ์์ต๋๋ค.
.notDetermined : ์ฌ์ฉ์๊ฐ ์ฑ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ถํ์ ์๋ฌด๊ฒ๋ ์ค์ ํ์ง ์์ ๊ฒฝ์ฐ ์ ๋๋ค.
.restricted : ์ฌ์ฉ์๋ฅผ ํตํด ๊ถํ์ ๋ถ์ฌ ๋ฐ๋ ๊ฒ์ด ์๋์ง๋ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ถํ์ ์ ํ์ด ์๊ธด ๊ฒฝ์ฐ ์ ๋๋ค. ์ฌ์ง์ ์ป์ด ์ฌ ์ ์์ต๋๋ค
.denied : ์ฌ์ฉ์๊ฐ ์ ๊ทผ์ ๊ฑฐ๋ถํ ๊ฒ์ ๋๋ค. ์ฌ์ง์ ์ป์ด ์ฌ ์ ์์ต๋๋ค ๐ฅฒ
.authorized : ์ฌ์ฉ์๊ฐ ์ฑ์๊ฒ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ๊ถํ์ ์ค์ ํ ๊ฒฝ์ฐ ์ ๋๋ค.
.limited : (iOS 14+) ์ฌ์ฉ์๊ฐ ์ ํ๋ ์ ๊ทผ ๊ถํ์ ๋ถ์ฌํ ๊ฒฝ์ฐ ์ ๋๋ค.
PHAuthorizationStatus์ ํ์ ์ด enum์ด๋ฏ๋ก ์ ๊ฐ ์ข์ํ๋ switch ๋ฌธ์ผ๋ก ๋ฐ๊ฟ ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
@IBAction func presentGallaryView(_ sender: UIButton) {
if #available(iOS 14, *) {
switch PHPhotoLibrary.authorizationStatus(for: .readWrite) {
case .notDetermined:
print("not determined")
case .restricted:
print("restricted")
case .denied:
print("denined")
case .authorized:
print("autorized")
case .limited:
print("limited")
@unknown default:
print("unKnown")
}
} else {
switch PHPhotoLibrary.authorizationStatus() {
case .notDetermined:
print("not determined")
case .restricted:
print("restricted")
case .denied:
print("denined")
case .authorized:
print("autorized")
@unknown default:
print("unKnown")
}
}
}
์ฐจ์ด์ ์ iOS 14 ๋ฏธ๋ง ๋ฒ์ ์์๋ limited ํ์ ์ด ์๋ค๋ ๊ฒ์ ๋๋ค. limited ํ์ ์ ์ถ๊ฐํด์ผ ๋ ธ๋์ค์ด ์์๊ธฐ๋๋ฐ ์ฐจํผ iOS 14 ์์๋ง ๋์ํ๊ธฐ ๋๋ฌธ์ ์ ํ์ฌํญ์ผ๋ก ๋ฃ์ด์ฃผ์๋ฉด ๋ฉ๋๋ค.
์ด์ ์ ๊ถํ์ ์ป์ด์ค๊ธฐ ์ํ ์ผ๋ฟ ์ฐฝ์์ ๋ฒํผ์ด๋ ๋์์ ์ํํ ๊ฒฝ์ฐ ์๋ฎฌ๋ ์ดํฐ๋ ๋๋ฐ์ด์ค์์ ์์ ํ ์ฑ์ ์ญ์ ํ๊ณ ๋ค์ ๋น๋ ๋ฐ ์คํํด ๋ด ๋๋ค.
ํ์ฌ ์ฌ์ฉ์๊ฐ ์๋ฌด๋ฐ ๋์๋ ํ์ง ์์๊ธฐ ๋๋ฌธ์ not determined๊ฐ ํ๋ฉด์ ์ฐํ๋ ๊ฑธ ๋ณผ ์ ์์ด์ ๐
์ ์ด์ ์ด๋ป๊ฒ ํ๋๋ ํ๋ฉด... ์๋ฌด๋ฐ ์ ํ๋ ๋์ง ์์์ ๋ ์ฌ์ฉ์์๊ฒ ๊ถํ์ ๋ถ์ฌํด ์ฃผ๊ฒ ๋? ๋ฅผ ๋ฌผ์ด๋ณด๊ธฐ ์ํ ์ผ๋ฟ์ ๋์ธ ๊ฒ๋๋ค! ์ด์ ์ ๋ดค๋ ๊ทธ ์ผ๋ฟ ์ฐฝ์ด์์! ์ฐ์ iOS 14+ ๋ถํฐ ์งํํ๊ฒ ์ต๋๋ค
case .notDetermined:
print("not determined")
PHPhotoLibrary.requestAuthorization(for: .readWrite) { status in
switch status {
case .authorized, .limited:
print("๊ถํ์ด ๋ถ์ฌ ๋ฌ์ต๋๋ค. ์จ๋ฒ ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค")
case .denied:
print("๊ถํ์ด ๊ฑฐ๋ถ ๋ฌ์ต๋๋ค. ์จ๋ฒ ์ฌ์ฉ ๋ถ๊ฐํฉ๋๋ค.")
default:
print("๊ทธ ๋ฐ์ ๊ถํ์ด ๋ถ์ฌ ๋์์ต๋๋ค.")
}
}
.notDetermined ์ฝ๋์ ์ ์ด ์ฃผ์๋ฉด ๋์! ์ฌ์ฉ์๊ฐ ์ค์ ํ ๊ถํ์ ์ป์ด ์ฌ ๋๋ authorizationStatus๋ฅผ ์ฌ์ฉํ๋๋ฐ, ๊ถํ์ ์์ฒญํ ๋์๋ requestAuthorization์ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
์ฌ์ฉ์๊ฐ Select Photos๋ฅผ ๋๋ฅด๊ฒ ๋๋ฉด ์ฌ์ง์ ์ ํํ๊ณ ๋์ case ๋ฌธ์ .limited๋ฅผ ์คํํ๊ฒ ๋ฉ๋๋ค. ๋ง์ฝ ์ฌ์ฉ์๊ฐ Allow Access to All Photos๋ฅผ ๋๋ฅด๊ฒ ๋๋ฉด .authorized๊ฐ ์คํ๋ฉ๋๋ค. ๋ฐ๋ฉด์ Don't Allow๋ฅผ ์ ํํ๋ฉด ๊ถํ์ด ๊ฑฐ๋ถ ๋์์ผ๋ฏ๋ก .denied๊ฐ ์คํ๋ฉ๋๋ค
์ฌ์ฉ์๊ฐ Don't Allow๋ฅผ ๋๋ฅด๊ฒ ๋๋ค๋ฉด ์ฌ์ง ๊ธฐ๋ฅ์ ์ธ ์ ์์ผ๋ฏ๋ก ์ด๋ฅผ ์ผ๋ฟ ์ฐฝ์ ํตํด ์๋ดํ๊ณ , ์ฌ์ฉ์๊ฐ ์ฌ์ง์ ์ธ ์ ์๊ฒ ๊ถํ์ ๋ถ์ฌ ํ๋ค๋ฉด ํด๋น ์ฌ์ง์ ๋ณด์ฌ์ฃผ๋ ์ปค์คํ ์จ๋ฒ์ ๋ณด์ฌ ์ฃผ๋ฉด ๋๊ฒ ์ฃ ?
์ ์ฐฝ์์ ํ๋๋ฅผ ์ ํํด ์ฌ์ฉ์๊ฐ ๊ถํ ์ค์ ํ ์ฑ์ ๋๊ณ ๋ค์ ์ฑ์ ๋ค์ด์ค๋ฉด ์ด์ ๋ .notDetermined๋ฅผ ํ์ง ์์ต๋๋ค! ์๋ ์ด๋ฏธ ๊ถํ์ด ๋ถ์ฌ ๋์ด .notDetermined๊ฐ ์๋๊ฒ ๋๊ฒ์ด๊ธฐ ๋๋ฌธ์ด์์.
์ต์ด ๊ถํ์ ์ค์ ํ ๋ค ๋ค์ ์ฑ์ ๋ค์ด์ค๊ฒ ๋๋ฉด
.notDetermined๋ฅผ ํ์ง ์๊ณ ์ ์ฌ์ง์์, Don't allow๋ฅผ ์ ํํ์๋ค๋ฉด 1์ .denied๊ฐ ํธ์ถ๋๊ณ , ๊ถํ์ ๋ถ์ฌ ํ๋ค๋ฉด .authorized๋ .limited๊ฐ ํธ์ถ ๋๋ ๊ฑฐ์ฃ ! ์ด๋ ๊ฒ ํ๋ฉด ์ฌ์ฉ์๋ ์ฑ์ ์ต์ด๋ก ์ผค ๋ ๊ถํ์ ์ค์ ํ ์ ์๋ ์ผ๋ฟ์ฐฝ์ ๋ณด๊ฒ ๋๊ณ ๊ทธ ๋ค์ ๋ถํฐ๋ ์ค์ ๋ ๊ถํ์ผ๋ก ์ฑ์ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ ๊ฒ๋๋น ~~
์ด์ ๋ฒ์ด์ง ์ ์๋ ์ผ์ด์ค ํ๋๋ฅผ ์๊ฐํด ๋ด ์๋น! ์ฌ์ฉ์๊ฐ ์ด๋ฏธ์ง ์ ํํ๊ธฐ ๋ฒํผ์ ๋๋ฅธ ๋ค ์ผ๋ฟ ๋ทฐ๊ฐ ๋ ์ ์๋ฌด ์๊ฐ์์ด Don't Allow๋ฅผ ๋๋ ๋ค๊ณ ํฉ์๋ค! ๊ทธ๋ฌ๋ฉด ๊ทธ ํ๋ก ๋ฒํผ์ ๋๋ฌ๋ ๊ฐค๋ฌ๋ฆฌ ์ ๊ทผ ๊ถํ์ด ์๊ธฐ ๋๋ฌธ์ ์๋ฌด๊ฒ๋ ๋จ์ง ์์ ๊ฑฐ์์ใ ใ ์ฌ์ฉ์๋ ์๋ฌด๊ฒ๋ ๋ชจ๋ฅด๊ณ ๋ ์ด์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๊ฒ ๋ ์ง๋ ๋ชฐ๋ผ์! ๊ทธ๋์!!
์ข ๋ ์ฌ์ฉ์ ์ธก๋ฉด์ ๊ณ ๋ คํด์ ์ฝ๋๋ฅผ ์์ฑํด ๋ด ์๋ค
func moveToSetting() {
let alertController = UIAlertController(title: "๊ถํ ๊ฑฐ๋ถ๋จ", message: "์จ๋ฒ ์ ๊ทผ์ด ๊ฑฐ๋ถ ๋์์ต๋๋ค. ์ฑ์ ์ผ๋ถ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ด์", preferredStyle: UIAlertController.Style.alert)
let okAction = UIAlertAction(title: "๊ถํ ์ค์ ์ผ๋ก ์ด๋ํ๊ธฐ", style: .default) { (action) in
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
print("Settings opened: \(success)")
})
}
}
let cancelAction = UIAlertAction(title: "ํ์ธ", style: .cancel, handler: nil)
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.present(alertController, animated: false, completion: nil)
}
ํจ์ ํ๋๋ฅผ ์์ฑํด ๋ณผ๊ฒ์! ์ฝ๋๊ฐ ๊ธธ์ง๋ง ๊ฐ๋จํ๊ฒ UIAlertController ๋ฅผ ๋์ฐ๋ ์ฝ๋ ์ ๋๋ค. ์ผ๋ฟ ์ฐฝ์ ์ด ๋๊ฐ์ ๋ฒํผ์ด ์์ต๋๋ค. ์ผ๋ฟ ์ฐฝ์์๋ ์ฌ์ฉ์์๊ฒ ์จ๋ฒ ์ ๊ทผ์ด ๊ฑฐ๋ถ ๋์๋ค๋ ๊ฒ์ ์๋ ค์ค๋๋ค! ๋ฒํผ์ ์ด ๋๊ฐ์ธ๋ฐ์, ํ์ธ์ ๋๋ฅด๋ฉด ์ผ๋ฟ ์ฐฝ์ด ๋ซํ๊ฒ ๋๊ณ "๊ถํ ์ค์ ์ผ๋ก ์ด๋ํ๊ธฐ"๋ฅผ ๋๋ฅด๋ฉด ์น์ ํ๊ฒ ์ฑ์ ๊ถํ ์ค์ ํ์ด์ง๋ก ์ด๋ํด ์ค๋๋ค! ๊ทธ๋ฌ๋ฉด ์ฌ์ฉ์๋ ๊ถํ์ ๊ฑฐ๋ถ ํ ๋ค ๋ค์ ๋ฒํผ์ ๋๋ฅด๊ฑฐ๋ ๋ค์ ์ฑ์ ์ ์ํด์ ๋ฒํผ์ ๋๋ฅด๋ฉด! ๊ถํ ๊ฑฐ๋ถ๋นํ ๊ฒ์ ๋ฌด์์์ ์ผ๋ก ์๊ฒ ๋๊ณ ์ค์ ์ฐฝ์ผ๋ก ์ด๋ํด์ ๊ถํ์ ๋ค์ ๋ถ์ฌ ๋ฐ์ ์ ์๊ฒ ๋ฉ๋๋ค!!
์ด์ ์ด ํจ์๋ฅผ ์ ์ ํ ๊ณณ์ ๋ฐฐ์นํด ๋ด ์๋ค
if #available(iOS 14, *) {
switch PHPhotoLibrary.authorizationStatus(for: .readWrite) {
case .notDetermined:
print("not determined")
PHPhotoLibrary.requestAuthorization(for: .readWrite) { status in
switch status {
case .authorized, .limited:
print("์ปค์คํ
๊ฐค๋ฌ๋ฆฌ๋ก ์ด๋")
case .denied:
DispatchQueue.main.async {
self.moveToSetting()
}
default:
print("๊ทธ ๋ฐ์ ๊ถํ์ด ๋ถ์ฌ ๋์์ต๋๋ค.")
}
}
case .restricted:
print("restricted")
case .denied:
DispatchQueue.main.async {
self.moveToSetting()
}
case .limited, .authorized:
print("์ปค์คํ
๊ฐค๋ฌ๋ฆฌ๋ก ์ด๋")
default:
print("")
}
์ฝ๋๋ฅผ ์ข ๋ฐ๊ฟ ์ฃผ์์ต๋๋ค! .limited์ .authorized๋ ๊ถํ์ ์ป์ ๊ฒ์ด๋ฏ๋ก ์ปค์คํ ๊ฐค๋ฌ๋ฆฌ๋ก ์ด๋ํ๋ ์ฝ๋๋ฅผ ๋ฃ์ด์ฃผ๋ฉด ๋ฉ๋๋ค. authorizationStatus(for:)์ค requestAuthorization(for:) ๋ ๊ณณ ๋ชจ๋ ๊ฐ๋จํ๊ฒ ์ผ์ด์ค๋ฌธ์ ํฉ์ณ ์ค์๋ค.
๋ค์์ผ๋ก .denied๋ ๊ฒฝ์ฐ ์ผ๋ฟ ์ฐฝ์ ๋์ฐ๋ ํจ์๋ฅผ ํธ์ถํด ์ค๋๋ค! ๋ฐ๋์ ๋ช ์ฌํ ๊ฒ์ ํด๋ก์ ์์์ ๋ค๋ฅธ ์ฐ๋ ๋๋ก ๋์ํ๊ธฐ ๋๋ฌธ์ DispatchQueue๋ฅผ ํตํด์ main์์ ์ฝ๋๊ฐ ๋ ์ ์๋๋ก ๋ฐ๊พธ์ด ์ค๋๋ค.
์ ์ด์ ์ฑ์ ๋ค์ ์์ ํ ์ง์ฐ๊ณ ๋ค์ ์คํํด ๋ด ์๋ค
์ฌ์ฉ์๊ฐ .denied ๊ถํ์ ๋ถ์ฌ ํ ๊ฒฝ์ฐ (Don't allow๋ฅผ ๋๋ ์ ๋) ์์ ๊ฐ์ ์ฐฝ์ด ๋จ๋ ๊ฒ์ ํ์ธ ํ ์ ์์ต๋๋ค~~ ๊ทธ๋ฆฌ๊ณ ๊ถํ ์ค์ ์ผ๋ก ์ด๋ํ๊ธฐ ๋ฒํผ์ ๋๋ฅด๋ฉด ์น์ ํ๊ฒ ๊ถํ ์ค์ ํ์ด์ง๋ก ์ด๋ํฉ๋๋ค!! ์ข์ ์์ฐ์ค๋ฌ์ ์ด ๐๐๐
.restricted์ default์๋ ์ ์ ํ ์ผ๋ฟ ๋ทฐ๋ฅผ ๋์ ์ฌ์ฉ์์๊ฒ ์๋ ค์ฃผ๋ฉด ์ข๊ฒ ์ฃต?? ์ฃผ์ ํ ๊ฒ์ ๋ฉ์ธ ์ค๋ ๋์์ ๋๋ ค์ผ ํ๋ค๋ ๊ฒ ์์ผ์๋ฉด ์๋์ (์ฝ์ง ํ๊ฒ ๋ ๊ฐ๋ฅ์ฑ ๋์)
๊ถํ ๋ฐ๊พธ์ง ๋ง๊ณ ์ฑ์ ๋ค์ ์ฌ ์คํํ๋ฉด ๊ฑฐ๋ถ๋ ๊ถํ ๋๋ฌธ์ ๋ค์ ์ฌ์ฉ์์๊ฒ ๊ถํ ์ค์ ์ ํด๋ฌ๋ผ๋ ์ผ๋ฟ๋ทฐ๊ฐ ๋จ๋ ๊ฒ์ ํ์ธ ํ ์ ์์ต๋๋ค!
iOS 13 ๋ฏธ๋ง๋ ๋์ผํ๊ฒ ๊ตฌํํด ์ฃผ์๋ฉด ๋ฉ๋๋ค
switch PHPhotoLibrary.authorizationStatus() {
case .notDetermined:
print("13 not determined")
PHPhotoLibrary.requestAuthorization { status in
switch status {
case .authorized, .limited:
print("์ปค์คํ
๊ฐค๋ฌ๋ฆฌ๋ก ์ด๋")
case .denied:
DispatchQueue.main.async {
self.moveToSetting()
}
default:
print("๊ทธ ๋ฐ์ ๊ถํ์ด ๋ถ์ฌ ๋์์ต๋๋ค.")
}
}
case .restricted:
print("13 restricted")
case .denied:
DispatchQueue.main.async {
self.moveToSetting()
}
case .limited, .authorized:
print("13 ์ปค์คํ
๊ฐค๋ฌ๋ฆฌ๋ก ์ด๋")
@unknown default:
print("13 unKnown")
}
์ด๋ฒ ํํ ๋ฆฌ์ผ์ ์ปค์คํ ๊ฐค๋ฌ๋ฆฌ๋ฅผ ๊ตฌํํ๊ธฐ ๋ณด๋ค๋ ๊ทธ ์ด์ ์ ๊ผญ ํด์ค์ผ ํ ๊ถํ ์ป์ด์ค๊ธฐ๋ฅผ ํด๋ดค์ต๋๋ค~ ๋ฌด์๋ณด๋ค ์์ฐ์ค๋ฝ๊ฒ ๊ถํ์ ์ป์ด์ค๊ฒ๋ ๊ตฌํํด ๋ณด์๋๋ฐ์. ๋ํ ์ผ ์ค์!! ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์๋ค๋ฉด ๊ณต์ ๋ถํ๋๋ฆฝ๋๋น
๋ค์ ํํ ๋ฆฌ์ผ์๋ limited์ ๋ํด ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค! ์ ํ๋ ํ๊ฒฝ์์ ์ ๊ฒฝ ์จ์ค์ผ ํ ๊ฒ์ด ์๊ธฐ ๋๋ฌธ์ ๐๐๐ ใ ใ ใ
์ด๋ ๊ฒ ํฌ์คํ ํ๋๋ฐ ์๊ฐ์ด ๋๋ฌด ์ค๋ ๊ฑธ๋ฆฌ๋ค์ ใ ใ ์ด๋ป๊ฒ ํด์ผ ์กฐ๊ธ๋ ํจ์จ์ ์ผ๋ก ํฌ์คํ ํ ์ ์์๋ จ์ง..
์ฝ๋ ์ฎ๊ฒจ๊ฐ์ค ๋ ์ถ์ฒ ๋ฐํ ์ฃผ์ธ์!!
์ฐธ๊ณ ์ฌ์ดํธ
Apple PhotoKit
์ค์ ์ผ๋ก ์ด๋
https://stackoverflow.com/questions/28152526/how-do-i-open-phone-settings-when-a-button-is-clicked
๋๊ธ