Setup CloudKit in SwiftUI project and get user info | Advanced Learning #21
CloudKit
→ 애플 기기 연동 가능한 공용 데이터베이스CloudKit
실행 → 데이터베이스 설치 func fetchiCloudUserRecordID() {
CKContainer.default().fetchUserRecordID { [weak self] returnedId, returnedError in
guard let self = self else { return }
if let id = returnedId {
self.discoveriCloudUser(id: id)
}
}
}
func discoveriCloudUser(id: CKRecord.ID) {
CKContainer.default().discoverUserIdentity(withUserRecordID: id) { [weak self] returnedIdentity, returnedError in
guard let self = self else { return }
DispatchQueue.main.async {
if let name = returnedIdentity?.nameComponents?.givenName {
self.userName = name
}
}
}
}
DispatchQueue.main
을 통해 스레드 관리 → 강한 참조 사이클 방지를 위한 weak self
선언 주의struct CloudKitUserBootCamp: View {
@StateObject private var viewModel = CloudKitUserBootCampViewModel()
var body: some View {
VStack {
Text("IS SIGNED IN: \(viewModel.isSignedIntoiCloud.description.uppercased())")
Text(viewModel.error)
Text("Permission Status: \(viewModel.permissionStatus.description)")
Text("User Name: \(viewModel.userName)")
}
}
}
import SwiftUI
import CloudKit
class CloudKitUserBootCampViewModel: ObservableObject {
@Published var permissionStatus: Bool = false
@Published var isSignedIntoiCloud: Bool = false
@Published var error: String = ""
@Published var userName: String = ""
init() {
getiCloudStatus()
requestPermission()
fetchiCloudUserRecordID()
}
private func getiCloudStatus() {
CKContainer.default().accountStatus { [weak self] status, error in
guard let self = self else { return }
DispatchQueue.main.async {
switch status {
case .couldNotDetermine:
self.error = CloudKitError.iCloudAccountNotDetermined.rawValue
break
case .available:
self.isSignedIntoiCloud = true
break
case .restricted:
self.error = CloudKitError.iCloudAccountRestricted.rawValue
break
case .noAccount:
self.error = CloudKitError.iCloudAccountNotFound.rawValue
break
case .temporarilyUnavailable:
self.error = CloudKitError.iCloudAccountUnavailable.rawValue
break
@unknown default:
self.error = CloudKitError.iCloudAccountUnknown.rawValue
break
}
}
}
}
enum CloudKitError: String, LocalizedError {
case iCloudAccountUnavailable
case iCloudAccountNotFound
case iCloudAccountNotDetermined
case iCloudAccountRestricted
case iCloudAccountUnknown
}
func requestPermission() {
CKContainer.default().requestApplicationPermission([.userDiscoverability]) { [weak self] returnedStatus, returnedError in
guard let self = self else { return }
DispatchQueue.main.async {
if returnedStatus == .granted {
self.permissionStatus = true
}
}
}
}
func fetchiCloudUserRecordID() {
CKContainer.default().fetchUserRecordID { [weak self] returnedId, returnedError in
guard let self = self else { return }
if let id = returnedId {
self.discoveriCloudUser(id: id)
}
}
}
func discoveriCloudUser(id: CKRecord.ID) {
CKContainer.default().discoverUserIdentity(withUserRecordID: id) { [weak self] returnedIdentity, returnedError in
guard let self = self else { return }
DispatchQueue.main.async {
if let name = returnedIdentity?.nameComponents?.givenName {
self.userName = name
}
}
}
}
}
직접 허락을 받은 뒤 불리언 변수
permissionStatus
를 참으로 변경하는 데, 이 값이 바뀌었을 때 자동으로fetchCloudUserRecordID
함수를 호출하는 게 앱 사용 흐름 상 적절할 것 같다.