20200927のSwiftに関する記事は4件です。

SwiftUI100本ノック

SwiftUI(と関連知識)を習得するための100本ノックです。
「SwiftUIチュートリアルの次に何をすれば良いかわからない」という人向けに作ってみました。
100問無いので逐次追加します。
またもっと良い解答例があればコメントでどんどん教えてください m(_ _)m

かんたん(SwiftUIの簡単な構文だけで実装可能)

画像をリサイズして表示(fit)

150✖︎200サイズに画像をリサイズして表示させてください。
アスペクト比が異なる場合は余白を赤色で表示してください。

画像をリサイズして表示(fit)

解答

画像をリサイズして表示(clip)

150✖︎200サイズに画像をリサイズして表示させてください。
アスペクト比が異なる場合ははみ出た箇所を切り取って表示してください。

画像をリサイズして表示(clip)

解答

参考
【SwiftUI】画像(Image)の使い方

画像を丸く切り取り、枠を付ける

150✖︎150サイズに画像をリサイズし、丸く切り取り、黒い枠を付けて表示させてください。

画像を丸く切り取り、枠を付ける

解答

等間隔でViewを等間隔で横に並べる

画像を横に等間隔で横に並べてください。

等間隔でViewを等間隔で横に並べる)

解答

NavigationViewを隠す

NavigationView を隠してください

画像をリサイズして表示(fit)

解答

画面遷移時に値を渡す

画面遷移時に値を渡してください。

1.gif

解答

Picker を表示する

Picker を表示してください

1.gif

解答

TabViewを使って画面を切り替える

TabViewを使って画面を切り替えてください

1.gif

解答

Buttonが押されたら文字を変える

Buttonが押されたら文字を変えてください。

1.gif

解答

参考
SwiftUIにおけるscaledToFill()とかscaledToFit()とかaspectRatio(_:contentMode:)等の使い分け

SwiftUI でアラートを表示する

SwiftUI でアラートを表示させてください

1.gif

解答

Button内の画像やテキストの色を変えない

Buttonが押されたら文字の色を変えてください。
Button内の画像やテキストの色を変えないでください。

1.gif

解答

ふつう(SwiftUIだけで実装可能)

SwiftUIでアラートとシートを出し分ける

数字が入力されたらシートを表示してください。
数字以外が入力されたらアラートを表示してください。

1.gif

解答

Buttonからプッシュ遷移をする(NavigationLinkを無効にする)

NavigationLink内のテキストではなく、Button内のテキストが押されたら画面遷移をしてください。

1.gif

解答

SwiftUIで続きを読む。。。ボタンがあるViewを実装する

SwiftUIで続きを読む。。。ボタンがあるViewを実装してください。

1.gif

解答

アプリ起動時に画面を遷移させる

アプリ起動時に画面を遷移させてください。

アプリ起動時に画面を遷移させる

解答

Text中の文字の太さや色を変える

Text中の文字の太さや色を変えてください。

1.png

解答

FunctionBuilderを使ってViewに影をつける

FunctionBuilderを使ってViewに影をつけてください。

1.png

解答

ViewModifierを使ってViewに影をつける

ViewModifierを使ってViewに影をつけてください。

1.png

解答

リストを編集する

リストを編集してください。

1.gif

解答

UICollectionViewのようにViewを並べる

UICollectionViewのようにViewを並べてください。

1.gif

解答

参考
Q-Mobile/QGrid

画面遷移先の View から遷移元のメソッドを呼び出す

画面遷移先の View から遷移元のメソッドを呼び出してください。

1.gif

解答

リストのセルをタップするとアラートが表示させる

リストのセルをタップするとアラートが表示させてください。

1.gif

解答

むずかしい(UIKitや他のフレームワークが必要)

よくあるチュートリアル画面をUIPageViewControllerとSwiftUIで作る

画像のような良くあるウェークスルー画面を実装してください。

1.gif

解答

SwiftUIで閉じることができないモーダルを表示する

SwiftUIで閉じることができないモーダルを表示してください。

1.gif

解答

フルスクリーンモーダルを表示する

フルスクリーンモーダルを表示してください。

1.gif

解答

文字列中にタップ可能なリンクを追加する

文字列中にタップ可能なリンクを追加してください。

1.gif

解答

GithubのAPIを叩き、リポジトリの情報をリストに表示する(Closure)

GithubのAPI( https://api.github.com/search/repositories?q=swift&sort=stars&page=1&per_page=30 )を叩きリポジトリの情報をリストに表示してください。
Closureを使用してください。

1.gif

解答

参考
Infinite List Scroll with SwiftUI and Combine

GithubのAPIを叩き、リポジトリの情報をリストに表示する(Combine)

GithubのAPI( https://api.github.com/search/repositories?q=swift&sort=stars&page=1&per_page=30 )を叩きリポジトリの情報をリストに表示してください。
Combineを使用してください。

1.gif

解答

参考
Infinite List Scroll with SwiftUI and Combine

GithubのAPIを叩き、リポジトリの情報をリストに表示する。一番下までスクロールされたら追加で取得してください。

GithubのAPI( https://api.github.com/search/repositories?q=swift&sort=stars&page=1&per_page=30 )を叩きリポジトリの情報をリストに表示してください。
一番下までスクロールされたら追加で取得してください。

1.gif

解答

参考
Infinite List Scroll with SwiftUI and Combine

GithubのAPIを叩き、リポジトリの情報をリストに表示する。一番下までスクロールされたら追加で取得してください。Indicator も表示してください。

GithubのAPI( https://api.github.com/search/repositories?q=swift&sort=stars&page=1&per_page=30 )を叩きリポジトリの情報をリストに表示してください。
一番下までスクロールされたら追加で取得してください。

1.gif

解答

参考
Infinite List Scroll with SwiftUI and Combine

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftUIでフォトライブラリ

SwiftUIでフォトライブラリを表示する

ボタンをタップして、フォトライブラリを表示します。
フォトライブラリで写真を選択すると、全画面に表示します。

環境

Swift 5.3
Xcode 12.0.1
macOS 10.15.7

フォトライブラリ

フォトライブラリをSwiftUIでラップした構造体を定義します。

ImagePicker.swift
import SwiftUI

struct ImagePicker: UIViewControllerRepresentable {
    var sourceType: UIImagePickerController.SourceType = .photoLibrary

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let imagePicker = UIImagePickerController()
        imagePicker.allowsEditing = false
        imagePicker.sourceType = sourceType
        return imagePicker
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {

    }
}

最初の画面

アプリの基本となる画面の構造体です。
ステート変数の基づいて、フォトライブラリをシート形式で表示します。

ContentView.swift
import SwiftUI

struct ContentView: View {
    @State private var image = UIImage()
    @State private var isShowPhotoLibrary = false

    var body: some View {
        VStack {
            Image(uiImage: self.image)
            Button(action: {
                self.isShowPhotoLibrary = true
            }, label: {
                Text("Photo Library")
                    .padding()
            })
        }
        .sheet(isPresented: $isShowPhotoLibrary, content: {
            ImagePicker(sourceType: .photoLibrary)
        })
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

フォトライブラリの写真を選択する

UIImagePickerControllerDelegateプロトコルに準拠します。

ImagePicker.swift
import SwiftUI

struct ImagePicker: UIViewControllerRepresentable {
    // MARK: - Working with UIViewControllerRepresentable
    var sourceType: UIImagePickerController.SourceType = .photoLibrary

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let imagePicker = UIImagePickerController()
        imagePicker.allowsEditing = false
        imagePicker.sourceType = sourceType
        imagePicker.delegate = context.coordinator  // Coordinater to adopt UIImagePickerControllerDelegate Protcol.
        return imagePicker
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {

    }

    // MARK: - Using Coordinator to Adopt the UIImagePickerControllerDelegate Protocol
    @Binding var selectedImage: UIImage
    @Environment(\.presentationMode) private var presentationMode

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        var parent: ImagePicker

        init(_ parent: ImagePicker) {
            self.parent = parent
        }

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

            if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
                parent.selectedImage = image
            }

            parent.presentationMode.wrappedValue.dismiss()
        }
    }
}

選択した写真を表示する

Imageビューにモディファイアを追加します。
画面遷移するタイミングで、選択した写真をimageプロパティに設定します。

ContentView.swift
struct ContentView: View {
    @State private var image = UIImage()
    @State private var isShowPhotoLibrary = false

    var body: some View {
        VStack {
            Image(uiImage: self.image)
                .resizable()
                .scaledToFill()
                .frame(minWidth: 0, maxWidth: .infinity)
                .edgesIgnoringSafeArea(.all)
            Button(action: {
                self.isShowPhotoLibrary = true
            }, label: {
                Text("Photo Library")
                    .padding()
            })
        }
        .sheet(isPresented: $isShowPhotoLibrary, content: {
            ImagePicker(sourceType: .photoLibrary, selectedImage: self.$image)
        })
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SwiftLog、XcodeのOutput出力であれば、バックエンド使わず、Extension追加で賄う

SwiftLog

https://github.com/apple/swift-log

Swift Packageです。

Extension

import Logging

extension Logger {
    static var level = Logger.Level.info

    init(function: String = #function) {
        self.init(label: function)
        self.logLevel = Logger.level
    }

    func trace(_ message: String = "" , function: String = #function, line: Int = #line) {
        self.trace(Logger.Message(stringLiteral: String("[\(function):\(line)] \(message)")))
    }

    func debug(_ message: String = "" , function: String = #function, line: Int = #line) {
        self.debug(Logger.Message(stringLiteral: String("[\(function):\(line)] \(message)")))
    }

    func info(_ message: String = "" , function: String = #function, line: Int = #line) {
        self.info(Logger.Message(stringLiteral: String("[\(function):\(line)] \(message)")))
    }

    func notice(_ message: String = "" , function: String = #function, line: Int = #line) {
        self.notice(Logger.Message(stringLiteral: String("[\(function):\(line)] \(message)")))
    }

    func warning(_ message: String = "" , function: String = #function, line: Int = #line) {
        self.warning(Logger.Message(stringLiteral: String("[\(function):\(line)] \(message)")))
    }

    func error(_ message: String = "" , function: String = #function, line: Int = #line) {
        self.error(Logger.Message(stringLiteral: String("[\(function):\(line)] \(message)")))
    }

    func critical(_ message: String = "" , function: String = #function, line: Int = #line) {
        self.critical(Logger.Message(stringLiteral: String("[\(function):\(line)] \(message)")))
    }
}

Example

import UIKit
import Logging

class ViewController: UIViewController {

    let logger = Logger()

    override func viewDidLoad() {
        super.viewDidLoad()
        logger.info()
        logger.info("start")
 :
 :
 :
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSアプリからGoogleカレンダーにアクセスする

今回はiOSアプリからGoogle Calenear APIを通してGoogleカレンダーにアクセスしてみたいと思います。

環境: Xcode 12.0、Swift 5

準備

まずGoogle Cloud PlatformにアクセスしてGoogle Calendar APIを有効にします。
続いてOAuth認証を行うためのOAuthクライアントIDを取得します。
以下の記事の「クライアントIDを登録」に書かれている手順に従ってクライアントIDの取得の申請を行います。

Swift4でGoogleCalendarAPIを叩いてみた

使用する外部ライブラリ

Google API自体はREST APIになっていますが、これを直接呼び出すのは大変なので外部ライブラリを使用することにします。
今回は以下のライブラリを使用します。

・Google認証
AppAuth
GTMAppAuth

・Google Calendarとのアクセス
GoogleAPIClientForREST/Calendar

上記のライブラリはいずれもCocoaPodsで導入できます。
以下のようにPodfileを記述しpod installを実行して導入します。

platform :ios, '14.0'

target 'GoogleCalendarSample' do
  use_frameworks!

  pod 'AppAuth'
  pod 'GTMAppAuth'
  pod 'GoogleAPIClientForREST/Calendar'

end

認証

ではAppAuthとGTMAppAuthを使用してGoogle認証を行う処理を実装します。

まずAppDelegateにOIDExternalUserAgentSessionクラスを追加します。

AppDelegate.swift
import UIKit
import AppAuth
import GTMAppAuth

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    var currentAuthorizationFlow: OIDExternalUserAgentSession?

---------------- (以下略) ----------------

その上でGoogle認証を行う画面で以下の処理を記述します。

import UIKit
import AppAuth
import GTMAppAuth
import GoogleAPIClientForREST

---------------- (中略) ----------------

private var authorization: GTMAppAuthFetcherAuthorization?
private let clientID = "xxxxxxxxxxxxxxxxxxxx"
private let reverseClientID = "xxxxxxxxxxxxxxxxxxxx"
typealias showAuthorizationDialogCallBack = ((Error?) -> Void)

private func showAuthorizationDialog(callBack: @escaping showAuthorizationDialogCallBack) {
    let scopes = ["https://www.googleapis.com/auth/calendar","https://www.googleapis.com/auth/calendar.readonly","https://www.googleapis.com/auth/calendar.events","https://www.googleapis.com/auth/calendar.events.readonly"]

    let configuration = GTMAppAuthFetcherAuthorization.configurationForGoogle()
    let redirectURL = URL.init(string: reverseClientID + ":/oauthredirect")

    let request = OIDAuthorizationRequest.init(configuration: configuration,
                                                   clientId: clientID,
                                                   scopes: scopes,
                                                   redirectURL: redirectURL!,
                                                   responseType: OIDResponseTypeCode,
                                                   additionalParameters: nil)

    let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
    appDelegate.currentAuthorizationFlow = OIDAuthState.authState(
        byPresenting: request,
        presenting: self,
        callback: { (authState, error) in
            if let error = error {
                NSLog("\(error)")
            } else {
                if let authState = authState {
                    self.authorization = GTMAppAuthFetcherAuthorization.init(authState: authState)
                    GTMAppAuthFetcherAuthorization.save(self.authorization!, toKeychainForName: "authorization")
                }
            }
            callBack(error)
    })
}

以下の変数にはOAuthクライアントIDを取得した時に入手したIDを記載します。
clientにはOAuth 2.0クライアントIDを、reverseClientIDにはリバースクライアントIDを記載します。

private let clientID = "xxxxxxxxxxxxxxxxxxxx"
private let reverseClientID = "xxxxxxxxxxxxxxxxxxxx"

今回必要とする権限を配列scopesに設定します。今回はGoogleカレンダーを検索・変更する為の権限を要求しています。

let scopes = ["https://www.googleapis.com/auth/calendar","https://www.googleapis.com/auth/calendar.readonly","https://www.googleapis.com/auth/calendar.events","https://www.googleapis.com/auth/calendar.events.readonly"]

OIDAuthStateクラスのauthStateメソッドが実行されたところで以下の様なGoogle認証のダイアログが表示されます。
Google認証ダイアログ
ユーザーがダイアログにgmailアドレスとパスワードを正しく入力し認証が完了した場合は、authStateメソッドのCallback関数でGTMAppAuthFetcherAuthorizationクラスを生成し保存します。
このGTMAppAuthFetcherAuthorizationクラスが残っているうちは認証ダイアログを再度表示する必要はありません。

イベントの検索

では続いてGoogleAPIClientForRESTを使用してGoogleカレンダーにアクセスしてみたいと思います。
まずはGoogleカレンダーから既存のイベントを取得する処理を記載します。
getメソッドに開始日時、終了日時を渡すとGoogleカレンダーから開始日時 〜 終了日時の間にあるイベントを検索するプログラムです。

import UIKit
import AppAuth
import GTMAppAuth
import GoogleAPIClientForREST

---------------- (中略) ----------------

private var authorization: GTMAppAuthFetcherAuthorization?
private let clientID = "xxxxxxxxxxxxxxxxxxxx"
private let reverseClientID = "xxxxxxxxxxxxxxxxxxxx"
typealias showAuthorizationDialogCallBack = ((Error?) -> Void)
struct GoogleCalendaraEvent {
    var id: String
    var name: String
    var startDate: Date?
    var endDate: Date?
}
private var googleCalendarEventList: [GoogleCalendaraEvent] = []

private func showAuthorizationDialog(callBack: @escaping showAuthorizationDialogCallBack) {
---------------- (中略) ----------------
}

private func get(startDateTime: Date, endDateTime: Date) {
    if GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization") != nil {
        self.authorization = GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization")!
    }

    if self.authorization == nil {
        showAuthorizationDialog(callBack: {(error) -> Void in
            if error == nil {
                self.getCalendarEvents(startDateTime: startDateTime, endDateTime: endDateTime)
            }
        })
    } else {
        self.getCalendarEvents(startDateTime: startDateTime, endDateTime: endDateTime)
    }
}

private func getCalendarEvents(startDateTime: Date, endDateTime: Date) {
    let calendarService = GTLRCalendarService()
    calendarService.authorizer = self.authorization
    calendarService.shouldFetchNextPages = true

    let query = GTLRCalendarQuery_EventsList.query(withCalendarId: "primary")
    query.timeMin = GTLRDateTime(date: startDateTime)
    query.timeMax = GTLRDateTime(date: endDateTime)

    calendarService.executeQuery(query, completionHandler: { (ticket, event, error) -> Void in
        if let error = error {
            NSLog("\(error)")
        } else {
            if let event = event as? GTLRCalendar_Events, let items = event.items {
                self.googleCalendarEventList.removeAll()
                for item in items {
                    let id: String = item.identifier ?? ""
                    let name: String = item.summary ?? ""
                    let startDate: Date? = item.start?.dateTime?.date
                    let endDate: Date? = item.end?.dateTime?.date
                    self.googleCalendarEventList.append(GoogleCalendaraEvent(id: id, name: name, startDate: startDate, endDate: endDate))
                }
            }
        }
    })
}

まずGoole認証が完了しているかの確認を行います。
GTMAppAuthFetcherAuthorizationクラスが保存されているかを確認し、保存されていなかった場合は先に作成したshowAuthorizationDialog関数を呼び出しGoogle認証のダイアログを表示してGTMAppAuthFetcherAuthorizationクラスを取得します。
GTMAppAuthFetcherAuthorizationクラスが保存されていた場合はそれをそのまま使用します。

続いてGoogleAPIClientForRESTを使用してGooglカレンダーからイベントを取得します。
まずGooleカレンダーにアクセスする為のGTLRCalendarServiceクラスを生成しauthorizerプロパティにGTMAppAuthFetcherAuthorizationクラスを設定します。

let calendarService = GTLRCalendarService()
calendarService.authorizer = self.authorization
calendarService.shouldFetchNextPages = true

続いてGoogleカレンダーからイベントを検索するためのGTLRCalendarQuery_EventsListクラスを生成し、検索条件として開始日時と終了日時を設定します。

let query = GTLRCalendarQuery_EventsList.query(withCalendarId: "primary")
query.timeMin = GTLRDateTime(date: startDateTime)
query.timeMax = GTLRDateTime(date: endDateTime)

そしてこのGTLRCalendarQuery_EventsListクラスを引数にしてGTLRCalendarServiceクラスのexecuteQueryメソッドを実行しGoogleカレンダーからイベントを取得します。
イベントを取得できた時はexecuteQueryメソッドのCallback関数でGTLRCalendar_Eventsクラスが返ってきますのでここからイベントの情報を取得します。

if let event = event as? GTLRCalendar_Events, let items = event.items {
    self.googleCalendarEventList.removeAll()
    for item in items {
        let id: String = item.identifier ?? ""
        let name: String = item.summary ?? ""
        let startDate: Date? = item.start?.dateTime?.date
        let endDate: Date? = item.end?.dateTime?.date
        self.googleCalendarEventList.append(GoogleCalendaraEvent(id: id, name: name, startDate: startDate, endDate: endDate))
    }
}

特にidentifier(イベントのユニークID)が重要です。
イベントの変更や削除を行う時はこのidentifierがキーになります。

イベントの追加

では次はGoogleカレンダーにイベントを追加してみたいと思います。
addメソッドにイベント名、開始日時、終了日時を渡すとGoogleカレンダーにイベントを作成するプログラムです。

import UIKit
import AppAuth
import GTMAppAuth
import GoogleAPIClientForREST

---------------- (中略) ----------------

private var authorization: GTMAppAuthFetcherAuthorization?
typealias showAuthorizationDialogCallBack = ((Error?) -> Void)

private func showAuthorizationDialog(callBack: @escaping showAuthorizationDialogCallBack) {
---------------- (中略) ----------------
}

private func add(eventName: String, startDateTime: Date, endDateTime: Date) {

    if GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization") != nil {
        self.authorization = GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization")!
    }

    if self.authorization == nil {
        showAuthorizationDialog(callBack: {(error) -> Void in
            if error == nil {
                self.addCalendarEvent(eventName: eventName, startDateTime: startDateTime, endDateTime: endDateTime)
            }
        })
    } else {
        self.addCalendarEvent(eventName: eventName, startDateTime: startDateTime, endDateTime: endDateTime)
    }
}

private func addCalendarEvent(eventName: String, startDateTime: Date, endDateTime: Date) {

    let calendarService = GTLRCalendarService()
    calendarService.authorizer = self.authorization
    calendarService.shouldFetchNextPages = true

    let event = GTLRCalendar_Event()
    event.summary = eventName

    let gtlrDateTimeStart: GTLRDateTime = GTLRDateTime(date: startDateTime)
    let startEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
    startEventDateTime.dateTime = gtlrDateTimeStart
    event.start = startEventDateTime

    let gtlrDateTimeEnd: GTLRDateTime = GTLRDateTime(date: endDateTime)
    let endEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
    endEventDateTime.dateTime = gtlrDateTimeEnd
    event.end = endEventDateTime

    let query = GTLRCalendarQuery_EventsInsert.query(withObject: event, calendarId: "primary")
    calendarService.executeQuery(query, completionHandler: { (ticket, event, error) -> Void in
        if let error = error {
            NSLog("\(error)")
        }
    })
}

GTLRCalendarServiceクラスを生成するところまでは検索の場合と同じなのでその後の部分から説明します。
追加するイベントの情報を設定する為にGTLRCalendar_Eventクラスを生成します。
今回はイベントの名称、開始日時、終了日時を設定しますので、それぞれをGTLRCalendar_Eventクラスのsummaryプロパティ、startプロパティ、endプロパティに設定しています。

let event = GTLRCalendar_Event()
event.summary = eventName

let gtlrDateTimeStart: GTLRDateTime = GTLRDateTime(date: startDateTime)
let startEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
startEventDateTime.dateTime = gtlrDateTimeStart
event.start = startEventDateTime

let gtlrDateTimeEnd: GTLRDateTime = GTLRDateTime(date: endDateTime)
let endEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
endEventDateTime.dateTime = gtlrDateTimeEnd
event.end = endEventDateTime

尚、イベントのユニークIDとなるidentifierは新規追加の場合はGoogleカレンダーによって自動的に割り当てられますのでここで設定する必要はありません。

そしてGoogleカレンダーに新規追加する為のGTLRCalendarQuery_EventsInsertクラスをGTLRCalendar_Eventクラスを引数にして生成し、GTLRCalendarServiceクラスのexecuteQueryメソッドを実行することでGoogleカレンダーにイベントが新規追加されます。

イベントの変更

続いて既存のイベントの情報を変更してみます。
updateメソッドにイベントのidentifier、イベント名、開始日時、終了日時を渡すとGoogleカレンダーにある該当のidentifierのイベントの情報を変更するプログラムです。

import UIKit
import AppAuth
import GTMAppAuth
import GoogleAPIClientForREST

---------------- (中略) ----------------

private var authorization: GTMAppAuthFetcherAuthorization?
typealias showAuthorizationDialogCallBack = ((Error?) -> Void)

private func showAuthorizationDialog(callBack: @escaping showAuthorizationDialogCallBack) {
---------------- (中略) ----------------
}

private func update(eventId: String, eventName: String, startDateTime: Date, endDateTime: Date) {

    if GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization") != nil {
        self.authorization = GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization")!
    }

    if self.authorization == nil {
        showAuthorizationDialog(callBack: {(error) -> Void in
            if error == nil {
                self.updateCalendarEvent(eventId: eventId, eventName: eventName, startDateTime: startDateTime, endDateTime: endDateTime)
            }
        })
    } else {
        self.updateCalendarEvent(eventId: eventId, eventName: eventName, startDateTime: startDateTime, endDateTime: endDateTime)
    }
}

private func updateCalendarEvent(eventId: String, eventName: String, startDateTime: Date, endDateTime: Date) {
    let calendarService = GTLRCalendarService()
    calendarService.authorizer = self.authorization
    calendarService.shouldFetchNextPages = true

    let event = GTLRCalendar_Event()
    event.identifier = eventId
    event.summary = eventName

    let gtlrDateTimeStart: GTLRDateTime = GTLRDateTime(date: startDateTime)
    let startEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
    startEventDateTime.dateTime = gtlrDateTimeStart
    event.start = startEventDateTime

    let gtlrDateTimeEnd: GTLRDateTime = GTLRDateTime(date: endDateTime)
    let endEventDateTime: GTLRCalendar_EventDateTime = GTLRCalendar_EventDateTime()
    endEventDateTime.dateTime = gtlrDateTimeEnd
    event.end = endEventDateTime

    let query = GTLRCalendarQuery_EventsUpdate.query(withObject: event, calendarId: "primary", eventId: eventId)
    calendarService.executeQuery(query, completionHandler: { (ticket, event, error) -> Void in
        if let error = error {
            NSLog("\(error)")
        }
    })
}

更新の場合はGTLRCalendar_Eventクラスのidentifierプロパティに該当のイベントのIDを設定します。そして変更する値をGTLRCalendar_Eventクラスのプロパティに設定します。
その後、Googleカレンダーのイベントを更新する為のGTLRCalendarQuery_EventsUpdateクラスをGTLRCalendar_Eventクラスを引数にして生成し、それを引数にGTLRCalendarServiceクラスのexecuteQueryメソッドを実行します。

イベントの削除

最後にGoogleカレンダーのイベントの削除を行います。
deleteメソッドにイベントのidentifierを渡すとGoogleカレンダーから該当のイベントを削除するプログラムです。

import UIKit
import AppAuth
import GTMAppAuth
import GoogleAPIClientForREST

---------------- (中略) ----------------

private var authorization: GTMAppAuthFetcherAuthorization?
typealias showAuthorizationDialogCallBack = ((Error?) -> Void)

private func showAuthorizationDialog(callBack: @escaping showAuthorizationDialogCallBack) {
---------------- (中略) ----------------
}

private func delete(eventId: String) {

    if GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization") != nil {
        self.authorization = GTMAppAuthFetcherAuthorization(fromKeychainForName: "authorization")!
    }

    if self.authorization == nil {
        showAuthorizationDialog(callBack: {(error) -> Void in
            if error == nil {
                self.deleteCalendarEvent(eventId: eventId)
            }
        })
    } else {
        self.deleteCalendarEvent(eventId: eventId)
    }
}

private func deleteCalendarEvent(eventId: String) {
    let calendarService = GTLRCalendarService()
    calendarService.authorizer = self.authorization
    calendarService.shouldFetchNextPages = true

    let query = GTLRCalendarQuery_EventsDelete.query(withCalendarId: "primary", eventId: eventId)
    calendarService.executeQuery(query, completionHandler: { (ticket, event, error) -> Void in
        if let error = error {
            NSLog("\(error)")
        }
    })
}

削除はGTLRCalendarQuery_EventsDeleteクラスをイベントのidentifierを引数にして生成し、それを引数にGTLRCalendarServiceのexecuteQueryメソッドを実行することで行うことができます。

サンプルプログラム

今回作成したサンプルプログラムはGitHubで公開しています。
https://github.com/naosekig/GoogleCalendarSample

参考文献

CocoaDocs.org - GoogleAPIClientForRest
Qiita:Swift4でGoogleCalendarAPIを叩いてみた

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む