diff --git a/LocalNotificationsTutorial.xcodeproj/project.pbxproj b/LocalNotificationsTutorial.xcodeproj/project.pbxproj
index c2c71f7..11355ff 100644
--- a/LocalNotificationsTutorial.xcodeproj/project.pbxproj
+++ b/LocalNotificationsTutorial.xcodeproj/project.pbxproj
@@ -165,7 +165,9 @@
7469E4231A7C8E8200C68120 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0620;
+ LastSwiftMigration = 0720;
+ LastSwiftUpdateCheck = 0720;
+ LastUpgradeCheck = 0720;
TargetAttributes = {
7469E42A1A7C8E8200C68120 = {
CreatedOnToolsVersion = 6.2;
@@ -286,6 +288,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
@@ -351,6 +354,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = LocalNotificationsTutorial/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.lumarow.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@@ -361,6 +365,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = LocalNotificationsTutorial/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.lumarow.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
@@ -379,6 +384,7 @@
);
INFOPLIST_FILE = LocalNotificationsTutorialTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.lumarow.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LocalNotificationsTutorial.app/LocalNotificationsTutorial";
};
@@ -394,6 +400,7 @@
);
INFOPLIST_FILE = LocalNotificationsTutorialTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = "com.lumarow.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LocalNotificationsTutorial.app/LocalNotificationsTutorial";
};
diff --git a/LocalNotificationsTutorial.xcodeproj/project.xcworkspace/xcuserdata/chinnu.xcuserdatad/UserInterfaceState.xcuserstate b/LocalNotificationsTutorial.xcodeproj/project.xcworkspace/xcuserdata/chinnu.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..27c31bb
Binary files /dev/null and b/LocalNotificationsTutorial.xcodeproj/project.xcworkspace/xcuserdata/chinnu.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/LocalNotificationsTutorial.xcodeproj/xcuserdata/chinnu.xcuserdatad/xcschemes/LocalNotificationsTutorial.xcscheme b/LocalNotificationsTutorial.xcodeproj/xcuserdata/chinnu.xcuserdatad/xcschemes/LocalNotificationsTutorial.xcscheme
new file mode 100644
index 0000000..61af1c6
--- /dev/null
+++ b/LocalNotificationsTutorial.xcodeproj/xcuserdata/chinnu.xcuserdatad/xcschemes/LocalNotificationsTutorial.xcscheme
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LocalNotificationsTutorial.xcodeproj/xcuserdata/chinnu.xcuserdatad/xcschemes/xcschememanagement.plist b/LocalNotificationsTutorial.xcodeproj/xcuserdata/chinnu.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..6ea026f
--- /dev/null
+++ b/LocalNotificationsTutorial.xcodeproj/xcuserdata/chinnu.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ LocalNotificationsTutorial.xcscheme
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ 7469E42A1A7C8E8200C68120
+
+ primary
+
+
+ 7469E43F1A7C8E8200C68120
+
+ primary
+
+
+
+
+
diff --git a/LocalNotificationsTutorial/AppDelegate.swift b/LocalNotificationsTutorial/AppDelegate.swift
index 7d8b7bc..5629c79 100644
--- a/LocalNotificationsTutorial/AppDelegate.swift
+++ b/LocalNotificationsTutorial/AppDelegate.swift
@@ -31,19 +31,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
todoCategory.setActions([remindAction, completeAction], forContext: .Default) // UIUserNotificationActionContext.Default (4 actions max)
todoCategory.setActions([completeAction, remindAction], forContext: .Minimal) // UIUserNotificationActionContext.Minimal - for when space is limited (2 actions max)
- application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: .Alert | .Badge | .Sound, categories: NSSet(array: [todoCategory]))) // we're now providing a set containing our category as an argument
+ application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: Set([todoCategory]))) // we're now providing a set containing our category as an argument
return true
}
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
- var item = TodoItem(deadline: notification.fireDate!, title: notification.userInfo!["title"] as String, UUID: notification.userInfo!["UUID"] as String!)
+ let item = TodoItem(deadline: notification.fireDate!, title: notification.userInfo!["title"] as! String, UUID: notification.userInfo!["UUID"] as! String!)
switch (identifier!) {
case "COMPLETE_TODO":
TodoList().removeItem(item)
case "REMIND":
TodoList().scheduleReminderforItem(item)
default: // switch statements must be exhaustive - this condition should never be met
- println("Error: unexpected notification action identifier!")
+ print("Error: unexpected notification action identifier!")
}
completionHandler() // per developer documentation, app will terminate if we fail to call this
}
@@ -57,8 +57,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
func applicationWillResignActive(application: UIApplication) { // fired when user quits the application
- var todoItems: [TodoItem] = TodoList().allItems() // retrieve list of all to-do items
- var overdueItems = todoItems.filter({ (todoItem) -> Bool in
+ let todoItems: [TodoItem] = TodoList().allItems() // retrieve list of all to-do items
+ let overdueItems = todoItems.filter({ (todoItem) -> Bool in
return todoItem.deadline.compare(NSDate()) != .OrderedDescending
})
UIApplication.sharedApplication().applicationIconBadgeNumber = overdueItems.count // set our badge number to number of overdue items
diff --git a/LocalNotificationsTutorial/Info.plist b/LocalNotificationsTutorial/Info.plist
index c112b87..40c6215 100644
--- a/LocalNotificationsTutorial/Info.plist
+++ b/LocalNotificationsTutorial/Info.plist
@@ -7,7 +7,7 @@
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
- com.lumarow.$(PRODUCT_NAME:rfc1034identifier)
+ $(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
diff --git a/LocalNotificationsTutorial/TodoList.swift b/LocalNotificationsTutorial/TodoList.swift
index 5181ab8..1627bbd 100644
--- a/LocalNotificationsTutorial/TodoList.swift
+++ b/LocalNotificationsTutorial/TodoList.swift
@@ -13,8 +13,8 @@ class TodoList {
private let savePath = (NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString).stringByAppendingPathComponent("todo.plist") // ~/todo.plist
func allItems() -> [TodoItem] {
- var items: [AnyObject] = self.rawItems()
- return items.map({TodoItem(deadline: $0["deadline"] as NSDate, title: $0["title"] as String, UUID: $0["UUID"] as String!)}).sorted({
+ let items: [AnyObject] = self.rawItems()
+ return items.map({TodoItem(deadline: $0["deadline"] as! NSDate, title: $0["title"] as! String, UUID: $0["UUID"] as! String!)}).sort({
return ($0.deadline.compare($1.deadline) == .OrderedAscending)
})
}
@@ -22,17 +22,20 @@ class TodoList {
private func rawItems() -> [AnyObject] {
var items: Array = [] // default to an empty array...
if (NSArray(contentsOfFile: self.savePath) != nil) { // ...because init?(contentsOfFile:) will return nil if file doesn't exist yet
- items = NSArray(contentsOfFile: self.savePath)! // load stored items, if available
+ items = NSArray(contentsOfFile: self.savePath)! as Array // load stored items, if available
}
return items
}
func setBadgeNumbers() {
- var notifications = UIApplication.sharedApplication().scheduledLocalNotifications as [UILocalNotification] // all scheduled notifications
- var todoItems: [TodoItem] = self.allItems()
+ guard let notifications = UIApplication.sharedApplication().scheduledLocalNotifications else {
+ return
+ }
+
+ let todoItems: [TodoItem] = self.allItems()
for notification in notifications {
- var overdueItems = todoItems.filter({ (todoItem) -> Bool in // array of to-do items...
+ let _ = todoItems.filter({ (todoItem) -> Bool in // array of to-do items...
return (todoItem.deadline.compare(notification.fireDate!) != .OrderedDescending) // ...where item deadline is before or on notification fire date
})
UIApplication.sharedApplication().cancelLocalNotification(notification) // cancel old notification
@@ -48,7 +51,7 @@ class TodoList {
(items as NSArray).writeToFile(self.savePath, atomically: true) // items casted as NSArray because writeToFile:atomically: is not available on Swift arrays
// create a corresponding local notification
- var notification = UILocalNotification()
+ let notification = UILocalNotification()
notification.alertBody = "Todo Item \"\(item.title)\" Is Overdue" // text that will be displayed in the notification
notification.alertAction = "open" // text that is displayed after "slide to..." on the lock screen - defaults to "slide to view"
notification.fireDate = item.deadline // todo item due date (when notification will be fired)
@@ -62,7 +65,7 @@ class TodoList {
}
func scheduleReminderforItem(item: TodoItem) {
- var notification = UILocalNotification() // create a new reminder notification
+ let notification = UILocalNotification() // create a new reminder notification
notification.alertBody = "Reminder: Todo Item \"\(item.title)\" Is Overdue" // text that will be displayed in the notification
notification.alertAction = "open" // text that is displayed after "slide to..." on the lock screen - defaults to "slide to view"
notification.fireDate = NSDate().dateByAddingTimeInterval(30 * 60) // 30 minutes from current time
@@ -74,15 +77,18 @@ class TodoList {
}
func removeItem(item: TodoItem) {
- for notification in UIApplication.sharedApplication().scheduledLocalNotifications as [UILocalNotification] { // loop through notifications...
- if (notification.userInfo!["UUID"] as String == item.UUID) { // ...and cancel the notification that corresponds to this TodoItem instance (matched by UUID)
+ guard let notifications = UIApplication.sharedApplication().scheduledLocalNotifications else {
+ return
+ }
+ for notification in notifications { // loop through notifications...
+ if (notification.userInfo!["UUID"] as! String == item.UUID) { // ...and cancel the notification that corresponds to this TodoItem instance (matched by UUID)
UIApplication.sharedApplication().cancelLocalNotification(notification) // there should be a maximum of one match on UUID
break
}
}
var items: [AnyObject] = self.rawItems()
- items = items.filter {($0["UUID"] as String? != item.UUID)} // remove item that matches UUID
+ items = items.filter {($0["UUID"] as! String? != item.UUID)} // remove item that matches UUID
(items as NSArray).writeToFile(self.savePath, atomically: true) // overwrite todo.plist with new array
self.setBadgeNumbers()
diff --git a/LocalNotificationsTutorial/TodoSchedulingViewController.swift b/LocalNotificationsTutorial/TodoSchedulingViewController.swift
index bd4bede..9e362eb 100644
--- a/LocalNotificationsTutorial/TodoSchedulingViewController.swift
+++ b/LocalNotificationsTutorial/TodoSchedulingViewController.swift
@@ -13,14 +13,15 @@ class TodoSchedulingViewController: UIViewController {
@IBOutlet weak var deadlinePicker: UIDatePicker!
@IBAction func savePressed(sender: UIButton) {
- if (countElements(titleField.text.stringByTrimmingCharactersInSet(.whitespaceCharacterSet())) > 0) { // only save if titlefield text contains non-whitespace characters
- let todoItem = TodoItem(deadline: deadlinePicker.date, title: titleField.text, UUID: NSUUID().UUIDString)
- TodoList().addItem(todoItem) // schedule a local notification to persist this item
- self.navigationController?.popToRootViewControllerAnimated(true) // return to list view where the newly created item will be displayed
- } else { // text field was blank or contained only whitespace
- var alertController = UIAlertController(title: "Error", message: "You must give this todo item a title", preferredStyle: .Alert)
+ guard let text = titleField.text where text.stringByTrimmingCharactersInSet(.whitespaceCharacterSet()).characters.count > 0 else {
+ // text field was blank or contained only whitespace
+ let alertController = UIAlertController(title: "Error", message: "You must give this todo item a title", preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .Cancel, handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
+ return
}
+ let todoItem = TodoItem(deadline: deadlinePicker.date, title: text, UUID: NSUUID().UUIDString)
+ TodoList().addItem(todoItem) // schedule a local notification to persist this item
+ self.navigationController?.popToRootViewControllerAnimated(true) // return to list view where the newly created item will be displayed
}
-}
\ No newline at end of file
+}
diff --git a/LocalNotificationsTutorial/TodoTableViewController.swift b/LocalNotificationsTutorial/TodoTableViewController.swift
index 448750a..74a50bc 100644
--- a/LocalNotificationsTutorial/TodoTableViewController.swift
+++ b/LocalNotificationsTutorial/TodoTableViewController.swift
@@ -59,14 +59,14 @@ class TodoTableViewController: UITableViewController {
return true // all cells are editable
}
- override func tableView(tableView: UITableView, titleForDeleteConfirmationButtonForRowAtIndexPath indexPath: NSIndexPath) -> String! {
+ override func tableView(tableView: UITableView, titleForDeleteConfirmationButtonForRowAtIndexPath indexPath: NSIndexPath) -> String? {
return "Complete" // alternate text for delete button
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete { // the only editing style we'll support
// Delete the row from the data source
- var item = todoItems.removeAtIndex(indexPath.row) // remove TodoItem from notifications array, assign removed item to 'item'
+ let item = todoItems.removeAtIndex(indexPath.row) // remove TodoItem from notifications array, assign removed item to 'item'
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
TodoList().removeItem(item) // delete backing property list entry and unschedule local notification (if it still exists)
self.navigationItem.rightBarButtonItem!.enabled = true // we definitely have under 64 notifications scheduled now, make sure 'add' button is enabled
diff --git a/LocalNotificationsTutorialTests/Info.plist b/LocalNotificationsTutorialTests/Info.plist
index 749b5c4..ba72822 100644
--- a/LocalNotificationsTutorialTests/Info.plist
+++ b/LocalNotificationsTutorialTests/Info.plist
@@ -7,7 +7,7 @@
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
- com.lumarow.$(PRODUCT_NAME:rfc1034identifier)
+ $(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName