SlideShare a Scribd company logo
日記アプリで
CloudKitを使う
BUKURO.swift 2017.11.01
Bitz Co., Ltd. 村上幸雄
• 埼玉県朝霞市でソフトハウスを起業。
• macOSやiOS、Androidのアプリケーション開発を主に請け負う。
• 自社アプリの製作。
• Twitter: @m_yukio
• Facebook: yukio.murakami
• GitHub: murakami
• http://www.bitz.co.jp/weblog/
• BUKURO.swift
Cocoa勉強会とMOSAの合同勉強会。
毎月上旬の月曜日に池袋FORESTで開会。
https://cocoa-kanto.connpass.com/
• Swift勉強会 Developer's Tech Lab.
Cocoa勉強会 関東。
毎月下旬の土曜日に関東で開催。
https://cocoa-kanto.connpass.com/
Day Oneに代わる
日記アプリを作っています
10 GB Asset storage
100 MB Database storage
2 GB Data transfer
40 Requests per second
Overage Fees
Asset storage $0.03/GB
Database storage $3.00/GB
Data transfer $0.10/GB
Requests per sec $100 per 10 requests
容量小さい
リソース?
湘南.swiftのおさらい
コンテナ
コンテナID
デフォルトコンテナ
let container: CKContainer = CKContainer.default()
カスタムコンテナ
let container: CKContainer = CKContainer(identifier:
“iCloud.com.example.KeepADiary”)
データベース
公開データベース
let publicDatabase: CKDatabase = container.publicCloudDatabase
非公開データベース
let privateDatabase: CKDatabase = container.privateCloudDatabase
共有データベース
let sharedDatabase: CKDatabase = container.sharedCloudDatabase
アカウントの確認
CKContainer.default().accountStatus(completionHandler: {
accountStatus, error in
if error != nil {
print(error ?? "")
}
else if accountStatus == .noAccount {
let alert = UIAlertController.init(title: "Sign in to iCloud",
message: "Sign in to your iCloud account to write records.On the Home screen,
launch Settings, tap iCloud, and enter your Apple ID.Turn iCloud Drive on.If you don't have an iCloud
account, tap Create a new Apple ID.",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Okay", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
else {
print(“Insert your just-in-time schema code here”)
}
})
追加
/* レコードIDを生成 */
let uuidString = UUID.init().uuidString
let diaryRecordID: CKRecordID = CKRecordID(recordName: uuidString)
/* レコード・オブジェクトを生成 */
let diaryRecord: CKRecord = CKRecord(recordType: "Diary", recordID: diaryRecordID)
/* レコードのフィールドを設定 */
diaryRecord["UUID"] = uuidString as CKRecordValue
diaryRecord.setObject("本文です。" as NSString, forKey: "EntryText")
diaryRecord.setObject(Date() as NSDate, forKey: "DiaryDate")
/* レコードを保存する */
database.save(diaryRecord, completionHandler: { (record, error) in
if error != nil {
print(error)
}
else {
print(record)
}
})
更新
/* レコードIDからレコードを取得する */
database.fetch(withRecordID: diaryRecordID, completionHandler: { (record, error) in
if error != nil {
print(error)
}
else {
/* 値を更新する */
record.setObject("本文を更新します。" as NSString, forKey: "EntryText")
/* レコードを保存する */
database.save(diaryRecord, completionHandler: { (record, error) in
if error != nil {
print(error)
}
else {
print(record)
}
})
}
})
削除
/* 追加で使ったレコードIDで取得 */
database.delete(withRecordID: diaryRecordID, completionHandler: { (recordId, error) in
if error != nil {
print(error)
}
else {
print(recordId)
}
})
検索/* 検索条件 */
let now = Date()
var calendar = Calendar.current
calendar.locale = Locale(identifier: "ja")
var component = calendar.dateComponents([.year, .month, .day], from: now)
component.hour = 0
component.minute = 0
component.second = 0
let beginDate: NSDate = calendar.date(from:component)! as NSDate
let endDate: NSDate = NSDate(timeInterval: (60.0 * 60.0 * 24.0), since: beginDate as Date)
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "ja_JP")
dateFormatter.dateFormat = "yyyy/MM/dd HH:mm:ss"
let beginDateString = dateFormatter.string(from: beginDate as Date)
let endDateString = dateFormatter.string(from: endDate as Date)
let predicate = NSPredicate(format: "DiaryDate != %@", NSDate())
let query : CKQuery = CKQuery(recordType: "Diary", predicate: predicate)
/* 検索する */
database.perform(query, inZoneWith: nil, completionHandler: {
results, error in
if error != nil {
print(error)
}
else {
print(results)
/* 検索した結果 */
for record in results! {
/* 削除する */
database.delete(withRecordID: record.recordID, completionHandler: { (recordId, error) in
if error != nil {
print(error)
}
else {
print(recordId)
}
})
}
}
})
サブスクリプション保存
/* 条件 */
let predicate = NSPredicate(format: "TRUEPREDICATE")
let subscription = CKSubscription(recordType: "Diary",
predicate: predicate,
options: [CKSubscriptionOptions.firesOnRecordCreation,
CKSubscriptionOptions.firesOnRecordUpdate])
/* 通知 */
subscription.notificationInfo = CKNotificationInfo()
subscription.notificationInfo?.alertBody = "Item has been added."
subscription.notificationInfo?.alertLocalizationKey = "Diary record has changed!"
subscription.notificationInfo?.shouldBadge = true
/* 保存 */
database.save(subscription, completionHandler: {
subscription, error in
if error != nil {
print(error)
}
else {
print(subscription)
}
})
大容量ファイルをCloudKit
に格納する
アセットを使う
database.fetch(withRecordID: diaryRecordID, completionHandler: { (diaryRecord, error) in
print(#function)
if error != nil {
print(error)
}
else {
let asset = CKAsset(fileURL: fileUrl)
diaryRecord!["photo"] = asset
database.save(diaryRecord!, completionHandler: { (record, error) in
if error != nil {
print(error)
}
else {
print(record)
}
})
}
})
Assetフィールドにファイルを設定
レコードを保存するとファイルがアップロードさ
れる
Assetを操作するとダウンロードされる
容量問題
制限を超えるとお金を負担するのは開発者
定額課金などの検討が必要だが、制限を超えて発
生する金額と、定額課金の金額をどう対応づける
のか?
iCloud設計ガイド
CloudKitを取り入れた設計
アプリケーションのモデルオブジェクトの置き
換えおよびオブジェクトのローカル保存には
CloudKitフレームワークを使わないでください
。
このフレームワークは、iCloudとデータをやり
取りしたり、アプリケーションのユーザ間でデ
ータを共有したりするためのサービスです。
ありがとうございますありがとうございます

More Related Content

PPTX
日記アプリのデータ管理
幸雄 村上
 
PPTX
Cloud kitを使った日記アプリで写真をどう扱うか
幸雄 村上
 
PPTX
七曜表と備忘録
幸雄 村上
 
PPTX
OpenGLプログラミング
幸雄 村上
 
PDF
APIMeetup 20170329_ichimura
Tomohiro Ichimura
 
PPTX
RUDP
幸雄 村上
 
PDF
go generate 完全入門
yaegashi
 
PPTX
Keep a diary
幸雄 村上
 
日記アプリのデータ管理
幸雄 村上
 
Cloud kitを使った日記アプリで写真をどう扱うか
幸雄 村上
 
七曜表と備忘録
幸雄 村上
 
OpenGLプログラミング
幸雄 村上
 
APIMeetup 20170329_ichimura
Tomohiro Ichimura
 
go generate 完全入門
yaegashi
 
Keep a diary
幸雄 村上
 

Similar to 日記アプリでCloud kitを使う (20)

PPTX
Document based application
幸雄 村上
 
PDF
KanbanとTHETAとDK2とわたし
Maehana Tsuyoshi
 
PPTX
キーチェーン・アクセスのバックアップと同期
幸雄 村上
 
PPTX
独自Documentクラス
幸雄 村上
 
PDF
RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介
Fumiya Sakai
 
PPTX
Bukuro.makers
幸雄 村上
 
PDF
Mulvery@沖縄Ruby会議02
Daichi Teruya
 
PDF
Introduce Toaster (Toasterのご紹介)
Hiroshi Sakate
 
PPTX
デザインパターン
幸雄 村上
 
PPTX
The Bash in Tokyo : AppKitとUIKit
幸雄 村上
 
PPTX
Master-Detail App を実装する
幸雄 村上
 
PDF
Microsoft Graph API Library for Go
yaegashi
 
PDF
Power Appsで Excel関数を利用する3つの方法
Nagao Hiroaki
 
PDF
2020/06/16 tsjp-azure-staticwebapps-vs_codespaces
Issei Hiraoka
 
PDF
ReduxとSwiftの組み合わせ:改訂版
Fumiya Sakai
 
PDF
jQuery Mobile ハンズオン 資料
dsuke Takaoka
 
PPTX
IBM Watson Services for Core ML
幸雄 村上
 
PDF
Let's build a simple app with .net 6 asp.net core web api, react, and elasti...
Shotaro Suzuki
 
PPTX
独自Documentクラス
幸雄 村上
 
PDF
Swift 2.0 大域関数の行方から #swift2symposium
Tomohiro Kumagai
 
Document based application
幸雄 村上
 
KanbanとTHETAとDK2とわたし
Maehana Tsuyoshi
 
キーチェーン・アクセスのバックアップと同期
幸雄 村上
 
独自Documentクラス
幸雄 村上
 
RxDataSourceをNSDiffableDataSourceへ置き換える際のTips集紹介
Fumiya Sakai
 
Bukuro.makers
幸雄 村上
 
Mulvery@沖縄Ruby会議02
Daichi Teruya
 
Introduce Toaster (Toasterのご紹介)
Hiroshi Sakate
 
デザインパターン
幸雄 村上
 
The Bash in Tokyo : AppKitとUIKit
幸雄 村上
 
Master-Detail App を実装する
幸雄 村上
 
Microsoft Graph API Library for Go
yaegashi
 
Power Appsで Excel関数を利用する3つの方法
Nagao Hiroaki
 
2020/06/16 tsjp-azure-staticwebapps-vs_codespaces
Issei Hiraoka
 
ReduxとSwiftの組み合わせ:改訂版
Fumiya Sakai
 
jQuery Mobile ハンズオン 資料
dsuke Takaoka
 
IBM Watson Services for Core ML
幸雄 村上
 
Let's build a simple app with .net 6 asp.net core web api, react, and elasti...
Shotaro Suzuki
 
独自Documentクラス
幸雄 村上
 
Swift 2.0 大域関数の行方から #swift2symposium
Tomohiro Kumagai
 
Ad

More from 幸雄 村上 (16)

PDF
アプリケーション識別子.pdf
幸雄 村上
 
PDF
圧縮ネイティブ・ライブラリについて.pdf
幸雄 村上
 
PDF
分散環境におけるジャストインタイム設定の試み
幸雄 村上
 
PDF
SwiftのOptionalを理解する
幸雄 村上
 
PDF
え!それって参照渡し?
幸雄 村上
 
PDF
プライバシーとセキュリティ(リモート通知のデバイストークンの扱いなど)
幸雄 村上
 
PDF
AppleScriptなど
幸雄 村上
 
PDF
MojaveのDark Mode
幸雄 村上
 
PDF
AppleScriptとは何ぞや
幸雄 村上
 
PDF
Web API 通信の符号化について
幸雄 村上
 
PPTX
SwiftのOptionalを理解する
幸雄 村上
 
PPTX
Getting a packet trace
幸雄 村上
 
PPTX
Swiftでブロックチェーンを実装する
幸雄 村上
 
PPTX
ゲームの企画書づくりに挑戦
幸雄 村上
 
PPTX
サーバーレスアーキテクチャで悩んでます
幸雄 村上
 
PPTX
神経回路網の計算
幸雄 村上
 
アプリケーション識別子.pdf
幸雄 村上
 
圧縮ネイティブ・ライブラリについて.pdf
幸雄 村上
 
分散環境におけるジャストインタイム設定の試み
幸雄 村上
 
SwiftのOptionalを理解する
幸雄 村上
 
え!それって参照渡し?
幸雄 村上
 
プライバシーとセキュリティ(リモート通知のデバイストークンの扱いなど)
幸雄 村上
 
AppleScriptなど
幸雄 村上
 
MojaveのDark Mode
幸雄 村上
 
AppleScriptとは何ぞや
幸雄 村上
 
Web API 通信の符号化について
幸雄 村上
 
SwiftのOptionalを理解する
幸雄 村上
 
Getting a packet trace
幸雄 村上
 
Swiftでブロックチェーンを実装する
幸雄 村上
 
ゲームの企画書づくりに挑戦
幸雄 村上
 
サーバーレスアーキテクチャで悩んでます
幸雄 村上
 
神経回路網の計算
幸雄 村上
 
Ad

Recently uploaded (8)

PDF
【学会聴講報告】CVPR2025からみるVision最先端トレンド / CVPR2025 report
Sony - Neural Network Libraries
 
PPTX
baserCMS『カスタムコンテンツ』徹底活用術〜あなただけの管理画面を自由自在に〜
Ryuji Egashira
 
PPTX
2025_7_25_吉祥寺_設計ナイト_ADR運用におけるデータ利活用の考え方.pptx
ssuserfcafd1
 
PDF
20250730_QiitaBash_LT登壇資料_PDC_Kurashina.pdf
pdckurashina
 
PDF
TaketoFujikawa_ComicComputing12th_inKumamoto
Matsushita Laboratory
 
PDF
MahiroYoshida_セリフに着目したキャラクタロール推定に関する基礎検討_sigcc12th2025
Matsushita Laboratory
 
PDF
20250726_Devinで変えるエンプラシステム開発の未来
Masaki Yamakawa
 
PDF
20250729_Devin-for-Enterprise
Masaki Yamakawa
 
【学会聴講報告】CVPR2025からみるVision最先端トレンド / CVPR2025 report
Sony - Neural Network Libraries
 
baserCMS『カスタムコンテンツ』徹底活用術〜あなただけの管理画面を自由自在に〜
Ryuji Egashira
 
2025_7_25_吉祥寺_設計ナイト_ADR運用におけるデータ利活用の考え方.pptx
ssuserfcafd1
 
20250730_QiitaBash_LT登壇資料_PDC_Kurashina.pdf
pdckurashina
 
TaketoFujikawa_ComicComputing12th_inKumamoto
Matsushita Laboratory
 
MahiroYoshida_セリフに着目したキャラクタロール推定に関する基礎検討_sigcc12th2025
Matsushita Laboratory
 
20250726_Devinで変えるエンプラシステム開発の未来
Masaki Yamakawa
 
20250729_Devin-for-Enterprise
Masaki Yamakawa
 

日記アプリでCloud kitを使う