Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

iphonedude2008

macrumors 65816
Original poster
Nov 7, 2009
1,134
449
Irvine, CA
I am trying to save files to the sandbox. I have an object with an array, which has many arrays, which in turn contains arrays that contain nsstrings, nsurls, uiimages, and other media objects. All the objects implement nscoding or nssecurecoding. It will archive the objects to nsdata and i can unarchive it right there, but i can not save it to the disk. What is going on and how can i get it to save to the disk. I prefer to use archives, but if i absolutely have to, i can use core data.

heres the code for the model
Code:
//
//  CQStorageModel.h
//  White Nova
//
//  Created by Mark Hill on 12/4/12.
//  Copyright (c) 2012 Mark Hill. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface CQStorageModel : NSObject<NSCoding>

@property (strong, nonatomic) NSMutableArray *dataSource;
@property (strong, nonatomic) NSURL *savingUrl;


//methods for saving and retreaving the datasource
- (id) initWithDataSource;
- (void) saveDataSource;
- (id) refreshData;


//methods for adding projects to the datasource
- (void) addProject: (NSMutableArray *) arry withName: (NSString *) string;
- (void) removeProjectAtIndex: (NSUInteger) index;
- (NSString *) loadProjectNameAtIndex: (NSUInteger) index;


//methods for adding objects to the datasource
- (void) addObject: (id<NSCoding>) object withName: (NSString *)name toProjectAtIndex: (NSUInteger) index;
- (void) removeObjectAtIndex: (NSUInteger) index1 inProjectAtIndex: (NSUInteger) index2;
- (id) loadObjectAtIndex: (NSUInteger) index1 inProjectAtIndex: (NSUInteger) index2;
- (NSString *) loadNameAtIndex: (NSUInteger) index1 inProjectAtIndex: (NSUInteger) index2;


//methods for giving counts
- (NSUInteger) projectCount;
- (NSUInteger) objectCountInProject: (NSUInteger) projectNumber;


//refreshers
- (void) changeNotify;

@end
Code:
//
//  CQStorageModel.m
//  White Nova
//
//  Created by Mark Hill on 12/4/12.
//  Copyright (c) 2012 Mark Hill. All rights reserved.
//

#import "CQStorageModel.h"

@implementation CQStorageModel

@synthesize dataSource;


//compling with nscoding to save and retreave this object
- (void) encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.dataSource forKey:@"dataSource"];
    [aCoder encodeObject:self.savingUrl forKey:@"savingUrl"];
}

- (id) initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    self.dataSource = [aDecoder decodeObjectForKey:@"dataSource"];
    self.savingUrl = [aDecoder decodeObjectForKey:@"savingUrl"];
    return self;
}



//methods for saving and retreaving the datasource
- (id) initWithDataSource {
    self = [super init];
    if (self) {
        NSFileManager *fm = [[NSFileManager alloc]init];
        NSURL *appSupportUrl = [fm URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
        
        if (appSupportUrl == nil)
            appSupportUrl = [fm URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
        
        self.savingUrl = [appSupportUrl URLByAppendingPathComponent:@"CQStorageModel.cqstm"];
        [fm createDirectoryAtPath:self.savingUrl.path withIntermediateDirectories:YES attributes:nil error:nil];
        NSLog(@"%@", self.savingUrl.path);
        NSData *data = [[NSData alloc]initWithContentsOfURL:self.savingUrl];
        
        if (data)
        {
        self = [NSKeyedUnarchiver unarchiveObjectWithData:data];
        }
    
        self.dataSource = [NSMutableArray array];
        [self saveDataSource];
        NSLog(@"%@", self.savingUrl);
    }
    
    return self;
}

- (void) saveDataSource {
    BOOL ok = [NSKeyedArchiver archiveRootObject:self toFile:self.savingUrl.path];
    BOOL no = NO;
    //NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
    //[data writeToURL:self.savingUrl atomically:NO];
}

- (id) refreshData {
    id Data;
    NSFileManager *fm = [[NSFileManager alloc]init];
    NSURL *appSupportUrl = [fm URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
    
    if (!appSupportUrl)
        appSupportUrl = [fm URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
    
    self.savingUrl = [appSupportUrl URLByAppendingPathComponent:@"CQStorageModel.cqstm"];
    NSData *data = [[NSData alloc]initWithContentsOfURL:self.savingUrl];
    
    if (data)
    {
        Data = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    }
    
    [self saveDataSource];
    return Data;
}




//methods for adding projects to the datasource
- (void) addProject: (NSMutableArray *) arry withName: (NSString *) string {
    [arry insertObject:string atIndex:0];
    [self.dataSource addObject:arry];
    [self saveDataSource];
    [self changeNotify];
}

- (void) removeProjectAtIndex:(NSUInteger)index {
    if (self.dataSource != nil) {
    [self.dataSource removeObjectAtIndex:index];
    [self saveDataSource];
    }
    [self changeNotify];
}


//methods for adding objects to the datasource
- (void) addObject:(id<NSCoding>)object withName:(NSString *)name toProjectAtIndex:(NSUInteger)index {
    NSMutableArray *marray = [NSMutableArray array];
    
    if (name.length == 0)
        [marray insertObject:[NSString stringWithFormat:@"file %i", [[self.dataSource objectAtIndex:index] count]] atIndex:0];
    else
        [marray insertObject:name atIndex:0];
    
    [marray insertObject:object atIndex:1];
    [[self.dataSource objectAtIndex:index] addObject:marray];
    [self saveDataSource];
    [self changeNotify];
}

- (void) removeObjectAtIndex:(NSUInteger)index1 inProjectAtIndex:(NSUInteger)index2 {
    if (index1 != 0)
        [[self.dataSource objectAtIndex:index2] removeObjectAtIndex:index1];
    [self saveDataSource];
    [self changeNotify];
}

- (id) loadObjectAtIndex:(NSUInteger)index1 inProjectAtIndex:(NSUInteger)index2 {
    if (self.dataSource != nil) {
    id object = [[[self.dataSource objectAtIndex:index2] objectAtIndex:(index1 + 1)] objectAtIndex:1];
    return object;
    }
    else
        return nil;
}



//methods for getting names
- (NSString *) loadNameAtIndex:(NSUInteger)index1 inProjectAtIndex:(NSUInteger)index2 {
    if (self.dataSource != nil) {
            NSString *string = [[[self.dataSource objectAtIndex:index2] objectAtIndex:(index1 + 1)]objectAtIndex:0];
            return string;
    }
        return nil;
}

- (NSString *) loadProjectNameAtIndex:(NSUInteger)index {
    if (self.dataSource != nil && [self.dataSource count] > (index)) {
        NSString *strg = [[self.dataSource objectAtIndex:index] objectAtIndex:0];
        return strg;
    }
    else return @"";
}


//methods for giving counts

- (NSUInteger) projectCount {
    if (self.dataSource != nil) 
    return [self.dataSource count];
    else
        return 0;
}

- (NSUInteger) objectCountInProject:(NSUInteger)projectNumber {
    if (self.dataSource != nil && [self.dataSource count] != 0) {
        if ([self.dataSource objectAtIndex:projectNumber] != nil) {
            return ([[self.dataSource objectAtIndex:projectNumber] count] - 1);
        }
        }
        return 0;
}




//refresher

- (void) changeNotify {
    [[NSNotificationCenter defaultCenter]postNotificationName:@"data changed" object:self];
}


@end
 
Last edited:

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
Code:
//methods for saving and retreaving the datasource
- (id) initWithDataSource {
    self = [super init];
    if (self) {
        NSFileManager *fm = [[NSFileManager alloc]init];
        NSURL *appSupportUrl = [fm URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
        
        if (appSupportUrl == nil)
            appSupportUrl = [fm URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
        
        self.savingUrl = [appSupportUrl URLByAppendingPathComponent:@"CQStorageModel.cqstm"];
        [fm createDirectoryAtPath:self.savingUrl.path withIntermediateDirectories:YES attributes:nil error:nil];
- (void) saveDataSource {
    BOOL ok = [NSKeyedArchiver archiveRootObject:self toFile:self.savingUrl.path];
    BOOL no = NO;
    NSLog(@"%i", no);
    NSLog(@"hi %i", ok);
    //NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
    //[data writeToURL:self.savingUrl atomically:NO];
}


This looks sketchy to say the least. You set the savingURL. Then you create a directory at that path. That means you now have a directory called "CQStorageModel.cqstm" within the application support directory. This will prevent you writing a file with the same name...
 

iphonedude2008

macrumors 65816
Original poster
Nov 7, 2009
1,134
449
Irvine, CA
How should I fix it then? I don't quite understand what you said. I was trying to make a file inside the app support directory to save my model object to. Is that what I am doing and is there a better way?
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
How should I fix it then? I don't quite understand what you said. I was trying to make a file inside the app support directory to save my model object to. Is that what I am doing and is there a better way?

Break the following lines down, one at a time, explaining for each what you think it is doing (the lines numbered like (1)). Include where appropriate what the paths are, the log output and the expected change in the file system. You should see where the issue is (or you have not understood what the documentation says each method does):

Code:
//methods for saving and retreaving the datasource
- (id) initWithDataSource {
    self = [super init];
    if (self) {
        NSFileManager *fm = [[NSFileManager alloc]init];
(1)        NSURL *appSupportUrl = [fm URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
        
        if (appSupportUrl == nil)
(2)            appSupportUrl = [fm URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
        
(3)        self.savingUrl = [appSupportUrl URLByAppendingPathComponent:@"CQStorageModel.cqstm"];
(4)        [fm createDirectoryAtPath:self.savingUrl.path withIntermediateDirectories:YES attributes:nil error:nil];

...

- (void) saveDataSource {
(5)    BOOL ok = [NSKeyedArchiver archiveRootObject:self toFile:self.savingUrl.path];
(6)    BOOL no = NO;
(7)    NSLog(@"%i", no);
(8)    NSLog(@"hi %i", ok);
    //NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
    //[data writeToURL:self.savingUrl atomically:NO];
}
 

iphonedude2008

macrumors 65816
Original poster
Nov 7, 2009
1,134
449
Irvine, CA
I figured out it is a problem with this line in saveDataSource.

Code:
- (void) saveDataSource {
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
    NSError *err = nil;
    [data writeToFile:self.savingUrl.path options:NSDataWritingAtomic error:&err];
    NSLog(@"%@", [err localizedDescription]);
}

it prints out this

The operation couldn’t be completed. (Cocoa error 512.)
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
I figured out it is a problem with this line in saveDataSource.

Code:
- (void) saveDataSource {
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];
    NSError *err = nil;
    [data writeToFile:self.savingUrl.path options:NSDataWritingAtomic error:&err];
    NSLog(@"%@", [err localizedDescription]);
}

it prints out this

The operation couldn’t be completed. (Cocoa error 512.)

No, the error is where I've 1) told you and 2) guided you to work you for your self. This is just a symptom of the earlier error. If you worked through the lines I suggested you would see the issue.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.