I'm trying to write a test to make sure that my view model's model property when set calls my fetchPlan method from the model and then sets my 'plan' property in my view model. It seems to be setting the property but the values are missing...
Here's my view model
final class PlanProgressViewModel: PlanProgressViewModelView {
// MARK: - Properties
fileprivate var plan: PlanData?
// MARK: - PlanProgressViewModelView
weak var viewDelegate: PlanProgressViewModelViewDelegate?
var model: PlanModel? {
didSet {
model?.fetchCurrentPlan(completionHandler: { (plan) in
guard let plan = plan else {return}
self.plan = plan
})
}
}
// Testing this fails...
var planName: String! {
guard let plan = plan else {return "No plan"}
return plan.name
}
var planProgressionString: String! {
return "\(Int(round(self.progress * 100)))%"
}
var progress: Double! {
guard let plan = plan, let workouts = plan.workouts, let completedWorkouts = plan.completedWorkouts else {return 0}
return Double(Int(completedWorkouts) / workouts.count)
}
}
Here's my test suite, i'm using a mock to return hardcoded data from the model.
var sut: PlanProgressViewModel!
var model: MockPlanModel!
var moc: NSManagedObjectContext!
override func setUp() {
super.setUp()
moc = setupInMemoryMOC()
let mockModel = MockPlanModel(moc: moc)
model = mockModel
let viewModel = PlanProgressViewModel()
viewModel.model = model
sut = viewModel
}
override func tearDown() {
moc = nil
model = nil
sut = nil
super.tearDown()
}
// This passes
func testModelFetchesCurrentPlanOnce() {
XCTAssertEqual(model.fetchPlanWasCalled, 1)
}
// This is failing
func testPlanName() {
XCTAssertEqual(sut.planName, "Test plan")
}
Here's my method for setting up a in memory persistent store...
public func setupInMemoryMOC() -> NSManagedObjectContext {
let mom = NSManagedObjectModel.mergedModel(from: [Bundle.main])
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom!)
do {
try psc.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
} catch {
fatalError()
}
let moc = NSManagedObjectContext.init(concurrencyType: .mainQueueConcurrencyType)
moc.persistentStoreCoordinator = psc
return moc }
Here's my mock for the model which returns hardcoded data...
public class MockPlanModel: MWPlanModel {
var fetchPlanWasCalled = 0
override public func fetchCurrentPlan(completionHandler: #escaping (_ plan: PlanData?) -> ()) {
fetchPlanWasCalled += 1
let moc = setupInMemoryMOC()
let plan = createTestPlan(moc: moc)
completionHandler(plan)
}}
Here's my helper method for creating the model object, (PlanData is a protocol that my 'Plan' NSManaged object inherits).
public func createTestPlan(moc: NSManagedObjectContext) -> PlanData {
let plan: Plan = Plan(context: moc)
plan.name = "Test plan"
plan.completedWorkouts = 5
plan.currentPlan = true
for _ in 0..<5 {
plan.mutableOrderedSetValue(forKeyPath: #keyPath(Plan.workouts)).add(createTestCompletedWorkout(moc: moc))
}
return plan }
The plan name should be "Test plan" as that is what i set the hardcoded value to be but it fails and returns an empty string instead...
Really stuck on this, i'm fairly new to testing so i appreciate any help with this. Thanks
#MartinR comment good point out :
The non-optional on the left side "Test plan" gets automatically promoted to an optional. because sut.planName is an optional. more check this Swift comparing Strings optionals vs non-optional
You need to unwrap sut.planName
if let planName = sut.planName{
XCTAssertEqual(planName, "Test plan")
}
Or try this way :
XCTAssertEqual((sut.planName ?? ""), "Test plan")
Note: If you face still same issue then update your Xcode
// Using Apple XCTest (Xcode 7.3.1), this produces the output:
// "XCTAssertEqual failed: ("Optional(1)") is not equal to ("Optional(2)") - "
XCTAssertEqual(1, 2)
More details : Here Bug reported
Related
i have 2 entities one customers and other is cases, the relationship is one to many one customer had many cases and the relation names toCustomers for cases entity and toCases for customers entity so in my code i pass selected customer name by segue to the add cases UIViewController
var CustmerNameForAddNewCaseVar: Customers?
CustomerNameLbl.text = CustmerNameForAddNewCaseVar?.name
in the save button
let newCase : Cases!
newCase = Cases(context:context)
newCase.caseName = caseNameTextField.text
newCase.toCustomers = CustmerNameForAddNewCaseVar?.name // here i got error ... Cannot assign value of type 'String?' to type 'Customers?'
do{
AppDel.saveContext()
}catch{
print(error)
}
any help
thank you
To use your example... you would alter your code to match this:
let newCase : Cases!
newCase = Cases(context:context)
newCase.caseName = caseNameTextField.text
newCase.toCustomers = CustmerNameForAddNewCaseVar
do {
// Save Context
} catch {
// Handle Error
}
Notice the line "newCase.toCustomers" has changed.
What others are suggesting in the comments to your question is to clear up the naming of your entities and variables to help clarify usage. An example would be:
import UIKit
import CoreData
class Customer: NSManagedObject {
#NSManaged var cases: Set<Case>?
}
class Case: NSManagedObject {
#NSManaged var customer: Customer?
#NSManaged var name: String?
}
class ViewController: UIViewController {
var customer: Customer?
var context: NSManagedObjectContext?
#IBOutlet weak var caseName: UITextField?
#IBAction func didTapSave(_ sender: UIButton) {
guard let context = self.context else {
return
}
guard let customer = self.customer else {
return
}
let newCase = Case(context: context)
newCase.name = caseName?.text
newCase.customer = customer
do {
try context.save()
} catch {
// Handle Error
}
}
}
I implemented unit testing with my Swift iOS app that uses Core Data, but I am having trouble getting unit tests to pass. I referenced the guide linked below and some stack overflow threads, but I'm still having trouble.
The app runs without flaws when actually built, but the tests fail, leading me to believe that I've messed up somewhere with integrating the mocked the Core Data container and background persistent containers. However, I can't seem to figure out where I'm going wrong here, so any advice is appreciated.
I apologize if my post is lacking any key details, but I'll add them in as necessary.
Main reference material: Cracking the Tests for Core Data
Test Code
class MealTests: XCTestCase {
var sut: MealController!
lazy var managedObjectModel: NSManagedObjectModel = {
let managedObjectModel = NSManagedObjectModel.mergedModel(from: [Bundle(for: type(of: self))])!
return managedObjectModel
}()
lazy var mockPersistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "WeeklyModel", managedObjectModel: self.managedObjectModel)
let description = NSPersistentStoreDescription()
description.type = NSInMemoryStoreType
description.shouldAddStoreAsynchronously = false
container.persistentStoreDescriptions = [description]
container.loadPersistentStores {(description, error) in
//Double check to confirm that date store is in memory
precondition(description.type == NSInMemoryStoreType)
//Check for errors
if let error = error {
fatalError("Creating an in-memory coordinator failed")
}
}
return container
}()
override func setUp() {
super.setUp()
sut = MealController(tense: .all, persistentContainer: mockPersistentContainer)
}
func test_CreatingNewMeal_IsNotNilAndPropertiesSetCorrectly() {
let mealType = Int16(1)
let date = NSDate(timeIntervalSinceNow: 0.0)
let mealDescription = "Testy McTestFace"
let servings = Int16(1)
let image = UIImage(named: "Recipe")
let favorite = false
let meal = sut.saveLocalMeal(mealType: mealType, date: date, mealDescription: mealDescription, servings: servings, image: image, favorite: favorite)
//Test meal is not nil
XCTAssertNotNil(meal, "Should not be nil")
//Testing creating meal sets all properties correctly
XCTAssertEqual(meal?.meal, mealType)
}
Controller Class
class MealController {
//MARK: - Properties
//<...>
private let persistentContainer: NSPersistentContainer!
private var fetchedResultsController: NSFetchedResultsController<Meal>!
lazy var backgroundMOC: NSManagedObjectContext = {
return self.persistentContainer.newBackgroundContext()
}()
//Set to standard persistence container by default
init(tense: Tense, persistentContainer: NSPersistentContainer) {
self.persistentContainer = persistentContainer
self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
reloadAllLocalData(for: tense)
}
convenience init(tense: Tense) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
fatalError("Could not set Managed Object Context")
}
self.init(tense: tense, persistentContainer: appDelegate.persistenceContainer)
}
func getMealCount() -> Int {
return fetchedResultsController.fetchedObjects?.count ?? 0
}
func getMeal(at indexPath: IndexPath) -> Meal {
return fetchedResultsController.object(at: indexPath)
}
//The boolean determines whether historical or future data is shown
func reloadAllLocalData(for tense: Tense){
let fetchRequest: NSFetchRequest<Meal> = Meal.fetchRequest()
//Setting predicate, etc.
//<...>
fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: backgroundMOC, sectionNameKeyPath: nil, cacheName: nil)//Add cache to this?
do {
try fetchedResultsController.performFetch()
} catch let error {
//<...>
}
}
//Saving
func saveLocalMeal(mealType: Int16, date: NSDate, mealDescription: String, servings: Int16, image: UIImage?, favorite: Bool, comment: String? = nil, recipeUID: String? = nil) -> Meal? {
//Make new meal object
let meal = Meal(entity: Meal.entity(), insertInto: backgroundMOC)
//Call helper func and result result
return save(context: backgroundMOC, meal: meal, mealUID: nil, mealType: mealType, date: date, mealDescription: mealDescription, servings: servings, image: image, favorite: favorite, comment: comment, recipeUID: recipeUID)
}
private func save(context: NSManagedObjectContext, meal: Meal, mealUID: String?, mealType: Int16, date: NSDate, mealDescription: String, servings: Int16, image: UIImage?, favorite: Bool, comment: String? = nil, recipeUID: String? = nil) -> Meal? {
//Setting properties
//<...>
do {
try backgroundMOC.save()
return meal
} catch let error as NSError {
print("Could not save. \(error)")
return nil
}
}
I followed the guide on Realm's website, but my test are still producing varying results, depending on the random order they are done.
Either they succeed when run individually, or fail because the data was already set. For example:
XCTAssert(observer.events[0].value.element == "", "Initail hub name is expected to be equal to be an empty string but was \(String(describing: observer.events[0].value.element))")
XCTAssert(observer.events[1].value.element == testHubName, "Initail hub name is expected to be equal to be the name we set but was \(String(describing: observer.events[1].value.element))")
In this example, event[0] is already set to testHubName.
Or it gets a #throw RLMException(#"Object has been deleted or invalidated.");
So I guess there is some kind race going around, but this is in my setup method:
func setupRealm() {
testRealm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "DORSessionViewModelTestsRealm"))
try! self.testRealm.write {
self.testRealm.deleteAll()
}
}
So as far as I understand I should have a fresh Realm for every test, so where is the race going on?
Edit:
Adding a bigger part of the class
class DORSessionViewModelTests: XCTestCase {
var disposeBag: DisposeBag = DisposeBag()
var scheduler = TestScheduler(initialClock: 0)
var testRealm: Realm!
override func setUp() {
super.setUp()
setupRealm()
setupRx()
}
override func tearDown() {
super.tearDown()
}
func testHubNameLabelTextUpdate() {
let expectation = self.expectation(description: "expect hub name text to update")
let testHubName = "testHubName"
let viewModel = getSessionViewModel()
let observer = scheduler.createObserver(String.self)
scheduler.start()
let hubNameDriver = viewModel.hubNameLabelText()
hubNameDriver.asObservable().subscribe(observer).disposed(by: disposeBag)
hubNameDriver.asObservable().skip(1).subscribeNext { _ in expectation.fulfill()}.disposed(by: disposeBag)
try! self.testRealm.write {
viewModel.dependencies..hub.name = testHubName
}
waitForExpectations(timeout: 5, handler: { error in
XCTAssert(observer.events[0].value.element == "", "Initail hub name is expected to be equal to be an empty string but was \(String(describing: observer.events[0].value.element))")
XCTAssert(observer.events[1].value.element == testHubName, "Initail hub name is expected to be equal to be the name we set but was \(String(describing: observer.events[1].value.element))")
})
}
func setupRx() {
disposeBag = DisposeBag()
scheduler = TestScheduler(initialClock: 0)
}
Hi just wondering if this is possible, i have a simple counter app where a counter variable is incremented by 1 every time a button is pushed. is it possible to save the counter when the user exits the app using core data? i know NSUserdefaults would work here but im exploring core data and was wondering if it could be used in cases like this
class ViewController: UIViewController {
var counter = Int()
#IBOutlet var label: UILabel!
#IBAction func button(sender: AnyObject) {
counter += 1
label.text = "\(counter)"
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
NSManagedObject subclass Error
class IntegerEntity: NSManagedObject {
convenience init(entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?, value: Int) {
self.init(entity: entity, insertIntoManagedObjectContext: context)
self.value
// ERROR value of type IntegerEntity has no member value
}
}
ViewController.swift errors
import UIKit
import CoreData
class ViewController: UIViewController {
var counter = Int()
#IBOutlet var label: UILabel!
#IBAction func button(sender: AnyObject) {
counter += 1
label.text = "\(counter)"
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
let dataContext: NSManagedObjectContext! = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext
var integerEntity: IntegerEntity!
if dataContext != nil {
let entity = NSEntityDescription.entityForName("IntegerEntity", inManagedObjectContext: dataContext)
let request = NSFetchRequest()
request.entity = entity
let integer = try? dataContext.executeFetchRequest(request)
if integer != nil && !integer!.isEmpty {
(integer?.first! as! IntegerEntity).value = counter
// ERROR value of type IntegerEntity has no member value
} else {
let newInt = IntegerEntity(entity: entity, insertIntoManagedObjectContext: context, value: counter)
// ERROR Use of unresolved identifier context
dataContext.saveData()
}
}
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let dataContext: NSManagedObjectContext! = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext
var integerEntity: IntegerEntity!
if dataContext != nil {
let entity = NSEntityDescription.entityForName("IntegerEntity", inManagedObjectContext: dataContext)
let request = NSFetchRequest()
request.entity = entity
let integer = try? dataContext.executeFetchRequest(request)
if integer != nil && !integer!.isEmpty {
counter = (integer!.first! as! IntegerEntity).value
// ERROR value of type IntegerEntity has no member value
} else {
counter = 0
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension NSManagedObjectContext {
func saveData() -> Bool {
do {
try self.save()
return true
} catch let error as NSError {
print(error)
return false;
}
}
}
This is possible.
First, create a Core Data model and add an entity called IntegerEntity. In the entity, add a property called value whose type is Integer 64. Now generate the NSManagedObject subclass.
In IntegerEntity,swift, add the following initializer:
convenience init(entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?, value: Int) {
self.init(entity: entity, insertIntoManagedObjectContext: context)
self.value = value
}
This is because later on, we can use this directly to create an entity with a value.
I suppose your app has only one view controller, so you have two options of when to save the data:
Use an NSTimer to save the data every 60 seconds or some other time interval
override viewDidDisappear in the view controller or applicationWillResignActive in the app delegate.
To save the data, you first need to get the saved integer back (if present).
// Just some boilerplate code here
let dataContext: NSManagedObjectContext! = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext
var integerEntity: IntegerEntity!
if dataContext != nil {
let entity = NSEntityDescription.entityForName("IntegerEntity", inManagedObjectContext: dataContext)
let request = NSFetchRequest()
request.entity = entity
let integer = try? dataContext.executeFetchRequest(request)
// If some integer has already been saved...
if integer != nil && !integer.isEmpty {
(integer?.first! as! IntegerEntity).value = counter
} else {
// If no integer has been saved before...
let newInt = IntegerEntity(entity: entity, insertIntoManagedObjectContext: context, value: counter)
dataContext.saveData()
}
}
You may be wondering, what's saveData? I think my version of Xcode has a bug. Xcode always insists that save() method throws an error and returns Void. So I created this extension:
extension NSManagedObjectContext {
func saveData() -> Bool {
do {
try self.save()
return true
} catch let error as NSError {
print(error)
return false;
}
}
}
And BOOM! that's it!
"But how do I fetch the data back?" you asked. Actually, you did it before! Here's the code:
let dataContext: NSManagedObjectContext! = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext
var integerEntity: IntegerEntity!
if dataContext != nil {
let entity = NSEntityDescription.entityForName("IntegerEntity", inManagedObjectContext: dataContext)
let request = NSFetchRequest()
request.entity = entity
let integer = try? dataContext.executeFetchRequest(request)
// If some integer has already been saved...
if integer != nil && !integer.isEmpty {
counter = (integer!.first! as! IntegerEntity).value.integerValue
} else {
// If no integer has been saved before...
counter = 0
}
}
Looks familiar? It's almost the same code as before!
WARNING
IMO, it's not worth it to write so much code just to save one single integer, just so you know. Use user defaults instead. If you want to explore Core Data, you can try saving lists of words in Core Data. And with the press of a button , AVSpeechSynthesizer read them all aloud.
these days I start to learn ios applications development using SWIFT language
so I started to build my own app which contain forms that collect information from users and save\retrieve it to\from core data
my home page hide/show its buttons depending on data retrieved from the core data and do simple check on it so the data have to be up to date to avoid mistakes
but when I add user to the Core data and return to the home page it show the buttons as nothing has been added but if leave the home page to other page and then back to home page then the last user added appears
it seems like the context did not finish the data saving before the home appears
How I can fix that and ensure that the context object finish saving then show the home page
thanks a lot
Please keep in mind that waiting for context to save before performing segue might be not the best solution - depending on task it can take a long time. If use this approach you should show some progress indicator to user or smth.
Otherwise it will look like your app UI is freezing and that is a bad UX.
Anyway answering your question you have 3 basic solutions :
use competition closure
use delegation
use notifications
I assume you use some sort of custom class to load the CoreData Stack and you probably have function for saving context. Than it might look like this :
private func saveContext(completition : (()->() )?) {
if let moc = self.context {
var error : NSError? = nil
if moc.hasChanges && !moc.save(&error){
println(error?.localizedDescription)
abort()
}
//Call delegate method
delegate?.MiniCoreDataStackDidSaveContext()
//Send notification message
defaultCenter.postNotificationName("MyContextDidSaveNotification", object: self)
//Perform completition closure
if let closure = completition {
closure()
}
}
}
And you use it like this :
MyCoreDataStack.saveContext(){
performSegueWithIdentifier(SEGUE_ID,nil)
}
or
NSNotificationCenter.defaultCenter().addObserverForName("MyContextDidSaveNotification",
object: MyCoreDataStack.saveContext,
queue: NSOperationQueue.mainQueue(),
usingBlock: { _ in performSegueWithIdentifier(SEGUE_ID, sender: nil) }
)
In case you don't have any Stack - I've written this small singleton class as an example it lacks of proper error handling etc.
In a private function saveContext it combines all three approaches (it's only for example, I would not advice to use delegation with singleton pattern)
import CoreData
protocol MiniCoreDataStackDelegate : class {
func MiniCoreDataStackDidSaveContext()
}
#objc(MiniCoreDataStack)
class MiniCoreDataStack {
struct Constants {
static let persistentStoreName = "Store"
static let contextSaveNotification = "MiniCoreDataStackDidSaveContextNotification"
}
private var managedObjectModel : NSManagedObjectModel
private var persistentStoreCoordinator : NSPersistentStoreCoordinator? = nil
private var store : NSPersistentStore?
private let defaultCenter = NSNotificationCenter.defaultCenter()
var defaultContext : NSManagedObjectContext!
var stackIsLoaded : Bool = false
weak var delegate : MiniCoreDataStackDelegate?
class var defaultModel: NSManagedObjectModel {
return NSManagedObjectModel.mergedModelFromBundles(nil)!
}
class var sharedInstance: MiniCoreDataStack {
struct Singleton {
static let instance = MiniCoreDataStack()
}
return Singleton.instance
}
class func storesDirectory() -> NSURL {
let applicationDocumentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory,inDomains: .UserDomainMask).last as! NSURL
return applicationDocumentsDirectory
}
private func storeURLForName(name:String) -> NSURL {
return MiniCoreDataStack.storesDirectory().URLByAppendingPathComponent("\(name).sqlite")
}
func localStoreOptions() -> NSDictionary {
return [
NSInferMappingModelAutomaticallyOption:true,
NSMigratePersistentStoresAutomaticallyOption:true
]
}
init( model : NSManagedObjectModel = MiniCoreDataStack.defaultModel){
managedObjectModel = model
}
func openStore(completion:(()->Void)?) {
println("\(NSStringFromClass(self.dynamicType)): \(__FUNCTION__)")
var error: NSError? = nil
let tempPersistenStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
if let newStore = tempPersistenStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: self.storeURLForName(Constants.persistentStoreName), options: self.localStoreOptions() as [NSObject : AnyObject], error: &error){
self.persistentStoreCoordinator = tempPersistenStoreCoordinator
defaultContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
defaultContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
defaultContext.persistentStoreCoordinator = persistentStoreCoordinator
self.stackIsLoaded = true
println("\(NSStringFromClass(self.dynamicType)): Store loaded")
if let completionClosure = completion {
completionClosure()
}
} else {
println("\(NSStringFromClass(self.dynamicType)): !!! Could not add persistent store !!!")
println(error?.localizedDescription)
}
}
private func saveContext(context: NSManagedObjectContext? = MiniCoreDataStack.sharedInstance.defaultContext!, completition : (()->() )?) {
if !self.stackIsLoaded {
return
}
if let moc = context {
var error : NSError? = nil
if moc.hasChanges && !moc.save(&error){
println(error?.localizedDescription)
abort()
}
//Call delegate method
delegate?.MiniCoreDataStackDidSaveContext()
//Send notification message
defaultCenter.postNotificationName(Constants.contextSaveNotification, object: self)
//Perform completition closure
if let closure = completition {
closure()
}
}
}
func save(context: NSManagedObjectContext? = MiniCoreDataStack.sharedInstance.defaultContext!,completition : (()->() )? ) {
//Perform save on main thread
if (NSThread.isMainThread()) {
saveContext(context: context,completition: completition)
}else {
NSOperationQueue.mainQueue().addOperationWithBlock(){
self.saveContext(context: context, completition : completition)
}
}
}
func fetchResultsControllerForEntity(entity : NSEntityDescription, predicate :NSPredicate? = nil, sortDescriptors:[NSSortDescriptor]? = nil, sectionNameKeyPath:String? = nil, cacheName: String? = nil,inManagedContext context : NSManagedObjectContext? = nil ) ->NSFetchedResultsController {
let fetchRequest = NSFetchRequest()
fetchRequest.entity = entity
fetchRequest.sortDescriptors = sortDescriptors
fetchRequest.predicate = predicate
fetchRequest.fetchBatchSize = 25
var aContext = context ?? self.defaultContext!
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: aContext, sectionNameKeyPath: sectionNameKeyPath, cacheName: cacheName)
var error: NSError?
if !fetchedResultsController.performFetch(&error){
println("Could not fetch : \(error)")
}
return fetchedResultsController
}
func executeFetchRequest(request : NSFetchRequest, context: NSManagedObjectContext? = nil) -> [NSManagedObject] {
var fetchedObjects = [NSManagedObject]()
let managedContext = context ?? defaultContext
managedContext?.performBlockAndWait{
var error: NSError?
if let result = managedContext?.executeFetchRequest(request, error: &error) {
if let managedObjects = result as? [NSManagedObject] {
fetchedObjects = managedObjects
}
}
if let err = error{
println(err)
}
}
return fetchedObjects
}
func insertEntityWithClassName(className :String, andAttributes attributesDictionary : NSDictionary? = nil, andContext context : NSManagedObjectContext = MiniCoreDataStack.sharedInstance.defaultContext ) -> NSManagedObject {
let entity = NSEntityDescription.insertNewObjectForEntityForName(className, inManagedObjectContext: context) as! NSManagedObject
if let attributes = attributesDictionary {
attributes.enumerateKeysAndObjectsUsingBlock({
(dictKey : AnyObject!, dictObj : AnyObject!, stopBool) -> Void in
entity.setValue(dictObj, forKey: dictKey as! String)
})
}
return entity
}
func deleteEntity(entity: NSManagedObject){
self.defaultContext!.deleteObject(entity)
}
}
Using Stack :
//Open store
MiniCoreDataStack.sharedInstance.openStore()
//Insert Entity
let newEntity = MiniCoreDataStack.sharedInstance.insertEntityWithClassName(YourEntityName)
//Saving
MiniCoreDataStack.sharedInstance.save(){
// completition closure
}
//Perform fetch request
MiniCoreDataStack.sharedInstance.executeFetchRequest(YourFetchRequest)