iOS 9 and iOS 10 CoreData simultaneously - ios

I have a question about Swift 3 releted with Core Data. I am developing an App in Swift with Xcode 8, and I need to support iOS 9 and iOS10. The problem is that I don't know how to get the AppDelegate and the Context (to use for store and get data from my Entities). I think my code should be something like this:
#if avaliable(iOS10,*)
{
// iOS 10 code
} else
{
// iOS 9 code
}
But I don't know what to do.
Any idea?
(A small help in correction would be appreciated)

# Code in Swift 3 for Core Data for both iOS 9 and iOS 10 #
Since you want the core data code for both iOS 9 and iOS 10 then you don't have to use NSPersistentContainer as it not supported in iOS 9, so you have to use old method instead
If at the time of project creation you haven't included core data and later you want to include it, follow the following steps :-
Step 1. Go to Build Phases -> Link Binary with Library -> click on + sign -> Add CoreData.framework
Step 2. Now got to file -> New File -> select Data Model.
Step 3. Now you need to write some code inside AppDelegate.swift to get set go :-
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
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 invalidate graphics rendering callbacks. 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 active 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) {
self.saveContext()
}
// MARK: - Core Data stack
lazy var applicationDocumentsDirectory: NSURL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "hacker.at.work.mTirgger" in the application's documents Application Support directory.
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1] as NSURL
}()
lazy var managedObjectModel: NSManagedObjectModel = {
// The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
let modelURL = Bundle.main.url(forResource: "Model", withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject?
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
abort()
}
}
}
}
That's all your Core Data is ready for both iOS 9 and iOS 10 in Swift 3. Enjoy !!!

If you want to support iOS9 then the best bet is not to use any new iOS10 stuff.
Stick with the iOS9 API for now, and in the future when you eventually drop iOS9 support you can refactor your code to use the newer methods then.
edit: Just to be clear, all the iOS9 code will run fine on iOS10. You don't need to do anything special there, it is all backwards compatible.

CoreData for iOS9 and iOS10 simultaneously
For who you may need it:
This is an unmodified Master-Detail App template from the latest Xcode7 (for iOS9) release of May 2016. I have updated it with the current latest Xcode (Version 8.2.1)
With this template you can develope an application that uses CoreData compatible with iOS9 and iOS10, at least for now (May 2017)
AppDelegate.swift
//
// AppDelegate.swift
// trash
//
// Created by Markus on 22/05/17.
// Copyright © 2017 Markus. All rights reserved.
//
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let splitViewController = self.window!.rootViewController as! UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
splitViewController.delegate = self
let masterNavigationController = splitViewController.viewControllers[0] as! UINavigationController
let controller = masterNavigationController.topViewController as! MasterViewController
controller.managedObjectContext = self.managedObjectContext
return true
}
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:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
// MARK: - Split view
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
if topAsDetailController.detailItem == nil {
// Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
return true
}
return false
}
// MARK: - Core Data stack
lazy var applicationDocumentsDirectory: URL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "com.senbei.trash" in the application's documents Application Support directory.
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1]
}()
lazy var managedObjectModel: NSManagedObjectModel = {
// The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
let modelURL = Bundle.main.url(forResource: "trash", withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject?
dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject?
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
abort()
}
}
}
}
MasterViewController.swift
//
// MasterViewController.swift
// trash
//
// Created by Markus on 22/05/17.
// Copyright © 2017 Markus. All rights reserved.
//
import UIKit
import CoreData
class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate {
var detailViewController: DetailViewController? = nil
var managedObjectContext: NSManagedObjectContext? = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(insertNewObject(_:)))
self.navigationItem.rightBarButtonItem = addButton
if let split = self.splitViewController {
let controllers = split.viewControllers
self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
}
}
override func viewWillAppear(_ animated: Bool) {
self.clearsSelectionOnViewWillAppear = self.splitViewController!.isCollapsed
super.viewWillAppear(animated)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func insertNewObject(_ sender: AnyObject) {
let context = self.fetchedResultsController.managedObjectContext
let entity = self.fetchedResultsController.fetchRequest.entity!
let newManagedObject = NSEntityDescription.insertNewObject(forEntityName: entity.name!, into: context)
// If appropriate, configure the new managed object.
// Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
newManagedObject.setValue(Date(), forKey: "timeStamp")
// Save the context.
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//print("Unresolved error \(error), \(error.userInfo)")
abort()
}
}
// MARK: - Segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let object = self.fetchedResultsController.object(at: indexPath)
let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
// MARK: - Table View
override func numberOfSections(in tableView: UITableView) -> Int {
return self.fetchedResultsController.sections?.count ?? 0
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = self.fetchedResultsController.sections![section]
return sectionInfo.numberOfObjects
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let object = self.fetchedResultsController.object(at: indexPath) as! NSManagedObject
self.configureCell(cell, withObject: object)
return cell
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let context = self.fetchedResultsController.managedObjectContext
context.delete(self.fetchedResultsController.object(at: indexPath) as! NSManagedObject)
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//print("Unresolved error \(error), \(error.userInfo)")
abort()
}
}
}
func configureCell(_ cell: UITableViewCell, withObject object: NSManagedObject) {
//cell.textLabel!.text = object.value(forKey: "timeStamp")!.description
cell.textLabel!.text = (object.value(forKey: "timeStamp")! as AnyObject).description
}
// MARK: - Fetched results controller
//var fetchedResultsController: NSFetchedResultsController {
var fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult> {
if _fetchedResultsController != nil {
return _fetchedResultsController!
}
//let fetchRequest = NSFetchRequest()
//let fetchRequest = NSFetchRequest<Event>(entityName: "Event") //another alternative
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Event")
// Edit the entity name as appropriate.
let entity = NSEntityDescription.entity(forEntityName: "Event", in: self.managedObjectContext!)
fetchRequest.entity = entity
// Set the batch size to a suitable number.
fetchRequest.fetchBatchSize = 20
// Edit the sort key as appropriate.
let sortDescriptor = NSSortDescriptor(key: "timeStamp", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath: nil, cacheName: "Master")
aFetchedResultsController.delegate = self
_fetchedResultsController = aFetchedResultsController
do {
try _fetchedResultsController!.performFetch()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//print("Unresolved error \(error), \(error.userInfo)")
abort()
}
return _fetchedResultsController!
}
//var _fetchedResultsController: NSFetchedResultsController? = nil
var _fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>?
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
self.tableView.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
switch type {
case .insert:
self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
case .delete:
self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
default:
return
}
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
tableView.insertRows(at: [newIndexPath!], with: .fade)
case .delete:
tableView.deleteRows(at: [indexPath!], with: .fade)
case .update:
self.configureCell(tableView.cellForRow(at: indexPath!)!, withObject: anObject as! NSManagedObject)
case .move:
tableView.moveRow(at: indexPath!, to: newIndexPath!)
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
self.tableView.endUpdates()
}
/*
// Implementing the above methods to update the table view in response to individual changes may have performance implications if a large number of changes are made simultaneously. If this proves to be an issue, you can instead just implement controllerDidChangeContent: which notifies the delegate that all section and object changes have been processed.
func controllerDidChangeContent(controller: NSFetchedResultsController) {
// In the simplest, most efficient, case, reload the table view.
self.tableView.reloadData()
}
*/
}
DetailViewController.swift
//
// DetailViewController.swift
// trash
//
// Created by Markus on 22/05/17.
// Copyright © 2017 Markus. All rights reserved.
//
import UIKit
class DetailViewController: UIViewController {
#IBOutlet weak var detailDescriptionLabel: UILabel!
var detailItem: AnyObject? {
didSet {
// Update the view.
self.configureView()
}
}
func configureView() {
// Update the user interface for the detail item.
if let detail = self.detailItem {
if let label = self.detailDescriptionLabel {
//label.text = detail.value(forKey: "timeStamp")!.description
label.text = (detail.value(forKey: "timeStamp")! as AnyObject).description
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.configureView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Data model is the original from template, as well as storyboard. Both there are not modified.

You can use the new API and get the benefits out of it by doing something like this:
var coreDataManager: CoreDataManagerProtocol!
#if available(iOS10,*)
{
coreDataManager = CoreDataManagerNewStack()
} else
{
coreDataManager = CoreDataManagerOldStack()
}
and then you implement the new CoreData with the new stack into a class:
class CoreDataManagerNewStack: CoreDataManagerProtocol {
var container: NSPersistentContainer
// etc
}
and the old one with the code paster above with the whole code to generate the stack
class CoreDataManagerOldStack: CoreDataManagerProtocol {
lazy var managedObjectContext: NSManagedObjectContext = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// etc
}

Related

Swift 4 error: [<UIViewController 0x7ff66ec0ef30> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key emailField

I've tried to link a couple objects in a xib file to my code for the View Controller through IBOutlets, but when I run the code I get the error
'NSUnknownKeyException', reason: '[< UIViewController 0x7f94dfc0f110>
setValue:forUndefinedKey:]: this class is not key value
coding-compliant for the key emailField.'
I've tried deleting all the outlets and reassigning them, and checking that all the connected objects only have one respective outlet each. Also, when unlinking one element, its error goes away, but the same format of the error for a different linked element appears.
import UIKit
import FirebaseAuth
import Firebase
class SignUpViewController: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var usernameField: UITextField!
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func toSignUp(_ sender: Any) {
Auth.auth().createUser(withEmail: emailField.text!, password: passField.text!, completion: nil)
Firestore.firestore().collection("users").document(usernameField.text!).setData([
"name" : nameField.text!,
"username" : usernameField.text!,
"email" : emailField.text!
])
TransitionModel().transitionModel(viewControllerName: "LoginViewController", newView: LoginViewController().view!, viewControllerCurrent: self)
}
#IBAction func toLogin(_ sender: Any) {
TransitionModel().transitionModel(viewControllerName: "LoginViewController", newView: LoginViewController().view!, viewControllerCurrent: self)
}
}
import UIKit
import Firebase
class LoginViewController: UIViewController {
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func toLogin(_ sender: Any) {
}
}
import UIKit
import CoreData
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = UIViewController(nibName: "SignUpViewController", bundle: nil)
self.window?.makeKeyAndVisible()
return true
}
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 invalidate graphics rendering callbacks. 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 active 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:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "Pono_Beta")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
Thank you in advance for responses.
This happens when you just copy paste view controller.
Goto Storyboard, Select View Controller Open connection inspector and remove connections for emailField and create new Outlet

Save user input data of UITableView

There is an option in my app to add new excercises (via user input), i've managed to set the alert and add feature, but I can't save the data added and let it be persistent after closure and that.
//
// ExcerciseListViewController.swift
// OneRepMax
//
// Created by Mauro Garcia on 17/01/2019.
// Copyright © 2019 Mauro Garcia. All rights reserved.
//
import Foundation
import UIKit
import CoreData
class ExcerciseListViewController: UIViewController, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
title = "Excercises"
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
// This view controller itself will provide the delegate methods and row data for the table view.
tableView.delegate = self
tableView.dataSource = self
}
#IBOutlet weak var tableView: UITableView!
// Add a new excercise
#IBAction func addExcercise(_ sender: UIBarButtonItem) {
let alert = UIAlertController(title: "New Excercise", message: "Add a new excercise", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) { [unowned self] action in
guard let textField = alert.textFields?.first,
let nameToSave = textField.text
else {
return
}
print(nameToSave)
self.excercises.append(nameToSave)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
present(alert, animated: true)
}
var excercises: [String] = []
}
// MARK: - UITableViewDataSource
extension ExcerciseListViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
print(excercises.count)
return excercises.count
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
let cell =
tableView.dequeueReusableCell(withIdentifier: "Cell",
for: indexPath)
cell.textLabel?.text = excercises[indexPath.row]
return cell
}
// What happens when user touch an excercise
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let excerciseChosen = "\(excercises[indexPath.row])"
goBackToOneButtonTapped((Any).self)
excUserChose = excerciseChosen
print(excUserChose)
print("You tapped cell number \(indexPath.row).")
print(excerciseChosen)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "changeText"), object: nil)
}
func goBackToOneButtonTapped(_ sender: Any) {
performSegue(withIdentifier: "unwindToViewController", sender: self)
}
}
// TODO: save user input
In my AppDelegate.swift
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "OneRepMax")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
I want to -when the user press "Save"- to save the data to be accesible after.
I've tried to implement CoreData but I have failed trying. Don't know what I'm doing wrong.
EDIT:
Code for adding and saving input
var excercisess: [NSManagedObject] = []
#IBAction func addExcercise(_ sender: UIBarButtonItem) {
let alert = UIAlertController(title: "New Excercise", message: "Add a new excercise", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) { [unowned self] action in
guard let textField = alert.textFields?.first,
let nameToSave = textField.text
else {
return
}
self.save(name: nameToSave)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
present(alert, animated: true)
}
func save(name: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
/*1.
Before you can save or retrieve anything from your Core Data store, you first need to get your hands on an NSManagedObjectContext. You can consider a managed object context as an in-memory “scratchpad” for working with managed objects.
Think of saving a new managed object to Core Data as a two-step process: first, you insert a new managed object into a managed object context; then, after you’re happy with your shiny new managed object, you “commit” the changes in your managed object context to save it to disk.
Xcode has already generated a managed object context as part of the new project’s template. Remember, this only happens if you check the Use Core Data checkbox at the beginning. This default managed object context lives as a property of the NSPersistentContainer in the application delegate. To access it, you first get a reference to the app delegate.
*/
let managedContext = appDelegate.persistentContainer.viewContext
/*
An NSEntityDescription object is associated with a specific class instance
Class
NSEntityDescription
A description of an entity in Core Data.
Retrieving an Entity with a Given Name here person
*/
let entity = NSEntityDescription.entity(forEntityName: "Excercise", in: managedContext)!
/*
Initializes a managed object and inserts it into the specified managed object context.
init(entity: NSEntityDescription,
insertInto context: NSManagedObjectContext?)
*/
let excercises = NSManagedObject(entity: entity, insertInto: managedContext)
//we can simply create person object this way also.
// let excercise = Excercise(context: managedContext)
/*
With an NSManagedObject in hand, you set the name attribute using key-value coding. You must spell the KVC key (name in this case) exactly as it appears in your Data Model
*/
excercises.setValue(name, forKeyPath: "name")
/*
You commit your changes to person and save to disk by calling save on the managed object context. Note save can throw an error, which is why you call it using the try keyword within a do-catch block. Finally, insert the new managed object into the people array so it shows up when the table view reloads.
*/
do {
try managedContext.save()
excercisess.append(excercises)
tableView.reloadData()
print("SAVED")
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
And the code for fetching:
func fetchAllExcercises(){
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
/*Before you can do anything with Core Data, you need a managed object context. */
let managedContext = appDelegate.persistentContainer.viewContext
/*As the name suggests, NSFetchRequest is the class responsible for fetching from Core Data.
Initializing a fetch request with init(entityName:), fetches all objects of a particular entity. This is what you do here to fetch all Person entities.
*/
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Excercise")
/*You hand the fetch request over to the managed object context to do the heavy lifting. fetch(_:) returns an array of managed objects meeting the criteria specified by the fetch request.*/
do {
excercisess = try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
There are several things that you still need once you have the xcdatamodeld file set up.
Your array should be an array of your CoreData entity.
var exercises = [Exercise]()
You need to create an instance of the managed object context.
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
Then you will need to use that instance to create new objects in the array, save the new objects and fetch them. Have a go at finding out how to create those functions (Youtube, web articles) and then see if you still have questions.

Data not persistent in Core Data when app re-launches

I am using Core Data for the first time in a project made in XCode 8, swift 3. I have used background context (calling container.performBackgroundTask block..) to save the data and main context to fetch the data. When my app re-launches, the data I saved in the private background context is deleted.
Please tell me where I went wrong !!!
Here I call CoreDataManager class save context method in applicationDidEnterBackground and applicationWillTerminate methods of AppDelegate class:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
lazy var coreDataMgrInstance = CoreDataManager.sharedInstance
func applicationDidEnterBackground(_ application: UIApplication) {
coreDataMgrInstance.saveContext()
}
func applicationWillTerminate(_ application: UIApplication) {
coreDataMgrInstance.saveContext()
}}
Here is my Singleton class CoreDataManager to initiate NSpersistentContainer
class CoreDataManager: NSObject {
class var sharedInstance: CoreDataManager {
struct Singleton {
static let instance = CoreDataManager()
}
return Singleton.instance
}
private override init() {
super.init()
}
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "E_CareV2")
let description = NSPersistentStoreDescription() // enable auto lightweight migratn
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions = [description]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
return container
}()
func saveContext(){
print("saveContext")
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Failure to save main context \(nserror), \(nserror.userInfo)")
}
}}
Now this is the class where I save and fetch the data from Core Data
class SenderViewController: UIViewController {
var persistentContainer: NSPersistentContainer!
override func viewDidLoad() {
super.viewDidLoad()
persistentContainer = CoreDataManager.sharedInstance.persistentContainer
let results = self.fetchPersistentData(entityName: "School", withPredicate: nil)
print("results \n \(results)")
}
#IBAction func enterPressed(_ sender: Any) {
self.persistentContainer.performBackgroundTask({ (backgroundContext) in
backgroundContext.mergePolicy = NSMergePolicy.mergeByPropertyStoreTrump
let schoolentity = NSEntityDescription.insertNewObject(forEntityName: "School", into: backgroundContext) as! School
schoolentity.schoolName = "ABC"
schoolentity.schoolWebSite = "http://anywebsite.com/"
do {
try backgroundContext.save()
} catch {
fatalError("Failure to save background context: \(error)")
}
})
}
func fetchPersistentData(entityName: String?, withPredicate: NSPredicate?) -> [NSManagedObject]{
let context = self.persistentContainer.viewContext
let request: NSFetchRequest<School> = School.fetchRequest()
let newentity = NSEntityDescription.entity(forEntityName: entityName!, in: context)
request.entity = newentity
request.returnsObjectsAsFaults = false
do {
let searchResults = try context.fetch(request) as [NSManagedObject]
return searchResults
} catch {
print("Error with request: \(error)")
}
return []
}
Actually the lightweight migrations are enabled by default as you can see on the screenshot
So you can safely delete these lines:
let description = NSPersistentStoreDescription() // enable auto lightweight migratn
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions = [description]
After that everything should work.
There are two ways to use NSPersistentContainer - the simple way and the correct way. You are mixing them which is leading to problems. Apple is a little inconsistent on this in its documentation so it is understandable that you are confused.
The Simple Way - The simple way is only use the viewContext both for reading and for writing and only from the main thread. There are never any conflicts because core-data is assessed via a single thread. The problem with this approach is that you can't run anything in a background thread. So if you are importing a lot of data the UI will freeze. If you have a super simple app (a small task list?) this will work OK, but not something that I would ever recommend for a serious app. It is OK for a testing app for a beginner to learn core-data.
The Correct Way - the correct way is to NEVER write to the viewContext EVER. Apple documents this in NSPersistentContainer documentation (but also in its template creates a save method for the viewContext?!). In this setup all writes to core data MUST go through performBackgroundTask and you have to call save on that context before the end of the block. You also need an operation queue to make sure that there are no merge conflicts see NSPersistentContainer concurrency for saving to core data. This setup is a lot harder to do correctly. Objects from performBackgroundTask contexts cannot leave the block and objects from the viewContext cannot be used in the block. The complier doesn't help you with this so it is something that you always need to watch out for.
Your problem is mergePolicy. mergePolicy is evil. If you have conflicts in core-data you have already done something wrong and any merge policy will lose data. In the simple setup there are no conflicts because it is all on one thread. In the correct setup there is no conflicts because of the queue you created when using performBackgroundTask. The problem is that if you use BOTH performBackgroundTask and write the the viewContext you can get conflicts and you will lose data. Personally, I think it is better to have no mergePolicy and crash then to silently lose data.
I figured out what causes my data not to be persistent in Core Data. It was these below 4 lines of code that I put in persistentContainer definition for enabling LIGHTWEIGHT MIGRATION of models:
let description = NSPersistentStoreDescription() // enable auto lightweight migratn
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions = [description]
When I deleted these lines, I became able to retain my data when the app re-launches.
I had written the above lines to enable Lightweight Migration to my model, but I did not change my model or created new version of the model, making the Core Data unable to search the destination model in NSBundle and thus unable to infer the Mapping.
I am still not sure, how that would delete my data but I will keep trying to figure this out too and comment when I get success in it... :)

Unable to share data using Shared App Groups for Today Extension

I am trying to create a today extension that displays data from the parent app by using a shared app group container, and then adding the persistent store to a context.
Add Today Extension Target
Turn on app groups for parent app and extension and select same group
Add Today Extension as Target Membership for Data model and entities
Add Persistent store to context
Fetch Objects
I get no errors but the extension does not seem to be fetching any results. Does anybody have any suggestions where I may be going wrong ?
Heres what I am doing in the extension TodayViewController
class TodayViewController: UIViewController, NCWidgetProviding {
var context: NSManagedObjectContext!
#IBOutlet weak var table: UITableView!
var objectsArray = [Objects]()
override func viewDidLoad() {
super.viewDidLoad()
let fileManager = NSFileManager.defaultManager()
var containerPath = fileManager.containerURLForSecurityApplicationGroupIdentifier("group.com.Company.AppName")
containerPath = containerPath?.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
let modelURL = NSBundle.mainBundle().URLForResource("AppName", withExtension: "momd")
let model = NSManagedObjectModel(contentsOfURL: modelURL!)
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: model!)
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: containerPath, options: nil)
} catch {
print("yellow")
}
context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
context.persistentStoreCoordinator = coordinator
let moc = context
let request = NSFetchRequest(entityName: "Objects")
request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: true)]
do {
try
self.objectsArray = moc.executeFetchRequest(request) as! [Objects]
print ("objects count \(objectsArray.count)")
} catch {
// failure
print("Fetch failed")
}
self.table.reloadData()
}
// MARK: - Table view data source
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
//return sectionsArray.count
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.objectsArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = table.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell!
cell.textLabel!.textColor = UIColor.whiteColor()
cell.textLabel!.text = self.objectsArray[indexPath.row].title
return cell
}
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) {
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResult.Failed
// If there's no update required, use NCUpdateResult.NoData
// If there's an update, use NCUpdateResult.NewData
completionHandler(NCUpdateResult.NewData)
}
}
In Apple's App Extension Programming Guide --Sharing Data with Your Containing App
Even though an app extension bundle is nested within its containing app’s bundle, the running app extension and containing app have no direct access to each other’s containers.
So they wouldn't be able to share data directly,even if you
Add Today Extension as Target Membership for Data model and entities
Instead,they communicated with each other by shared container(App groups) indirectly,which you had already setup in step 2.
So the solution is :
In your Contraning App,create the sql data model in your shared container ,insert data in this database.Adjust your code in todayExtension ,and fetch data.
Or Using NSUserDefaults to share data instead.
like this:
// Create and share access to an NSUserDefaults object
NSUserDefaults *mySharedDefaults = [[NSUserDefaults alloc] initWithSuiteName: #"com.example.domain.MyShareExtension"];
// Use the shared user defaults object to update the user's account
[mySharedDefaults setObject:theAccountName forKey:#"lastAccountName"];

iOS Simulator Stuck on Launch Page after Update to XCode 7

I updated to Xcode 7 from Xcode 6 and updated my code to swift 2.0 from swift 1.2. When I run the project, there are no compile time errors, just warnings, and the build is successful. The problem I am having is that the main.storyboard does not load. By this i mean all that is shown in the simulator is the launch page and the initial view controller is never put into the hierarchy (i believe). When i updated my code to swift 2.0, i manually updated the AppDelegate which i did not expect and is why i think there may be something wrong with the file. I also get a Thread 1: EXC_BAD_ACCESS (code=2 ...) error which i understand to be a recursion error but don't understand how to resolve the issue.
Things I have tried
Reinstalling Xcode 7
Using Simulator 8.4 instead of 9.0
Updated to last swift syntax (Edit->Convert->To Latest Swift Syntax)
Here is my AppDelegate File
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
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:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
// MARK: - Core Data stack
lazy var applicationDocumentsDirectory: NSURL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "com.wt9t.BaseballsInsightVersionBeta" in the application's documents Application Support directory.
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1]
}()
lazy var managedObjectModel: NSManagedObjectModel = {
// The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
let modelURL = NSBundle.mainBundle().URLForResource("BaseballsInsightVersionBeta", withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("BaseballsInsightVersionBeta.sqlite")
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
do {
try coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
} catch let error as NSError {
print(error.localizedDescription)
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext? = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support
func saveContext () {
if managedObjectContext!.hasChanges {
do {
try managedObjectContext!.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
abort()
}
}
}
}
Also i am including my initial view controller called MainVC
import UIKit
import CoreData
import Foundation
import SystemConfiguration
class MainVC: UIViewController {
#IBOutlet var chartCountTextView: UITextView!
let cdao = CoreDataRequests()
var chartsCompleted:Array<String> = []
override func viewDidLoad() {
super.viewDidLoad()
print("Viewdidload finished")
self.view.backgroundColor = UIColor.darkGrayColor()
let count = cdao.getChartCountInQueue()
if(count != 0)
{
chartCountTextView.text = "\(count) charts have yet to be uploaded, click Chart Queue to start the process"
}
else
{
chartCountTextView.text = ""
}
chartCountTextView.backgroundColor = UIColor.clearColor()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(animated: Bool) {
let email = NSUserDefaults.standardUserDefaults().stringForKey("userEmail")
let password = NSUserDefaults.standardUserDefaults().stringForKey("userPassword")
if(email == nil || password == nil)
{
self.performSegueWithIdentifier("login", sender: self)
}
}
}

Resources