photoLibrary에 접근하여 사진을 불러오고 사진의 이름과 간단한 설명을 적고 cloudKit 에 저장한다. 그리고 클라우드에 저장된 내용을 불러오고, 수정하고, 삭제 할 수 있는 예제를 만들어 본다.
추가로 다른 기기에서 cloudkit에 새로운 사진을 저장했을때 단말에 push notificaton 이 오는 subscription 도 함께 만들어본다.
stroybord 에 textfield, textView, imageView 그리고 사진호출, 저장, 불러오기, 수정, 삭제 를 수행하는 5개의 버튼 을 만들고 controller에 연결하자.
프로젝트의 capabilities 탭에서 아이클라우드를 On 으로 하고 CloudKit 사용을 체크하는 것도 잊지 말자.
아래는 viewController.swift 파일의 전체 내용이다.
import UIKit
import CloudKit
import MobileCoreServices
class ViewController: UIViewController , UIImagePickerControllerDelegate, UINavigationControllerDelegate{
let container = CKContainer.defaultContainer()
var publicDatabase : CKDatabase?
var currentRecord : CKRecord?
var photoURL : NSURL?
@IBOutlet var addressField: UITextField!
@IBOutlet var commentsField: UITextView!
@IBOutlet var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
publicDatabase = container.publicCloudDatabase
let predicate = NSPredicate(format: "TRUEPREDICATE")
let subscription = CKSubscription(recordType: "Houses", predicate: predicate, options: .FiresOnRecordCreation)
let notificationInfo = CKNotificationInfo()
notificationInfo.alertBody = "A new houses was added"
notificationInfo.shouldBadge = true
subscription.notificationInfo = notificationInfo
publicDatabase?.saveSubscription(subscription, completionHandler: ({returnRecord , error in
if let err = error {
print("subscription failed %@", err.localizedDescription)
} else {
dispatch_async(dispatch_get_main_queue()) {
self.notifyUser("success", message: "subscription set up successfully")
}
}
}))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
addressField.endEditing(true)
commentsField.endEditing(true)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
self.dismissViewControllerAnimated(true, completion: nil)
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
imageView.image = image
photoURL = saveImageToFile(image)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
self.dismissViewControllerAnimated(true, completion: nil)
}
func saveImageToFile(image : UIImage) -> NSURL {
let filemgr = NSFileManager.defaultManager()
let dirPaths = filemgr.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let filePath = dirPaths[0].URLByAppendingPathComponent("currentImage.png").path
UIImageJPEGRepresentation(image, 0.5)!.writeToFile(filePath!, atomically : true)
return NSURL.fileURLWithPath(filePath!)
}
func notifyUser(title : String, message : String) -> Void {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
let cancelAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alert.addAction(cancelAction)
self.presentViewController(alert, animated: true, completion: nil)
}
func fetchRecord(recordID : CKRecordID) -> Void {
publicDatabase = container.publicCloudDatabase
publicDatabase?.fetchRecordWithID(recordID, completionHandler: ({record, error in
if let err = error {
dispatch_async(dispatch_get_main_queue()) {
self.notifyUser("fetch errer", message: err.localizedDescription)
}
} else {
dispatch_async(dispatch_get_main_queue()) {
self.currentRecord = record
self.addressField.text = record!.objectForKey("address") as? String
self.commentsField.text = record!.objectForKey("comment") as? String
let photo = record!.objectForKey("photo") as! CKAsset
let image = UIImage(contentsOfFile: photo.fileURL.path!)
self.imageView.image = image
self.photoURL = self.saveImageToFile(image!)
}
}
}))
}
@IBAction func saveRecord(sender: AnyObject) {
if(photoURL == nil) {
notifyUser("No Photo",message: "use the photo option to choose a photo for the record")
return
}
let asset = CKAsset(fileURL: photoURL!)
let myRecord = CKRecord(recordType: "Houses")
myRecord.setObject(addressField.text, forKey: "address")
myRecord.setObject(commentsField.text, forKey: "comment")
myRecord.setObject(asset, forKey: "photo")
publicDatabase!.saveRecord(myRecord, completionHandler: ({returnRecord, error in
if let err = error {
self.notifyUser("Save Error",message: err.localizedDescription)
} else {
dispatch_async(dispatch_get_main_queue()) {
self.notifyUser("Success", message : "Record saved successfully")
}
self.currentRecord = myRecord
}
}))
}
@IBAction func performQuery(sender: AnyObject) {
let predicate = NSPredicate(format: "address = %@", addressField.text!)
let query = CKQuery(recordType: "Houses", predicate: predicate)
publicDatabase?.performQuery(query, inZoneWithID: nil, completionHandler: ({results, error in
if(error != nil) {
dispatch_async(dispatch_get_main_queue()){
self.notifyUser("Cloud Access Error", message: error!.localizedDescription)
}
} else {
if results!.count > 0 {
let record = results![0]
self.currentRecord = record
dispatch_async(dispatch_get_main_queue()) {
self.commentsField.text = record.objectForKey("comment") as! String
let photo = record.objectForKey("photo") as! CKAsset
let image = UIImage(contentsOfFile: photo.fileURL.path!)
self.imageView.image = image
self.photoURL = self.saveImageToFile(image!)
}
}else {
dispatch_async(dispatch_get_main_queue()) {
self.notifyUser("No match found", message: "no record matching the address was found")
}
}
}
}))
}
@IBAction func selectPhoto(sender: AnyObject) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
imagePicker.mediaTypes = [kUTTypeImage as String]
self.presentViewController(imagePicker, animated: true, completion: nil)
}
@IBAction func updateRecord(sender: AnyObject) {
if let record = currentRecord {
let asset = CKAsset(fileURL: photoURL!)
record.setObject(addressField.text, forKey: "address")
record.setObject(commentsField.text, forKey: "comment")
record.setObject(asset, forKey: "photo")
publicDatabase!.saveRecord(record, completionHandler: ({returnRecord, error in
if let err = error {
dispatch_async(dispatch_get_main_queue()) {
self.notifyUser("Update Error", message: err.localizedDescription)
}
}else {
dispatch_async(dispatch_get_main_queue()) {
self.notifyUser("success", message: "record updated successfully")
}
}
}))
}else {
notifyUser("no record selected", message: "use query to select a record to update")
}
}
@IBAction func deleteRecord(sender: AnyObject) {
if let record = currentRecord {
publicDatabase?.deleteRecordWithID(record.recordID, completionHandler: ({returnRecord, error in
if let err = error {
dispatch_async(dispatch_get_main_queue()) {
self.notifyUser("delete error", message: err.localizedDescription)
}
} else {
dispatch_async(dispatch_get_main_queue()) {
self.notifyUser("success", message: "record deleted successfully")
}
}
}))
} else {
notifyUser("no record selected", message: "use query to select a record to delete")
}
}
}
아래는 AppDelegate.swift 파일의 전체 소스이다.
import UIKit
import CloudKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let settings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
if let options : NSDictionary = launchOptions {
let remoteNotification = options.objectForKey(UIApplicationLaunchOptionsRemoteNotificationKey) as? NSDictionary
if let notification = remoteNotification {
self.application(application, didReceiveRemoteNotification: notification as [NSObject : AnyObject])
}
}
return true
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
let viewController : ViewController = self.window?.rootViewController as! ViewController
let notification : CKNotification = CKNotification(fromRemoteNotificationDictionary : userInfo as! [String : NSObject])
if(notification.notificationType == CKNotificationType.Query) {
let queryNotification = notification as! CKQueryNotification
let recordID = queryNotification.recordID
viewController.fetchRecord(recordID!)
}
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
위의 코드는 "핵심만 골라 배우는 ios 9 프로그래밍 (닐스미스 지음/ 황반석 옮김)" 에 있는 예제를 참고하여 작성하였습니다.
'programming language > swift' 카테고리의 다른 글
ios 로컬알림 및 앱 background 사용 in swift (0) | 2016.09.07 |
---|---|
ios iAd, google Admob 사용하기 in swift (0) | 2016.09.07 |
ios icloud key-value storage 사용 in swift (0) | 2016.09.03 |
ios icloud 저장소 사용하기 in swift (0) | 2016.09.03 |
ios 터치 아이디 인증 구현 in swift (0) | 2016.08.31 |