IOS:Swift: Video Screen Capture - ios

What is the screen device called in iOS/Swift?
When I print the devices I get
(
"<AVCaptureFigVideoDevice: 0x134d0f210 [Back Camera][com.apple.avfoundation.avcapturedevice.built-in_video:0]>",
"<AVCaptureFigVideoDevice: 0x134e0af80 [Front Camera][com.apple.avfoundation.avcapturedevice.built-in_video:1]>",
"<AVCaptureFigAudioDevice: 0x174265440 [iPad Microphone][com.apple.avfoundation.avcapturedevice.built-in_audio:0]>"
)
So where's the screen ID?
There's just too much outdated objective c code while swift is a moving target. I'm looking for a swift solution to capture video from my iPad screen and audio from built-in microphone. The audio will be a separate question.
Here is a screen grabber for OS X
https://github.com/kennyledet/SwiftCap
// AVCaptureSession holds inputs and outputs for real-time capture
let mSession = AVCaptureSession()
let mScreenCapOutput = AVCaptureMovieFileOutput()
var mOutputPath = ""
// Just capture main display for now
let mMainDisplayId = CGMainDisplayID()
but I cannot find in the documentation the display ID, CGMainDisplayID, for an iPad...
Here is a typical solution for a camera in swift
https://github.com/bradley/iOSSwiftSimpleAVCamera
but it has too many errors and doesn't compile with iOS 8.1 or 8.2 and grabs video from camera.
func addVideoOutput() {
var rgbOutputSettings: NSDictionary = NSDictionary(object: Int(CInt(kCIFormatRGBA8)), forKey: kCVPixelBufferPixelFormatTypeKey)
self.videoDeviceOutput = AVCaptureVideoDataOutput()
self.videoDeviceOutput.alwaysDiscardsLateVideoFrames = true
self.videoDeviceOutput.setSampleBufferDelegate(self, queue: self.sessionQueue)
if self.session.canAddOutput(self.videoDeviceOutput) {
self.session.addOutput(self.videoDeviceOutput)
}
}
https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/04_MediaCapture.html#//apple_ref/doc/uid/TP40010188-CH5-SW18
Apple gives an objective-c solution like this
/*
* Create video connection
*/
AVCaptureDeviceInput *videoIn = [[AVCaptureDeviceInput alloc] initWithDevice:[self videoDeviceWithPosition:AVCaptureDevicePositionBack] error:nil];
if ([_captureSession canAddInput:videoIn])
[_captureSession addInput:videoIn];
AVCaptureVideoDataOutput *videoOut = [[AVCaptureVideoDataOutput alloc] init];
[videoOut setAlwaysDiscardsLateVideoFrames:YES];
[videoOut setVideoSettings:#{(id)kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithInt:kCVPixelFormatType_32BGRA]}];
dispatch_queue_t videoCaptureQueue = dispatch_queue_create("Video Capture Queue", DISPATCH_QUEUE_SERIAL);
[videoOut setSampleBufferDelegate:self queue:videoCaptureQueue];
if ([_captureSession canAddOutput:videoOut])
[_captureSession addOutput:videoOut];
_videoConnection = [videoOut connectionWithMediaType:AVMediaTypeVideo];
self.videoOrientation = _videoConnection.videoOrientation;
if([self.session canSetSessionPreset:AVCaptureSessionPreset640x480])
[self.session setSessionPreset:AVCaptureSessionPreset640x480]; // Lower video resolution to decrease recorded movie size
return YES;
}
This should be easy.....???

Here is a working copy of iOSSwiftSimpleAVCamera in swift. It doesn't quite solve your problem but it is a bit of a starting point for anyone else that looks at this thread. Some of the error checking was removed from this code so be weary, it will only work on an actual device not in the simulator.
App delegate
//
// AppDelegate.swift
// iOSSwiftSimpleAVCamera
//
// Created by Bradley Griffith on 7/1/14.
// Copyright (c) 2014 Bradley Griffith. All rights reserved.
//
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func applicationDidFinishLaunching(application: UIApplication) {
}
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()
}
func saveContext () {
var error: NSError? = nil
let managedObjectContext = self.managedObjectContext
//if managedObjectContext != nil {
if managedObjectContext.hasChanges && !managedObjectContext.save(&error) {
// 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.
//println("Unresolved error \(error), \(error.userInfo)")
abort()
// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}
}
}
// #pragma mark - Core Data stack
// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
var managedObjectContext: NSManagedObjectContext {
if !(_managedObjectContext != nil) {
let coordinator = self.persistentStoreCoordinator
//if coordinator != nil {
_managedObjectContext = NSManagedObjectContext()
_managedObjectContext!.persistentStoreCoordinator = coordinator
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}
}
return _managedObjectContext!
}
var _managedObjectContext: NSManagedObjectContext? = nil
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
var managedObjectModel: NSManagedObjectModel {
if !(_managedObjectModel != nil) {
let modelURL = NSBundle.mainBundle().URLForResource("iOSSwiftSimpleAVCamera", withExtension: "momd")
_managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL!)
}
return _managedObjectModel!
}
var _managedObjectModel: NSManagedObjectModel? = nil
// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
var persistentStoreCoordinator: NSPersistentStoreCoordinator {
if !(_persistentStoreCoordinator != nil) {
let storeURL = self.applicationDocumentsDirectory.URLByAppendingPathComponent("iOSSwiftSimpleAVCamera.sqlite")
var error: NSError? = nil
_persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
if _persistentStoreCoordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil, error: &error) == nil {
/*
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.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
NSFileManager.defaultManager().removeItemAtURL(storeURL, error: nil)
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true}
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
//println("Unresolved error \(error), \(error.userInfo)")
abort()
}
}
return _persistentStoreCoordinator!
}
var _persistentStoreCoordinator: NSPersistentStoreCoordinator? = nil
// #pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
var applicationDocumentsDirectory: NSURL {
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.endIndex-1] as! NSURL
}
}
CameraSessionController
//
// CameraSessionController.swift
// iOSSwiftSimpleAVCamera
//
// Created by Bradley Griffith on 7/1/14.
// Copyright (c) 2014 Bradley Griffith. All rights reserved.
//
import UIKit
import AVFoundation
import CoreMedia
import CoreImage
#objc protocol CameraSessionControllerDelegate {
optional func cameraSessionDidOutputSampleBuffer(sampleBuffer: CMSampleBuffer!)
}
class CameraSessionController: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {
var session: AVCaptureSession!
var sessionQueue: dispatch_queue_t!
var videoDeviceInput: AVCaptureDeviceInput!
var videoDeviceOutput: AVCaptureVideoDataOutput!
var stillImageOutput: AVCaptureStillImageOutput!
var runtimeErrorHandlingObserver: AnyObject?
var sessionDelegate: CameraSessionControllerDelegate?
/* Class Methods
------------------------------------------*/
class func deviceWithMediaType(mediaType: NSString, position: AVCaptureDevicePosition) -> AVCaptureDevice {
var devices: NSArray = AVCaptureDevice.devicesWithMediaType(mediaType as String)
var captureDevice: AVCaptureDevice = devices.firstObject as! AVCaptureDevice
for object:AnyObject in devices {
let device = object as! AVCaptureDevice
if (device.position == position) {
captureDevice = device
break
}
}
return captureDevice
}
/* Lifecycle
------------------------------------------*/
override init() {
super.init();
self.session = AVCaptureSession()
self.authorizeCamera();
self.sessionQueue = dispatch_queue_create("CameraSessionController Session", DISPATCH_QUEUE_SERIAL)
dispatch_async(self.sessionQueue, {
self.session.beginConfiguration()
self.addVideoInput()
self.addVideoOutput()
self.addStillImageOutput()
self.session.commitConfiguration()
})
}
/* Instance Methods
------------------------------------------*/
func authorizeCamera() {
AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: {
(granted: Bool) -> Void in
// If permission hasn't been granted, notify the user.
if !granted {
dispatch_async(dispatch_get_main_queue(), {
UIAlertView(
title: "Could not use camera!",
message: "This application does not have permission to use camera. Please update your privacy settings.",
delegate: self,
cancelButtonTitle: "OK").show()
})
}
});
}
func addVideoInput() -> Bool {
var success: Bool = false
var error: NSError?
var videoDevice: AVCaptureDevice = CameraSessionController.deviceWithMediaType(AVMediaTypeVideo, position: AVCaptureDevicePosition.Back)
self.videoDeviceInput = AVCaptureDeviceInput.deviceInputWithDevice(videoDevice, error: &error) as! AVCaptureDeviceInput;
if !(error != nil) {
if self.session.canAddInput(self.videoDeviceInput) {
self.session.addInput(self.videoDeviceInput)
success = true
}
}
return success
}
func addVideoOutput() {
//&&&&&&&&&&&&&&&&&&&&&var rgbOutputSettings: NSDictionary = NSDictionary(object: Int(CInt(kCIFormatRGBA8)), forKey: kCVPixelBufferPixelFormatTypeKey)
self.videoDeviceOutput = AVCaptureVideoDataOutput()
self.videoDeviceOutput.alwaysDiscardsLateVideoFrames = true
self.videoDeviceOutput.setSampleBufferDelegate(self, queue: self.sessionQueue)
if self.session.canAddOutput(self.videoDeviceOutput) {
self.session.addOutput(self.videoDeviceOutput)
}
}
func addStillImageOutput() {
self.stillImageOutput = AVCaptureStillImageOutput()
self.stillImageOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
if self.session.canAddOutput(self.stillImageOutput) {
self.session.addOutput(self.stillImageOutput)
}
}
func startCamera() {
dispatch_async(self.sessionQueue, {
var weakSelf: CameraSessionController? = self
self.runtimeErrorHandlingObserver = NSNotificationCenter.defaultCenter().addObserverForName(AVCaptureSessionRuntimeErrorNotification, object: self.sessionQueue, queue: nil, usingBlock: {
(note: NSNotification!) -> Void in
let strongSelf: CameraSessionController = weakSelf!
dispatch_async(strongSelf.sessionQueue, {
strongSelf.session.startRunning()
})
})
self.session.startRunning()
})
}
func teardownCamera() {
dispatch_async(self.sessionQueue, {
self.session.stopRunning()
NSNotificationCenter.defaultCenter().removeObserver(self.runtimeErrorHandlingObserver!)
})
}
func focusAndExposeAtPoint(point: CGPoint) {
dispatch_async(self.sessionQueue, {
var device: AVCaptureDevice = self.videoDeviceInput.device
var error: NSErrorPointer!
if device.lockForConfiguration(error) {
if device.focusPointOfInterestSupported && device.isFocusModeSupported(AVCaptureFocusMode.AutoFocus) {
device.focusPointOfInterest = point
device.focusMode = AVCaptureFocusMode.AutoFocus
}
if device.exposurePointOfInterestSupported && device.isExposureModeSupported(AVCaptureExposureMode.AutoExpose) {
device.exposurePointOfInterest = point
device.exposureMode = AVCaptureExposureMode.AutoExpose
}
device.unlockForConfiguration()
}
else {
// TODO: Log error.
}
})
}
func captureImage(completion:((image: UIImage?, error: NSError?) -> Void)?) {
if (completion != nil){
if(self.stillImageOutput != nil) {
return
}}
dispatch_async(self.sessionQueue, {
self.stillImageOutput.captureStillImageAsynchronouslyFromConnection(self.stillImageOutput.connectionWithMediaType(AVMediaTypeVideo), completionHandler: {
(imageDataSampleBuffer: CMSampleBuffer?, error: NSError?) -> Void in
if (imageDataSampleBuffer != nil)
{
if(error != nil)
{
completion!(image:nil, error:nil)
}
}
else if (imageDataSampleBuffer != nil) {
var imageData: NSData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
var image: UIImage = UIImage(data: imageData)!
completion!(image:image, error:nil)
}
})
})
}
/* AVCaptureVideoDataOutput Delegate
------------------------------------------*/
func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {
self.sessionDelegate?.cameraSessionDidOutputSampleBuffer?(sampleBuffer)
}
}
camera view controller
//
// CameraViewController.swift
// iOSSwiftSimpleAVCamera
//
// Created by Bradley Griffith on 7/1/14.
// Copyright (c) 2014 Bradley Griffith. All rights reserved.
//
import UIKit
import CoreMedia
import AVFoundation
class CameraViewController: UIViewController, CameraSessionControllerDelegate {
var cameraSessionController: CameraSessionController!
var previewLayer: AVCaptureVideoPreviewLayer!
/* Lifecycle
------------------------------------------*/
override func viewDidLoad() {
super.viewDidLoad()
self.cameraSessionController = CameraSessionController()
self.cameraSessionController.sessionDelegate = self
self.setupPreviewLayer()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.cameraSessionController.startCamera()
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.cameraSessionController.teardownCamera()
}
/* Instance Methods
------------------------------------------*/
func setupPreviewLayer() {
var minSize = min(self.view.bounds.size.width, self.view.bounds.size.height)
var bounds: CGRect = CGRectMake(0.0, 0.0, minSize, minSize)
self.previewLayer = AVCaptureVideoPreviewLayer(session: self.cameraSessionController.session)
self.previewLayer.bounds = bounds
self.previewLayer.position = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds))
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
self.view.layer.addSublayer(self.previewLayer)
}
func cameraSessionDidOutputSampleBuffer(sampleBuffer: CMSampleBuffer!) {
// Any frame processing could be done here.
}
}

If you want to capture the video of screen and save it, there is also an option to make a number of screenshots, and later to convert array of images to the video, not very efficient from performance standpoint though, you probably won't have 30-60 fps, but if you are ok w/ 5-20 fps you might want to take a look at this example for swift3.

Related

I am getting records from core data in ios 10 but I am not getting same records for iOS 9

In iOS 10 I am getting records from core data but the same records I am not getting for iOS 9.
Here is my code:
let request:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Airport")
let predicate = NSPredicate(format: "iata == %#", arrayData[i])
request.predicate = predicate
do {
airportData = try appDel?.databaseContext.fetch(request) as! [Airport]
print("data:\(airportData.count)")
} catch {
print("Fetching Failed")
}
Actually it's duplicated question. For iOS 8 and 9 you should implement another app delegate and use 2 different ways for inserting data into database.
Xcode 8 Core Data Template for iOS 8,9
Let me show you example from my project.
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) {
// 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.
if #available(iOS 10.0, *) {
self.saveContext()
} else {
self.saveOldStyleContext()
}
}
// MARK: - Core Data stack
#available(iOS 10.0, *)
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "CafeManager")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
//Error handling
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
#available(iOS 10.0, *)
static var persistantContainer: NSPersistentContainer {
return (UIApplication.shared.delegate as! AppDelegate).persistentContainer
}
static var viewContext: NSManagedObjectContext {
if #available(iOS 10.0, *) {
return persistantContainer.viewContext
} else {
return AppDelegate.managedObjectContext
}
}
// MARK: - Core Data stack for iOS 8+
static var managedObjectContext: NSManagedObjectContext = {
var applicationDocumentsDirectory: URL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "com.cadiridris.coreDataTemplate" in the application's documents Application Support directory.
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1]
}()
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: "CafeManager", withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
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: managedObjectModel)
let url = 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: "iGlock.CafeManager.com", 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
}()
// 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 = persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support for iOS 10
#available(iOS 10.0, *)
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)")
}
}
}
// MARK: - Core Data Saving support for iOS 8+
func saveOldStyleContext () {
if AppDelegate.managedObjectContext.hasChanges {
do {
try AppDelegate.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()
}
}
}
}
And how I handled insertion requests for iOS 8-9 and 10+:
class func addNewCustomGuest (guestName: String, tableSession: TableSessionTable) {
if #available(iOS 10.0, *) {
let newGuest = GuestsTable(context: context)
newGuest.guestName = guestName
newGuest.openTime = Date() as NSDate
newGuest.closeTime = nil
tableSession.addToGuest(newGuest)
} else {
let newGuest = GuestsTable(entity: NSEntityDescription.entity(forEntityName: "GuestsTable", in: context)!, insertInto: context)
newGuest.guestName = guestName
newGuest.openTime = Date() as NSDate
newGuest.closeTime = nil
tableSession.addToGuest(newGuest)
}
try? context.save()
}
In the same time fetch requests will work for both versions:
class func getActiveGuestsForTable (tableSession: TableSessionTable) -> [GuestsTable]? {
guestTableRequest.predicate = NSPredicate(format: "table = %# and closeTime = %#", tableSession, NSNull() as CVarArg)
guestTableRequest.sortDescriptors = [NSSortDescriptor(key: "openTime", ascending: true, selector: #selector(NSDate.compare(_:)))]
let matchedGuests = try? context.fetch(guestTableRequest)
return matchedGuests
}

How to use Ensembles Framework in Swift Project

I have a project which already uses Core Data. I have added support for the iPad, but now will need to use iCloud & Core Data to sync the data.
I came across Ensembles, it seems like an easy and robust framework to add to my project. Found here: https://github.com/drewmccormack/ensembles
However there are no Swift example projects with the Ensembles project so have attempted to do it myself. Here are the steps I have taken,
Step 1
Manually add Ensembles to iOS projects.
Step 2
Create new CoreDataStack using existing persistent store .sql file.
import UIKit
import CoreData
class CoreDataStack: NSObject, CDEPersistentStoreEnsembleDelegate {
static let defaultStack = CoreDataStack()
var ensemble : CDEPersistentStoreEnsemble? = nil
var cloudFileSystem : CDEICloudFileSystem? = nil
// MARK: - Core Data stack
lazy var storeName : String = {
return NSBundle.mainBundle().objectForInfoDictionaryKey(kCFBundleNameKey as String) as! String
}()
lazy var sqlName : String = {
return "SingleViewCoreData.sqlite"
}()
lazy var icloudStoreName : String = {
return self.storeName + "CloudStore"
}()
lazy var storeDescription : String = {
return "Core data stack of " + self.storeName
}()
lazy var iCloudAppID : String = {
return "iCloud." + NSBundle.mainBundle().bundleIdentifier!
}()
lazy var modelURL : NSURL = {
return NSBundle.mainBundle().URLForResource(self.storeName, withExtension: "momd")!
}()
lazy var storeDirectoryURL : NSURL = {
var directoryURL : NSURL? = nil
do {
try directoryURL = NSFileManager.defaultManager().URLForDirectory(NSSearchPathDirectory.ApplicationSupportDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
directoryURL = directoryURL!.URLByAppendingPathComponent(NSBundle.mainBundle().bundleIdentifier!, isDirectory: true)
} catch {
NSLog("Unresolved error: Application's document directory is unreachable")
abort()
}
return directoryURL!
}()
lazy var storeURL : NSURL = {
return self.storeDirectoryURL.URLByAppendingPathComponent(self.sqlName)
// return self.applicationDocumentsDirectory.URLByAppendingPathComponent(self.sqlName)
}()
lazy var applicationDocumentsDirectory: NSURL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "com.dprados.CoreDataSpike" 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(self.storeName, withExtension: "momd")
return NSManagedObjectModel(contentsOfURL: 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 = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
var options = [NSObject: AnyObject]()
options[NSMigratePersistentStoresAutomaticallyOption] = NSNumber(bool: true)
options[NSInferMappingModelAutomaticallyOption] = NSNumber(bool: true)
do {
try NSFileManager.defaultManager().createDirectoryAtURL(self.storeDirectoryURL, withIntermediateDirectories: true, attributes: nil)
} catch {
NSLog("Unresolved error: local database storage position is unavailable.")
abort()
}
// Create the coordinator and store
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
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
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
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()
}
}
}
static func save() {
CoreDataStack.defaultStack.saveContext()
}
func enableEnsemble() {
CoreDataStack.defaultStack.cloudFileSystem = CDEICloudFileSystem(ubiquityContainerIdentifier: nil)
CoreDataStack.defaultStack.ensemble = CDEPersistentStoreEnsemble(ensembleIdentifier: self.storeName, persistentStoreURL: self.storeURL, managedObjectModelURL: self.modelURL, cloudFileSystem: CoreDataStack.defaultStack.cloudFileSystem)
CoreDataStack.defaultStack.ensemble!.delegate = CoreDataStack.defaultStack
}
func persistentStoreEnsemble(ensemble: CDEPersistentStoreEnsemble!, didSaveMergeChangesWithNotification notification: NSNotification!) {
CoreDataStack.defaultStack.managedObjectContext.performBlockAndWait({ () -> Void in
CoreDataStack.defaultStack.managedObjectContext.mergeChangesFromContextDidSaveNotification(notification)
})
if notification != nil {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.02 * Double(NSEC_PER_MSEC))), dispatch_get_main_queue(), {
NSLog("Database was updated from iCloud")
CoreDataStack.defaultStack.saveContext()
NSNotificationCenter.defaultCenter().postNotificationName("DB_UPDATED", object: nil)
})
}
}
func persistentStoreEnsemble(ensemble: CDEPersistentStoreEnsemble!, globalIdentifiersForManagedObjects objects: [AnyObject]!) -> [AnyObject]! {
NSLog("%#", (objects as NSArray).valueForKeyPath("uniqueIdentifier") as! [AnyObject])
return (objects as NSArray).valueForKeyPath("uniqueIdentifier") as! [AnyObject]
}
func syncWithCompletion(completion: (() -> Void)!) {
if CoreDataStack.defaultStack.ensemble!.leeched {
CoreDataStack.defaultStack.ensemble!.mergeWithCompletion({ (error:NSError?) -> Void in
if error != nil && error!.code != 103 {
NSLog("Error in merge: %#", error!)
} else if error != nil && error!.code == 103 {
self.performSelector("syncWithCompletion:", withObject: nil, afterDelay: 1.0)
} else {
if completion != nil {
completion()
}
}
})
} else {
CoreDataStack.defaultStack.ensemble!.leechPersistentStoreWithCompletion({ (error:NSError?) -> Void in
if error != nil && error!.code != 103 {
NSLog("Error in leech: %#", error!)
} else if error != nil && error!.code == 103 {
self.performSelector("syncWithCompletion:", withObject: nil, afterDelay: 1.0)
} else {
self.performSelector("syncWithCompletion:", withObject: nil, afterDelay: 1.0)
if completion != nil {
completion()
}
}
})
}
}
}
Step 3
Update App Delegate to sync and add notifications
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let _ : CoreDataStack = CoreDataStack.defaultStack
// Value.ValueTypeInManagedObjectContext(CoreDataStack.defaultStack.managedObjectContext)
CoreDataStack.defaultStack.saveContext()
CoreDataStack.defaultStack.enableEnsemble()
// Listen for local saves, and trigger merges
NSNotificationCenter.defaultCenter().addObserver(self, selector: "localSaveOccured:", name: CDEMonitoredManagedObjectContextDidSaveNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "cloudDataDidDownload:", name:CDEICloudFileSystemDidDownloadFilesNotification, object:nil)
CoreDataStack.defaultStack.syncWithCompletion(nil);
return true
}
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.
let identifier : UIBackgroundTaskIdentifier = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler(nil)
CoreDataStack.defaultStack.saveContext()
CoreDataStack.defaultStack.syncWithCompletion( { () -> Void in
UIApplication.sharedApplication().endBackgroundTask(identifier)
})
}
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 application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
NSLog("Received a remove notification")
}
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.
CoreDataStack.defaultStack.syncWithCompletion(nil)
}
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.
CoreDataStack.defaultStack.syncWithCompletion(nil)
}
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.
CoreDataStack.defaultStack.saveContext()
}
func localSaveOccured(notif: NSNotification) {
NSLog("Local save occured")
CoreDataStack.defaultStack.syncWithCompletion(nil)
}
func cloudDataDidDownload(notif: NSNotification) {
NSLog("Cloud data did download")
CoreDataStack.defaultStack.syncWithCompletion(nil)
}
Step 4
Add Notifications to project to refresh UI
override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "cloudDataDidDownload:", name:"DB_UPDATED", object:nil)
//cloudDataDidDownload refetches the entities and reload the table
}
Step 5
Watch the magic happen.. Unfortunately there is no magic atm. The new CoreDataStack works fine, I can save and retrieve data from the persistent store.
I have two devices logged into the same iCloud account, and neither data is shared to the other device.
When deleting the app and reinstalling the data is not retrieved from the iCloud and saved to the persistent store.
I do get the following NSLog when 'sometimes' saving data or loading up the app.
2016-04-06 13:17:37.101 APPNAME[435:152241] Cloud data did download
This is the outcome for the following appDelegate notification function
func cloudDataDidDownload(notif: NSNotification) {
NSLog("Cloud data did download")
CoreDataStack.defaultStack.syncWithCompletion(nil)
}
The notification is sent from this function in the CoreDataStack for when changes are merged.
func persistentStoreEnsemble(ensemble: CDEPersistentStoreEnsemble!, didSaveMergeChangesWithNotification notification: NSNotification!) {
CoreDataStack.defaultStack.managedObjectContext.performBlockAndWait({ () -> Void in
CoreDataStack.defaultStack.managedObjectContext.mergeChangesFromContextDidSaveNotification(notification)
})
if notification != nil {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.02 * Double(NSEC_PER_MSEC))), dispatch_get_main_queue(), {
NSLog("Database was updated from iCloud")
CoreDataStack.defaultStack.saveContext()
NSNotificationCenter.defaultCenter().postNotificationName("DB_UPDATED", object: nil)
})
}
}
So everything seems like it should be working fine. I get no errors but the data is not syncing. I cannot tell if the problem is the data backing up to iCloud or retrieving from iCloud and merging with the persistent store. All I can tell is that data is not shared between devices using the same iCloud account and the app does not actually restore the data from the iCloud when reinstalling the app.

How to make Core Data's ManagedObjectContext.ExecuteFetchRequest Synchronous and not Asynchronous

Attached is my code below.
The line that is giving me the problems is let fetchRequest = try moc.executeFetchRequest(fetchRequest) as! [AppSettings] appears to load asynchronously but I want it to load synchronously so that I can ensure it checks properly for a username record.
How do I do this?
I know it loads asynchronously because when I start and stop the program constantly it will find the entity roughly 80% of the time and randomly 20% of the time it will not. Since nothing else is changing the entity (since I'm just starting and stopping the program constantly), it would make sense that the code is being run asynchrnously so when I use the command
guard let appSettingsArrayItem = fetchRequest.first where fetchRequest.count>0 else {
print ("no entities found...")
return false
}
It fails to find any entities sometimes.
Check Login Function
func checkIfLoggedInAlready() -> Bool{
let fetchRequest = NSFetchRequest(entityName: "AppSettings")
//let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) //Deletes ALL appsettings entities
do {
let fetchRequest = try moc.executeFetchRequest(fetchRequest) as! [AppSettings]
guard let appSettingsArrayItem = fetchRequest.first where fetchRequest.count>0 else {
print ("no entities found...")
return false
}
guard let username = (appSettingsArrayItem as AppSettings).username else{
print ("username not found")
return false
}
print("number Of AppSetting Entities =\(fetchRequest.count)")
print(username)
//The following code deletes ALL the entities!
//try moc.persistentStoreCoordinator!.executeRequest(deleteRequest, withContext: moc)
//To delete just '1' entry use the code below.
//moc.deleteObject(appSettingsArrayItem)
//try moc.save()//save deletion change.
//print("deleted particular entity item")
return true
} catch{
fatalError("bad things happened \(error)")
}
}
Entire LoginViewController including Check Login Function
import UIKit
import CoreData
class LoginViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var usernameField: UITextField!
#IBOutlet weak var passwordField: UITextField!
var isLoggedIn = false
let moc = DataController().managedObjectContext
#IBAction func SignUpButtonPressed(sender: UIButton) {
print("sign up")
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
override func viewDidLoad() {
super.viewDidLoad()
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
view.addGestureRecognizer(tap)
print("view loaded, check if already signed in here")
let loggedIn = checkIfLoggedInAlready() //checks database to see
if(loggedIn){
print("was logged in!")
isLoggedIn = true
self.performSegueWithIdentifier("loginSegue", sender: self)
}
}
func checkIfLoggedInAlready() -> Bool{
let fetchRequest = NSFetchRequest(entityName: "AppSettings")
//let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest) //Deletes ALL appsettings entities
do {
let fetchRequest = try moc.executeFetchRequest(fetchRequest) as! [AppSettings]
guard let appSettingsArrayItem = fetchRequest.first where fetchRequest.count>0 else {
print ("no entities found...")
return false
}
guard let username = (appSettingsArrayItem as AppSettings).username else{
print ("username not found")
return false
}
print("number Of AppSetting Entities =\(fetchRequest.count)")
print(username)
//The following code deletes ALL the entities!
//try moc.persistentStoreCoordinator!.executeRequest(deleteRequest, withContext: moc)
//To delete just '1' entry use the code below.
//moc.deleteObject(appSettingsArrayItem)
//try moc.save()//save deletion change.
//print("deleted particular entity item")
return true
} catch{
fatalError("bad things happened \(error)")
}
}
func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
print("prepare seque")
}
func displayErrorMessage(errorMessage: String){
print("show error console with Error:"+errorMessage)
let alert = UIAlertController(title: "Error", message: errorMessage, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
switch(identifier){
case "loginSegue":
print("Is the user already logged in?")
if(isLoggedIn){
print("Detected as YES")
return true
}
print("Detected as NO, so checking username and password fields next...")
guard let password = passwordField.text!.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet()) where !password.isEmpty else {
displayErrorMessage("Password can not be empty!")
return false
}
guard let username = usernameField.text!.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet()) where !username.isEmpty else{
displayErrorMessage("Username can not be empty!")
return false
}
let url = "http://distribution.tech/restapi/v1/userlogin?email="+username+"&password="+password
print(url)
let json = JSON(url:url)
print(json)
if(json["status"].asInt==1){
let entity = NSEntityDescription.insertNewObjectForEntityForName("AppSettings", inManagedObjectContext: moc) as! AppSettings
entity.setValue(username, forKey: "username")
entity.setValue(password, forKey: "password")
entity.setValue(json["tokenid"].asString, forKey: "token")
entity.setValue(json["roleid"].asInt, forKey: "roleid")
entity.setValue(json["role"].asString, forKey: "role")
entity.setValue(json["companyid"].asInt , forKey: "companyid")
entity.setValue(json["isdev"].asInt, forKey: "isdev")
//save token and other details to database.
do {
try moc.save()
print("saved to entity")
}catch{
fatalError("Failure to save context: \(error)")
}
// token
// roleid int
// role
// companyid int
//
// {
// "companyid": 3,
// "userid": 2,
// "tokenid": "804febae26ddbd0292b3d2c66b30afd5028d5ba9",
// "status": 1,
// "roleId": 1,
// "role": "super_admin",
// "isdev": 0
// }
//Save to disk using our own method, as COREDATA is unreliable!
return true //login succesfull
}else{
displayErrorMessage("Incorrect Username or Email")
return false//failed
}
default:
displayErrorMessage("Unknown Error Related To Segue Not Found")
}
return false //if it gets to this point assume false
}
}
The managed object is created in the DataController its file is here below.
import UIKit
import CoreData
class DataController: NSObject {
var managedObjectContext: NSManagedObjectContext
override init() {
// This resource is the same name as your xcdatamodeld contained in your project.
guard let modelURL = NSBundle.mainBundle().URLForResource("AppSettings", withExtension:"momd") else {
fatalError("Error loading model from bundle")
}
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
guard let mom = NSManagedObjectModel(contentsOfURL: modelURL) else {
fatalError("Error initializing mom from: \(modelURL)")
}
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
self.managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
self.managedObjectContext.persistentStoreCoordinator = psc
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let docURL = urls[urls.endIndex-1]
/* The directory the application uses to store the Core Data store file.
This code uses a file named "DataModel.sqlite" in the application's documents directory.
*/
let storeURL = docURL.URLByAppendingPathComponent("AppSettings.sqlite")
do {
try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil)
} catch {
fatalError("Error migrating store: \(error)")
}
}
}
}
Image Reference Of Entity & Console Error That Can Happen Sometimes
Image Reference Of Entity & Console When It Does Find Entity Most Of Time
ManagedObjectContext.ExecuteFetchRequest already runs synchronously but it looks like you are setting up your persistent store coordinator asynchronously in a background priority thread.
If this fetch request happens immediately when the app starts up, and you do it over and over again, it may not be finished setting up some of the times.
Okay the answer above was correct, so what I did was created a new project single view, selected core data option, and copied code from its AppDelegate over my own AppDelegate to get the proper CoreData Init Code, and in such a way that when the project terminates it saves the context correctly and so forth. The code looks like this.
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.distribution.tech.Test" 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("AppSettings", withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: 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.URLByAppendingPathComponent("AppSettings.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
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()
}
}
}
}
Its key when you do this that you change the reference to your own xcdatamodeld or this won't work. In my case it was changing this line to the correct sqlite based on my previous work.
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("AppSettings.sqlite")
and this line...
let modelURL = NSBundle.mainBundle().URLForResource("AppSettings", withExtension: "momd")!
which is the actual name of the xcdatamodeld file.
Hope this helps someone who had same issue as me. Oh...and apple if you are reading this...please add 'core data' option for tab based projects in the future... and not just single view.

My app is crashing when I assign the managed object context to a variable

Pleeeease help. I'm making this app and I didn't add coreData in the beginning. I added it later with the help of some online tutorials. everything seems to be working fine except that my app is crashing at line 33 here:
import UIKit
import CoreData
class SittingsViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//preperation
Stepper.continuous = false
Stepper.autorepeat = false
Stepper.maximumValue = 6
Stepper.minimumValue = 0
valChanged(1)
var request = NSFetchRequest(entityName: "Sittings")
request.returnsObjectsAsFaults = false
Stepper.value = managedContext.executeFetchRequest(request, error: nil) as! Double
managedContext.save(nil)
}
//global vars and iboutlets
#IBOutlet var Stepper: UIStepper!
#IBOutlet var AproximateLabel: UILabel!
var decimalPlaces = Int()
//core data
var appDel = UIApplication.sharedApplication().delegate as! AppDelegate
var managedContext = SittingsViewController().appDel.managedObjectContext! //my error happens here
let entity = NSEntityDescription.entityForName("Sittings",
inManagedObjectContext:
SittingsViewController().managedContext)
let decimal = NSManagedObject(entity: SittingsViewController().entity!,
insertIntoManagedObjectContext:SittingsViewController().managedContext)
#IBAction func stepperValueChanged(sender: UIStepper) {
valChanged(Int(sender.value))
AproximateLabel.text = Int(sender.value).description
}
//segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var firstView: ViewController = segue.destinationViewController as! ViewController
firstView.decimalPlaces = Int(decimalPlaces)
}
func valChanged(num: Int) {
let entity = NSEntityDescription.entityForName("Sittings",
inManagedObjectContext:
managedContext)
let decimal = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext:managedContext)
//3
decimal.setValue(num, forKey: "decimalPlaces")
//4
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
decimalPlaces = num
}
}
If you need more code or anything else, I would be happy to help!
Backtrace:
https://drive.google.com/file/d/0Bxu11l4-PozQTHk5cmYydlZ3Zm8/view?usp=sharing
AppDelegate:
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.
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent
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:.
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.xxxx.math" in the application's documents Application Support directory.
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .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 = NSBundle.mainBundle().URLForResource("math", 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("math.sqlite")
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil {
coordinator = nil
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
error = 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 \(error), \(error!.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
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support
func saveContext () {
if let moc = self.managedObjectContext {
var error: NSError? = nil
if moc.hasChanges && !moc.save(&error) {
// 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.
NSLog("Unresolved error \(error), \(error!.userInfo)")
abort()
}
}
}
}
Thank you very much!
I just found out that my managedObjectContext is nil, but I don't know why?
Can anybody help?

Core Data Context not Saving

I have been struggling to get Core Data working in my mobile application. The values consistently stay nil after all of my attempts to fix it. This is the related information for saving my information, mind you there will only be one result at any point in time.
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
let insertBools = NSEntityDescription.insertNewObjectForEntityForName("Codes", inManagedObjectContext: context) as NSManagedObject
Later in the code after doing a string check comparison based upon the QR Code that is scanned...
else if (metadataObj.stringValue == "oiu2162poiu" && res.qrCode5_Found != true) {
captureSession?.stopRunning()
println("\(metadataObj.stringValue) qrCode5_Found if")
insertBools.setValue(true, forKey: "qrCode5_Found")
var alert = UIAlertController(title: "Code Found!", message: "You have found and scanned Code #5!", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
insertBools.managedObjectContext?.save(nil)
self.navigationController?.popViewControllerAnimated(false)
}
I'm not sure where I'm going wrong. The View controller before this retrieves the values of each of these keys every time it loads and displays certain labels based upon whether or not some of the elements has been found (This is a scavenger hunt style portion of the application).
override func viewDidLoad() {
super.viewDidLoad()
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
let request = NSFetchRequest(entityName: "Codes")
request.returnsObjectsAsFaults = false
var results:NSArray = context.executeFetchRequest(request, error: nil)!
if (results.count == 1) {
var res = results[0] as Codes
if (res.qrCode1_Found != true) {
qrCode1.enabled = true
scanQRCodeButton.enabled = true
qrLeftList.enabled = true
}
if (res.qrCode2_Found != true) {
qrCode2.enabled = true
scanQRCodeButton.enabled = true
qrLeftList.enabled = true
}
if (res.qrCode3_Found != true) {
qrCode3.enabled = true
scanQRCodeButton.enabled = true
qrLeftList.enabled = true
}
if (res.qrCode4_Found != true) {
qrCode4.enabled = true
scanQRCodeButton.enabled = true
qrLeftList.enabled = true
}
if (res.qrCode5_Found != true) {
qrCode5.enabled = false
scanQRCodeButton.enabled = true
qrLeftList.enabled = true
}
if (res.qrCode5_Found == true && res.qrCode4_Found == true && res.qrCode3_Found == true && res.qrCode2_Found == true && res.qrCode1_Found == true) {
registerButton.enabled = true
scanQRCodeButton.enabled = false
}
}
........
And my AppDelegate file, I didn't originally include Core Data but I imported it all manually, and the compiler isn't throwing any errors.
//
// AppDelegate.swift
// webview_test
//
// Created by Robert on 3/19/15.
// Copyright (c) 2015 Robert. All rights reserved.
//
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.
}
// 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.xxxx.ProjectName" in the application's documents Application Support directory.
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .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 = NSBundle.mainBundle().URLForResource("SavedVariables", 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("webview_test.sqlite")
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil {
coordinator = nil
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
error = 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 \(error), \(error!.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
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support
func saveContext () {
if let moc = self.managedObjectContext {
var error: NSError? = nil
if moc.hasChanges && !moc.save(&error) {
// 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.
NSLog("Unresolved error \(error), \(error!.userInfo)")
abort()
}
}
}
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()
}
}
And as a sidenote...if someone could tell me how to force the program to wait for a user to press the OK button on an alert before continuing I would forever be in your debt.
I misunderstood the concept of Core Data. Instead I now loop through each result instead of
var res = results[0] as Codes
with
for res in results as [NSManagedObject] {
....
}
and get the results I need and then use those for comparison, it's a shoddy work around, but it works.

Resources