Could not delete core data PersistentStore - objective-c

I want to remove the app PersistentStore completely. I read the following question completely and none of them worked:
Delete/Reset all entries in Core Data?
I have a Model Helper and do the delete task inside it:
#import <CoreData/CoreData.h>
#interface GeneralModel : NSFetchedResultsController
#property (nonatomic, strong) NSManagedObjectContext *context;
#property (nonatomic, strong) NSManagedObjectModel *model;
- (NSString *)storagePath;
- (void)removeStorage;
- (void)removeStorage2;
#end
#implementation GeneralModel
- (instancetype)init
{
self = [super init];
if (self) {
// Read in Model.xcdatamodeld
_model = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *psc =
[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_model];
// Where does the SQLite file go?
NSString *path = self.storagePath;
NSURL *storeURL = [NSURL fileURLWithPath:path];
NSError *error = nil;
if (![psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:nil
error:&error]) {
#throw [NSException exceptionWithName:#"OpenFailure"
reason:[error localizedDescription]
userInfo:nil];
}
// Create the managed object context
_context = [[NSManagedObjectContext alloc] init];
_context.persistentStoreCoordinator = psc;
}
return self;
}
- (NSString *)storagePath
{
NSArray *documentDirectories =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
// Get one and only document directory from that list
NSString *documentDirectory = [documentDirectories firstObject];
return [documentDirectory stringByAppendingPathComponent:#"model.sqlite"];
}
- (void)removeStorage {
NSPersistentStore *store = [self.context.persistentStoreCoordinator.persistentStores lastObject];
NSError *error = nil;
NSURL *storeURL = store.URL;
BOOL isRemovePersistentStore = [self.context.persistentStoreCoordinator removePersistentStore:store error:&error];
if (isRemovePersistentStore == NO) {
NSLog(#"NO RemovePersistentStore. Reason: %#", error.localizedFailureReason);
}
BOOL isRemoveItemAtURL = [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];
if (isRemoveItemAtURL == NO) {
NSLog(#"NO RemoveItemAtURL. Reason: %#", error.localizedFailureReason);
}
}
- (void)removeStorage2 {
NSError *error;
NSString *storagePath = [self storagePath];
NSDictionary *options = #{NSPersistentStoreUbiquitousContentNameKey: #"model"};
bool removeResult = [NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:[NSURL URLWithString:storagePath] options:options error:&error];
if (removeResult == NO) {
NSLog(#"Could not remove Storage. Reason: %#", error.localizedFailureReason);
}
}
#end
When I call the "removeStorage" method by the following code:
GeneralModel *model = [[GeneralModel alloc] init];
[model removeStorage];
Result is that No error apear in the console, but it just removed the main storage file: "model.sqlite" and 2 other related files: "model.sqlite-shm" and "model.sqlite-wal" remained.
When I call the "removeStorage2" method by the same code, I see the following text on the console and none of the files deleted:
Could not remove Storage. Reason: (null)
How could I solve this problem?

Check out the video "Straight outta Moscone Center West" for the official introduction of how you should be doing this, and/or consult NSPersistentStoreCoordinator.h from which the following snippet was extracted.
/* delete or truncate the target persistent store in accordance with the store
class's requirements. It is important to pass similar options as
addPersistentStoreWithType: ... SQLite stores will honor file locks, journal
files, journaling modes, and other intricacies. It is not possible to unlink
a database file safely out from underneath another thread or process, so this
API performs a truncation. Other stores will default to using NSFileManager.
*/
- (BOOL)destroyPersistentStoreAtURL:(NSURL *)url
withType:(NSString *)storeType
options:(nullable NSDictionary *)options
error:(NSError**)error NS_AVAILABLE(10_11, 9_0);
/* copy or overwrite the target persistent store in accordance with the store
class's requirements. It is important to pass similar options as
addPersistentStoreWithType: ... SQLite stores will honor file locks, journal
files, journaling modes, and other intricacies. Other stores will default
to using NSFileManager.
*/
- (BOOL)replacePersistentStoreAtURL:(NSURL *)destinationURL
destinationOptions:(nullable NSDictionary *)destinationOptions
withPersistentStoreFromURL:(NSURL *)sourceURL
sourceOptions:(nullable NSDictionary *)sourceOptions
storeType:(NSString *)storeType
error:(NSError**)error NS_AVAILABLE(10_11, 9_0);

Related

Core Data isn't being reset when I close the calling class - how can I reset it?

This is a question that appears to have been answered many times on Stack Overflow - but still it doesn't work for my use-case. Core Data mostly works fine. The problem comes when closing the document - at that point I need the Core Data to be reset, ready for the next Document to be loaded. What actually happens is that the next Document to be loaded gets loaded with all of its data, and all of the previous Documents data - and it doesn't reset until the Application is quit and reopened again.
I have an NSDocument based application which can load many different document types. Each document type is described in its own Class. Foo, for example, might be a really simple document type, small, text based, no problem to handle so it doesn't need a complex class to load it. Bar, on the other hand, is a vast complicated database many GB in size - and it doesn't make sense to load it all into memory.
My Bar class uses Core Data - it's the only one that needs to, and therefore the only one which contains this logic. I mention this because nearly every description on how to use Core Data puts the Core Data code in App Delegate - there might be a good reason for this!
In my Bar header I have my Core Data set up as follows:
#property (nonatomic, strong, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, strong, readonly) NSDate *readStart;
And in my Bar .m I have the following:
- (NSURL *)dataStoreURL {
NSString *docDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
//NSString* filename = [NSString stringWithFormat:#"%#.sql",[StringWangers generateUUIDString]];
NSString* filename = #"datastore.sql";
return [NSURL fileURLWithPath:[docDir stringByAppendingPathComponent:filename]];
}
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel) {
return _managedObjectModel;
}
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator) {
return _persistentStoreCoordinator;
}
[NSFileManager.defaultManager removeItemAtURL:self.dataStoreURL error:nil]; // this isn't supposed to be persistent - clear out old crap
NSError *error = nil;
NSDictionary *options = #{NSMigratePersistentStoresAutomaticallyOption: #(YES), NSInferMappingModelAutomaticallyOption: #(YES)};
_persistentStoreCoordinator = [NSPersistentStoreCoordinator.alloc initWithManagedObjectModel:self.managedObjectModel];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:self.dataStoreURL
options:options
error:&error]) {
NSLog(#"Unresolved Core Data error with persistentStoreCoordinator: %#, %#", error, [error userInfo]);
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext) {
return _managedObjectContext;
}
if ([self persistentStoreCoordinator]) {
_managedObjectContext = [NSManagedObjectContext.alloc initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
}
return _managedObjectContext;
}
I've tried many things to delete this pesky data - including, belt and braces, everything (which I really don't like doing because I'd like to understand what's going on - but I was desperate!) - this is the 'everything' stateā€¦
-(void)deinitialise {
#try {
NSLog(#"Deleting old core storage");
NSArray *allEntities = self.managedObjectModel.entities;
for (NSEntityDescription *entityDescription in allEntities) {
NSFetchRequest *fetchRequest = NSFetchRequest.new;
[fetchRequest setEntity:entityDescription];
fetchRequest.includesPropertyValues = NO;
fetchRequest.includesSubentities = NO;
NSLog(#"%#",fetchRequest);
NSError *error = nil;
NSArray *items;
if (self.managedObjectContext &&
fetchRequest &&
([fetchRequest.sortDescriptors isKindOfClass:NSArray.class] && fetchRequest.sortDescriptors.count > 0) &&
fetchRequest.predicate) {
items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
}
if (error) {
NSLog(#"Error requesting items from Core Data: %#", error.localizedDescription);
}
for (NSManagedObject *managedObject in items) {
[self.managedObjectContext deleteObject:managedObject];
[self.managedObjectContext save:&error];
if (error) {
NSLog(#"Error deleting items from Core Data: %#", error.localizedDescription);
}
}
}
}
#catch (NSException *exception) {
NSLog(#"Error deleting persistent storage - Exception: %#", exception);
}
NSError *error = nil;
NSArray* persistentStoreArray = self.persistentStoreCoordinator.persistentStores;
for (id store in persistentStoreArray) {
[self.persistentStoreCoordinator removePersistentStore:store error:&error];
if (error) {
NSLog(#"Error Removing Persistent Store: %#", error.localizedDescription);
}
NSString* storePath = [store URL].path;
NSLog(#"%#",storePath);
[NSFileManager.defaultManager removeItemAtPath:storePath error:&error];
if (error) {
NSLog(#"Error Deleting Persistent Store: %#", error.localizedDescription);
}
}
self.persistentStoreCoordinator = nil;
}
Interestingly, - (NSPersistentStoreCoordinator *)persistentStoreCoordinator only gets called the first time that my Bar class is called on document load, but every time I call my reinitialise class.
Hopefully this makes sense to someone - 'cos I'm bang out of ideas.
Thank you to everyone who posted suggestions. They were great avenues of investigation - but they all turned out to be incorrect for my particular use-case. In the event, all I had to do was this:
-(void)deinitialise {
[self.managedObjectContext reset];
}
I hope that this might help someone else who has this problem.

Core Data without Master Detail Template

I want to create an iphone application which uses Core Data.
As i understood, only master-detail application template gives me an option to use Core Data. But it creates table view.
What i want to use is view controller not table view controller.
I couldnt use core data with single view application template..
Which way should I follow to overcome this issue?
Thanks.
You should realize that CoreData is a framework that is not bound to any UIKit components like UITableView. You can freely use it in any sort of an application. All you have to do is to create your singleton class that manages CoreData operations and add CoreData.framework to your project.
Here is my DataAccessLayer template:
DataAccessLayer.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface DataAccessLayer : NSObject
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (strong, nonatomic) NSPersistentStoreCoordinator *storeCoordinator;
+ (DataAccessLayer *)sharedInstance;
- (void)saveContext;
#end
DataAccessLayer.m
#import "DataAccessLayer.h"
#interface DataAccessLayer ()
- (NSURL *)applicationDocumentsDirectory;
#end
#implementation DataAccessLayer
#synthesize storeCoordinator;
#synthesize managedObjectModel;
#synthesize managedObjectContext;
+ (DataAccessLayer *)sharedInstance {
__strong static DataAccessLayer *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[DataAccessLayer alloc] init];
sharedInstance.storeCoordinator = [sharedInstance persistentStoreCoordinator];
sharedInstance.managedObjectContext = [sharedInstance managedObjectContext];
});
return sharedInstance;
}
#pragma mark - Core Data
- (void)saveContext {
#synchronized(self) {
NSError *error = nil;
if (managedObjectContext != nil)
{
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
NSLog(#"error: %#", error.userInfo);
/*
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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Oops!"
message:#"Something has gone terribly wrong! You need to reinstall the app in order for it to work properly."
delegate:nil
cancelButtonTitle:#"Close."
otherButtonTitles:nil, nil];
[alert show];
}
}
}
}
#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.
*/
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext != nil)
{
return managedObjectContext;
}
if (storeCoordinator != nil)
{
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:storeCoordinator];
}
return managedObjectContext;
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil)
{
return managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"DataModel" withExtension:#"momd"];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel;
}
/**
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.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (storeCoordinator != nil)
{
return storeCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"words_db.sqlite"];
NSError *error = nil;
storeCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
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:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Oops!"
message:#"Something has gone terribly wrong! You need to reinstall the app in order for it to work properly."
delegate:nil
cancelButtonTitle:#"Close."
otherButtonTitles:nil, nil];
[alert show];
}
return storeCoordinator;
}
#pragma mark Application's Documents directory
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#end
You will also have to create an .xcdatamodeld file in order to create your Data Model objects. And replace the name here with appropriate
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"DataModel" withExtension:#"momd"];

NSManagedObject fail to save it's attributes, but able to save when adding related objects

I'm developing an iOS app using Core Data. And I have a Log entity with one-to-many relationships with Audio, Photo entities, and one-to-one relationship with Status entity. The log also has text, longitude, latitude properties. I can create the log, change its properties, add status entity, these changes would display right, until I quit the App. All the changes would disappear, and I was looking at the sqlite database, all these changes were never persisted in the database. In the database, the status object will just be created, but not linked to the log object.
But if I add an audio or photo object into the log.audioSet or log.photoSet, the changes I made to log, including the changes to text or status, will suddenly be saved into the database.
So it seems the changes are only maintained in the NSManagedObjectContext, until a related one_to_many entity is added and the [[LTLogStore sharedStore] saveChanges] will suddenly start to work.
I am using a singleton to manage the NSManagedObjectContext. Any ideas?
I would post some code if it's relevant. Thanks.
UPDATE: I'm not sure these code is enough. But basically everything works, and displays, it just doesn't save to the database. I'm using the mogenerator to set the text and latitude, but since everything is in the context. I am not sure this is the code you might need.
CODE:
#interface LTLogStore : NSObject{
}
+ (LTLogStore *)sharedStore;
- (void)removeItem:(Log *)p;
- (Log *)createItem;
- (BOOL)saveChanges;
#property(nonatomic, strong) NSFetchedResultsController *resultsController;
#property(nonatomic, strong) NSManagedObjectModel *model;
#property(nonatomic, strong) NSManagedObjectContext *context;
#end
#implementation LTLogStore
#synthesize resultsController;
#synthesize context, model;
+ (LTLogStore *)sharedStore
{
static LTLogStore *sharedStore = nil;
if(!sharedStore){
sharedStore = [[super allocWithZone:nil] init];
}
return sharedStore;
}
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedStore];
}
- (id)init
{
self = [super init];
if(self) {
model = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *psc =
[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
// Where does the SQLite file go?
NSString *path = [self itemArchivePath];
NSURL *storeURL = [NSURL fileURLWithPath:path];
NSError *error = nil;
if (![psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:nil
error:&error]) {
[NSException raise:#"Open failed"
format:#"Reason: %#", [error localizedDescription]];
}
// Create the managed object context
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:psc];
// The managed object context can manage undo, but we don't need it
[context setUndoManager:nil];
}
return self;
}
- (NSFetchedResultsController *)resultsController {
if (resultsController !=nil) {
return resultsController;
}
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *e = [[model entitiesByName] objectForKey:#"Log"];
[request setEntity:e];
NSSortDescriptor *sd = [NSSortDescriptor
sortDescriptorWithKey:#"created_at"
ascending:NO];
[request setSortDescriptors:[NSArray arrayWithObject:sd]];
[request setReturnsObjectsAsFaults:NO];
NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest:request
managedObjectContext:context
sectionNameKeyPath:nil cacheName:#"Root"];
NSError *error;
BOOL success = [fetchedResultsController performFetch:&error];
if (!success) {
//handle the error
}
return fetchedResultsController;
}
- (NSString *)itemArchivePath
{
NSArray *documentDirectories =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
// Get one and only document directory from that list
NSString *documentDirectory = [documentDirectories objectAtIndex:0];
NSString *storePath = [documentDirectory stringByAppendingPathComponent:#"store.data"];
return storePath;
}
- (BOOL)saveChanges
{
NSError *err = nil;
BOOL successful = [context save:&err];
NSLog(#"Saving changes to the database");
if (!successful) {
NSLog(#"Error saving: %#", [err localizedDescription]);
}
return successful;
}
- (void)removeItem:(Log *)l
{
[context deleteObject:l];
[self saveChanges];
}
- (Log *)createItem
{
Log *p = [NSEntityDescription insertNewObjectForEntityForName:#"Log"
inManagedObjectContext:context];
[self saveChanges];
return p;
}
#end
#interface Log : _Log {
}
//these two are some custom convenience methods for location attributes, but it does the work of setting the longitude and latitude value in the log object, but calling the [[LTLogStore sharedStore] saveChanges] still won't save it into the database.
-(CLLocation*)location;
-(void)setLocation:(CLLocation*)location;
//this all works
-(Audio*)newAudio;
-(Audio*)newAudioWithPath:(NSString*)audioPath;
//after calling this method, even the log.text changes will be saved to the database.
-(void)addAudioWithPath:(NSString*)audioPath;
-(void)removeAudio:(Audio*)audio;
#end
#import "Log.h"
#import "Audio.h"
#import "LTLogStore.h"
#implementation Log
-(CLLocation*)location{
if (!self.longitude || !self.latitude) {
return nil;
}
CLLocation *l = [[CLLocation alloc] initWithLatitude:[self.latitude doubleValue] longitude:[self.longitude doubleValue]];
return l;
}
-(void)setLocation:(CLLocation*)location{
if (location==nil) {
self.latitude = nil;
self.longitude = nil;
}
self.latitude = [NSNumber numberWithDouble: location.coordinate.latitude];
self.longitude = [NSNumber numberWithDouble:location.coordinate.longitude];
[[LTLogStore sharedStore] saveChanges];
}
-(Audio*)newAudio{
Audio *a = [Audio new];
a.log = self;
return a;
}
-(Audio*)newAudioWithPath:(NSString*)audioPath{
Audio *new = [self newAudio];
[new setKey:audioPath];
return new;
}
-(void)addAudioWithPath:(NSString*)audioPath{
Audio *new = [self newAudio];
[new setKey:audioPath];
[[LTLogStore sharedStore] saveChanges];
}
-(void)removeAudio:(Audio*)audio{
[self.audiosSet removeObject:audio];
[[[LTLogStore sharedStore] context] deleteObject:audio];
[[LTLogStore sharedStore] saveChanges];
}
#end
UPDATE:
Problem solved, see answer.
UPDATE QUESTION: Why is my overriding causing the problem? Can someone explain the cause behind the magic of Core Data or maybe KVO behind scene?
Problem solved, I overrode the willChangeValueForKey method in the Log class, which caused the problem, I thought the code is irrelevant. But it IS:
- (void)willChangeValueForKey:(NSString *)key{
//I added the following line to fix my problem
[super willChangeValueForKey:key];
//this is the original line, I want to have this
//because I want to have a isBlank property
//so I can see if the user modified the log
_isBlank = false;
//I tried to also add the following line to be safe.
//turns out this line is not needed, and it will make the problem occur again
//[super didChangeValueForKey:key];
}

ASINetworkQueue requests always fails - ios

I'm facing a little bit of trouble finding whats wrong with my code, because I'm trying to download several images from different urls and the requests are always failing.
Could you guys give me a little help?
Here is my code:
//
// Chapters.h
//
//
// Created by Nuno Martins on 11/07/18.
// Copyright 2011 WeTouch. All rights reserved.
//
#import <Foundation/Foundation.h>
//#import <GHUnit/GHUnit.h>
#class ASINetworkQueue;
#interface Chapters : NSObject {
NSString * chaptersBaseUrl;
NSMutableArray * chaptersList;
ASINetworkQueue *networkQueue;
}
#property (retain) ASINetworkQueue *networkQueue;
#property (nonatomic, retain) NSString *chaptersBaseUrl;
#property (nonatomic, retain) NSMutableArray *chaptersList;
-(void)downloadChaptersIconsFromUrlArrayToFile:(NSMutableArray *)iconUrls;
#end
//
// Chapters.m
//
//
// Created by Nuno Martins on 11/07/18.
// Copyright 2011 WeTouch. All rights reserved.
//
#import "Chapters.h"
#import "Chapter.h"
#import "PDFDataAgregator.h"
#import "ASIHTTPRequest.h"
#import "ASINetworkQueue.h"
#implementation Chapters
#synthesize chaptersBaseUrl;
#synthesize chaptersList;
#synthesize networkQueue;
- (void)dealloc
{
[networkQueue release];
[super dealloc];
}
-(void)downloadChaptersIconsFromUrlArrayToFile:(NSMutableArray *)iconUrls
{
networkQueue = [[ASINetworkQueue alloc] init];
// Stop anything already in the queue before removing it
[networkQueue cancelAllOperations];
// Creating a new queue each time we use it means we don't have to worry about clearing delegates or resetting progress tracking
[networkQueue setDelegate:self];
[networkQueue setRequestDidFinishSelector:#selector(requestFinished:)];
[networkQueue setRequestDidFailSelector:#selector(requestFailed:)];
[networkQueue setQueueDidFinishSelector:#selector(queueFinished:)];
NSLog(#"Array-> %d", [iconUrls count]);
NSMutableArray *myIcons = [[NSMutableArray alloc] initWithArray:iconUrls];
//Create Chapters Folder
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [paths objectAtIndex:0];
NSString *newDir = [docDirectory stringByAppendingPathComponent:#"Chapters"];
[[NSFileManager defaultManager] createDirectoryAtPath:newDir withIntermediateDirectories:YES attributes:nil error: NULL];
for(unsigned i = 0; i < [myIcons count]; i++)
{
NSURL *url = [NSURL URLWithString:[myIcons objectAtIndex:i]];
NSString *fileName = [url lastPathComponent];
NSString *filePath = [newDir stringByAppendingPathComponent:fileName];
NSLog(#"Icon File Path: %#",filePath);
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:[iconUrls objectAtIndex:i]]];
[request setDownloadDestinationPath:filePath];
//[request setUserInfo:[NSDictionary dictionaryWithObject:#"request1" forKey:#"name"]];
[request setTemporaryFileDownloadPath:[filePath stringByAppendingPathExtension:#"download"]];
[request setAllowResumeForFileDownloads:YES];
[networkQueue addOperation:request];
}
[networkQueue go];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
// You could release the queue here if you wanted
if ([networkQueue requestsCount] == 0) {
// Since this is a retained property, setting it to nil will release it
// This is the safest way to handle releasing things - most of the time you only ever need to release in your accessors
// And if you an Objective-C 2.0 property for the queue (as in this example) the accessor is generated automatically for you
[self setNetworkQueue:nil];
}
//... Handle success
NSLog(#"Request finished");
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
// You could release the queue here if you wanted
NSLog(#"Number of requests in Queue %d", [networkQueue requestsCount]);
if ([networkQueue requestsCount] == 0) {
[self setNetworkQueue:nil];
}
//... Handle failure
NSLog(#"Request failed");
}
- (void)queueFinished:(ASINetworkQueue *)queue
{
// You could release the queue here if you wanted
if ([networkQueue requestsCount] == 0) {
[self setNetworkQueue:nil];
}
NSLog(#"Queue finished");
}
Well this was a problem related with Bad url format.
I was passing http:/somesite.com/someimage.png instead of passing http://somesite.com/someimage.png
I was missing the / because when I append a BaseUrl string to the filename using stringByAppending path Component it removes one slash of the HTTP://.
Solved now!

How to unit test my models now that I am using Core Data?

I have been developing an iphone application using a domain model, and have put off the persistence aspect of the app until now. Core Data looks like a really good solution since I already have a well defined model but I am running into a snag with my existing unit tests.
Here is simple example of what I have now:
- (void)test_full_name_returns_correct_string {
Patient *patient = [[Patient alloc] init];
patient.firstName = #"charlie";
patient.lastName = #"chaplin";
STAssertTrue([[patient fullName] isEqualToString:#"charlie chaplin"], #"should have matched full name");
}
How can I make this work once my Patient object extends from NSManagedObject and uses #dynamic for the firstName and lastName properties?
Has anyone else run into this type of this with Core Data? Thanks.
You need to build a Core Data stack, either within each method or in -setUp and then tear it down. Using an NSInMemoryPersistentStore will keep things fast and in-memory for your unit tests. Add a #property (nonatomic,retain) NSManagedObjectContext *moc to your TestCase subclass. Then:
- (void)setUp {
NSManagedObjectModel *mom = [NSManagedObjectModel mergedModelFromBundles:[NSArray arrayWithObject:bundleContainingXCDataModel]];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
STAssertTrue([psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:NULL] ? YES : NO, #"Should be able to add in-memory store");
self.moc = [[NSManagedObjectContext alloc] init];
self.moc.persistentStoreCoordinator = psc;
[mom release];
[psc release];
}
- (void)tearDown {
self.moc = nil;
}
Your test method then looks like:
- (void)test_full_name_returns_correct_string {
Patient *patient = [NSEntityDescription insertNewObjectForEntityForName:#"Person" inManagedObjectContext:self.moc];
patient.firstName = #"charlie";
patient.lastName = #"chaplin";
STAssertTrue([[patient fullName] isEqualToString:#"charlie chaplin"], #"should have matched full name");
}
assuming your entity is named Person. There was a memory leak in your version of the method, by the way; patient should be -release'd in the non-Core Data version (insertNewObjectForEntityForName:managedObjectContext: returns an autoreleased instance).
I used the answer above by Barry Wark, but I had to do some modifications to make it work with the current projects Xcode 5, iOS 7.
The property stayed the same:
#interface SIDataTest : XCTestCase
#property (nonatomic, retain) NSManagedObjectContext *moc;
#end
The setup had to actually had to change first of all to not release and secondly to provide a model URL.
- (void)setUp
{
[super setUp];
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"SimpleInvoice" withExtension:#"momd"];
NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
XCTAssertTrue([psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:NULL] ? YES : NO, #"Should be able to add in-memory store");
self.moc = [[NSManagedObjectContext alloc] init];
self.moc.persistentStoreCoordinator = psc;
}
Here is the example test case:
- (void)testCreateNew
{
Invoice *newInvoice = [NSEntityDescription insertNewObjectForEntityForName:#"Invoice" inManagedObjectContext:self.moc];
newInvoice.dueDate = [NSDate date];
NSString* title = [[NSString alloc] initWithFormat:#"Invoice %#", #112];
newInvoice.title = title;
// Save the context.
NSError *error = nil;
if (![self.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.
XCTFail(#"Error saving in \"%s\" : %#, %#", __PRETTY_FUNCTION__, error, [error userInfo]);
}
XCTAssertFalse(self.moc.hasChanges,"All the changes should be saved");
}