๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŽ iOS

[Swift] PhotoKit ์‚ฌ์šฉํ•ด์„œ ์ปค์Šคํ…€ ์•จ๋ฒ” ๋งŒ๋“ค๊ธฐ - Permission ์ฒ˜๋ฆฌํ•˜๊ธฐ PHPhotoLibrary์˜ authorizationStatus์™€ requestAuthorization

by ํ‹ด๋”” 2022. 2. 5.
728x90
๋ฐ˜์‘ํ˜•

๐Ÿ‘‹ 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://developer.apple.com/documentation/photokit/delivering_an_enhanced_privacy_experience_in_your_photos_app

์„ค์ •์œผ๋กœ ์ด๋™

https://stackoverflow.com/questions/28152526/how-do-i-open-phone-settings-when-a-button-is-clicked

 

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€