blob: 24c585f6f5556cda48d2a0efc6c495ab07f253f7 [file] [log] [blame]
//
// NSManagedObjectContext+StoreMad.m
// StoreMad
//
// Created by Andrew Smith on 7/20/12.
// Copyright (c) 2012 Andrew B. Smith ( http://github.com/drewsmits ). All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#import "NSManagedObjectContext+StoreMad.h"
#import "StoreMad.h"
@implementation NSManagedObjectContext (StoreMad)
- (void)handleErrors:(NSError *)error
{
// Forget where I snagged this from
if (error) {
NSDictionary *userInfo = [error userInfo];
for (NSArray *detailedError in [userInfo allValues]) {
if ([detailedError isKindOfClass:[NSArray class]]) {
for (NSError *e in detailedError) {
if ([e respondsToSelector:@selector(userInfo)]) {
NSLog(@"Error Details: %@", [e userInfo]);
}
else {
NSLog(@"Error Details: %@", e);
}
}
}
else {
NSLog(@"Error: %@", detailedError);
}
}
NSLog(@"Error Domain: %@", [error domain]);
NSLog(@"Recovery Suggestion: %@", [error localizedRecoverySuggestion]);
}
}
#pragma mark - Thread
- (NSManagedObjectContext *)stm_threadSafeCopy
{
//
// Create new context with default concurrency type
//
NSManagedObjectContext *newContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[newContext setParentContext:self];
//
// Optimization. No undos in background thread.
//
[newContext setUndoManager:nil];
return newContext;
}
#pragma mark - Save
- (void)stm_save
{
NSError *error;
[self save:&error];
[self handleErrors:error];
}
- (void)stm_queueBlockSave
{
[self performBlock:^{
[self stm_save];
}];
}
- (void)stm_queueBlockSaveAndWait
{
[self performBlockAndWait:^{
[self stm_save];
}];
}
- (void)stm_queueBlockSaveOnParentContext
{
[self.parentContext performBlock:^{
[self.parentContext stm_save];
}];
}
#pragma mark - URI Helpers
- (NSManagedObject *)stm_objectForURI:(NSURL *)objectURI
{
NSManagedObjectID *objectID = [[self persistentStoreCoordinator] managedObjectIDForURIRepresentation:objectURI];
if (!objectID) return nil;
// If the object cannot be fetched, or does not exist, or cannot be faulted, existingObjectWithID returns nil
NSError *error;
NSManagedObject *object = [self existingObjectWithID:objectID
error:&error];
[self handleErrors:error];
return object;
}
#pragma mark - Delete
- (void)stm_deleteObjects:(NSArray *)objects
{
for (NSManagedObject *object in objects) {
[self deleteObject:object];
}
}
- (void)stm_deleteObjectAtURI:(NSURL *)objectURI
{
NSManagedObject *object = [self stm_objectForURI:objectURI];
if (!object) return;
[self deleteObject:object];
}
#pragma mark - Fetching
- (NSArray *)stm_executeFetchRequest:(NSFetchRequest *)request
{
NSError *error;
NSArray *results = [self executeFetchRequest:request error:&error];
[self handleErrors:error];
return results;
}
- (NSManagedObject *)stm_executeFetchRequestAndReturnFirstObject:(NSFetchRequest *)request
{
[request setFetchLimit:1];
NSArray *results = [self stm_executeFetchRequest:request];
if (results.count < 1) return nil;
return [results objectAtIndex:0];
}
- (NSUInteger)stm_countForFetchRequest:(NSFetchRequest *)request
{
// Optimization? I'd imagine it doesn't include these when counting, but
// should test.
request.includesPropertyValues = NO;
NSError *error;
NSUInteger count = [self countForFetchRequest:request error:&error];
[self handleErrors:error];
return count;
}
- (NSUInteger)stm_countForObjectClass:(Class)objectClass
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass(objectClass)];
return [self stm_countForFetchRequest:request];
}
- (NSArray *)stm_allValuesForProperty:(NSString *)propertyName
withRequest:(NSFetchRequest *)request
{
// This could be really slow. Use carefully.
NSDictionary *properties = request.entity.propertiesByName;
NSPropertyDescription *property = [properties objectForKey:propertyName];
if (!property) return nil;
[request setPropertiesToFetch:@[property]];
[request setResultType:NSDictionaryResultType];
NSArray *results = [self stm_executeFetchRequest:request];
NSMutableArray *propertyValuesList = [NSMutableArray arrayWithCapacity:results.count];
for (NSManagedObject *object in results) {
[propertyValuesList addObject:[object valueForKey:propertyName]];
}
return propertyValuesList;
}
#pragma mark - Fetch Requests
- (NSFetchRequest *)stm_fetchRequestForObjectNamed:(NSString *)objectName
{
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:objectName
inManagedObjectContext:self];
// Fetch request must have an entity
if (!entityDescription) return nil;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
return request;
}
- (NSFetchRequest *)stm_findAllFetchRequestForObjectNamed:(NSString *)objectName
{
NSFetchRequest *request = [self stm_fetchRequestForObjectNamed:objectName];
[request setPredicate:[NSPredicate predicateWithFormat:@"1 = 1"]];
return request;
}
- (NSFetchRequest *)stm_fetchRequestForObjectClass:(Class)objectClass;
{
return [self stm_fetchRequestForObjectNamed:NSStringFromClass(objectClass)];
}
- (NSFetchRequest *)stm_findAllFetchRequestForObjectClass:(Class)objectClass
{
return [self stm_findAllFetchRequestForObjectNamed:NSStringFromClass(objectClass)];
}
#pragma mark - Create
- (NSManagedObject *)stm_insertNewObjectForEntityNamed:(NSString *)entityName
{
// If entity is nil, initWithEntity will cause a crash. So make sure to bail.
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName
inManagedObjectContext:self];
if (!entity) return nil;
NSManagedObject *object = [[NSManagedObject alloc] initWithEntity:entity
insertIntoManagedObjectContext:self];
return object;
}
@end