Right way to Save Data in Sandbox

The Sandbox makes me wild. I writing a Mac App that save Images in different sizes to a User Selected Folder.

If i am use it without Sandbox the Images will be saved at a User Selected Directory. If i am Switch on the Sandbox

my Images will never saved at the User Selected Directory.

if(!(myImage)){
            [self message:@"Warning!" message:@"Please load a Image first"];
        }else{
            NSSavePanel *save = [NSSavePanel savePanel];
            [save setCanCreateDirectories:YES];
            [save setNameFieldStringValue:OSString];
            [save setTitle:@"Load Image"];
            [save setPrompt:@"Select"];
            [save beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {
                if (result == NSFileHandlingPanelOKButton) {
                    // We aren't allowing multiple selection, but NSOpenPanel still returns
                    // an array with a single element.
                    saveName = [save nameFieldStringValue];
                    NSURL* appDirectory = [save URL];
                    saveURL = appDirectory;
                    NSLog(@"Speicher Ort %@",appDirectory);
                    [self saveImage:myImage toPixelDimensions:NSMakeSize(128, 128) path:saveURL];
                } else {
                    [save close];
                }
            }];
          }


Can someone tell me that is the right way to save a Image in Sandbox?
I know in Sandbox it have the ~/Library/Containers , but it will never Save anything.

The Entitlement for read / write Userselected is set.

Replies

There is no difference in saving to a user-chosen directory (chosen via NSSavePanel) when your app is sandboxed. The file isn't saved inside the sandbox in that case — it's saved in the place the user chose.


My guess is that you're changing the URL inside the saveImage:toPixelDimensions:path: method (which is where the save happens, not this code), and you're not allowed to save to a different URL when sandboxed (since the user didn't choose it).


You need to work backwards from the point at which the save fails — there should be a message logged — to the URL you're actually trying to save to, then to the URL the user actually chose.

I do not change the URL in the methode, i got the right url that the user have chosen. If i Chose the User Document Folder the Image Could not save. Is the Entitlement, if i use select the Picture Folder, only Restricted to the Picture Folder or can i use another User Directory like the Document Folder or write the Desktop? Here i got the same error. This sandmoxing makes me crazy. If i want to save into my User Folder i want choose the Folder and not only the Picture Folder.


This is a output of my App: (If i use the the Picturefolder of the User):

iPhone

2018-08-19 11:31:30.740 ImageToAsset[27279:1981176] Real Folder:/Volumes/UserDisk/users/sven

2018-08-19 11:31:38.192 ImageToAsset[27279:1981176] Speicher Ort file:///Volumes/UserDisk/users/sven/Pictures/iPhone

2018-08-19 11:31:38.192 ImageToAsset[27279:1981176] Absoluter String from NSURL file:///Volumes/UserDisk/users/sven/Pictures/iPhone

2018-08-19 11:31:38.192 ImageToAsset[27279:1981176] FileName iPhone

2018-08-19 11:31:38.210 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Pictures/iPhone20@2x.png

2018-08-19 11:31:38.216 ImageToAsset[27279:1981176] Gespeichert

2018-08-19 11:31:38.216 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Pictures/iPhone20@2x.png

2018-08-19 11:31:38.234 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Pictures/iPhone20@3x.png

2018-08-19 11:31:38.236 ImageToAsset[27279:1981176] Gespeichert

2018-08-19 11:31:38.236 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Pictures/iPhone20@3x.png

2018-08-19 11:31:38.254 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Pictures/iPhone29@2x.png

2018-08-19 11:31:38.256 ImageToAsset[27279:1981176] Gespeichert

2018-08-19 11:31:38.256 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Pictures/iPhone29@2x.png

2018-08-19 11:31:38.275 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Pictures/iPhone29@3x.png

2018-08-19 11:31:38.276 ImageToAsset[27279:1981176] Gespeichert

2018-08-19 11:31:38.276 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Pictures/iPhone29@3x.png

2018-08-19 11:31:38.295 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Pictures/iPhone40@2x.png

2018-08-19 11:31:38.296 ImageToAsset[27279:1981176] Gespeichert

2018-08-19 11:31:38.296 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Pictures/iPhone40@2x.png

2018-08-19 11:31:38.318 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Pictures/iPhone40@3x.png

2018-08-19 11:31:38.320 ImageToAsset[27279:1981176] Gespeichert

2018-08-19 11:31:38.320 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Pictures/iPhone40@3x.png

2018-08-19 11:31:38.323 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Pictures/iPhone60@2x.png

2018-08-19 11:31:38.324 ImageToAsset[27279:1981176] Gespeichert

2018-08-19 11:31:38.324 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Pictures/iPhone60@2x.png

2018-08-19 11:31:38.350 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Pictures/iPhone60@3x.png

2018-08-19 11:31:38.352 ImageToAsset[27279:1981176] Gespeichert

2018-08-19 11:31:38.352 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Pictures/iPhone60@3x.png


and this is than i am try to save it into my Document/test folder

Real Folder:/Volumes/UserDisk/users/sven

2018-08-19 11:34:00.036 ImageToAsset[27279:1981176] Speicher Ort file:///Volumes/UserDisk/users/sven/Documents/test/iPhone

2018-08-19 11:34:00.036 ImageToAsset[27279:1981176] Absoluter String from NSURL file:///Volumes/UserDisk/users/sven/Documents/test/iPhone

2018-08-19 11:34:00.036 ImageToAsset[27279:1981176] FileName iPhone

2018-08-19 11:34:00.053 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Documents/test/iPhone20@2x.png

2018-08-19 11:34:00.055 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Documents/test/iPhone20@2x.png

2018-08-19 11:34:00.055 ImageToAsset[27279:1981176] Fehler

2018-08-19 11:34:00.073 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Documents/test/iPhone20@3x.png

2018-08-19 11:34:00.075 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Documents/test/iPhone20@3x.png

2018-08-19 11:34:00.075 ImageToAsset[27279:1981176] Fehler

2018-08-19 11:34:00.093 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Documents/test/iPhone29@2x.png

2018-08-19 11:34:00.095 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Documents/test/iPhone29@2x.png

2018-08-19 11:34:00.095 ImageToAsset[27279:1981176] Fehler

2018-08-19 11:34:00.114 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Documents/test/iPhone29@3x.png

2018-08-19 11:34:00.117 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Documents/test/iPhone29@3x.png

2018-08-19 11:34:00.117 ImageToAsset[27279:1981176] Fehler

2018-08-19 11:34:00.136 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Documents/test/iPhone40@2x.png

2018-08-19 11:34:00.138 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Documents/test/iPhone40@2x.png

2018-08-19 11:34:00.138 ImageToAsset[27279:1981176] Fehler

2018-08-19 11:34:00.140 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Documents/test/iPhone40@3x.png

2018-08-19 11:34:00.142 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Documents/test/iPhone40@3x.png

2018-08-19 11:34:00.142 ImageToAsset[27279:1981176] Fehler

2018-08-19 11:34:00.144 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Documents/test/iPhone60@2x.png

2018-08-19 11:34:00.145 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Documents/test/iPhone60@2x.png

2018-08-19 11:34:00.145 ImageToAsset[27279:1981176] Fehler

2018-08-19 11:34:00.171 ImageToAsset[27279:1981176] file:///Volumes/UserDisk/users/sven/Documents/test/iPhone60@3x.png

2018-08-19 11:34:00.173 ImageToAsset[27279:1981176] Speichernamefile:///Volumes/UserDisk/users/sven/Documents/test/iPhone60@3x.png

2018-08-19 11:34:00.173 ImageToAsset[27279:1981176] Fehler


The File should not be saved.

I try to use a selected Folder on my Second Drive, there is the same isue. I can‘t save anything. Is this a Bug. When it meens userselected folder and i cant save anything on it, it is for nothing.

if i set the Fileacces in my Project User Select Files, Download Folder , Picture Folder , Musik Folder and Movie Folder to read / write i could save it only in this folders my Pictures. But this is not that i thing if there user selected files read write or selected folder means.

I think if the User will save it in a another location as in the Sandbox defind Folder, this is not a Option. The Restriction is to Restricted.

Let's ignore all the distractions you've thrown into this, and go back the original problem:


You want to save a file at a user-specified location. The correct way to do that is:


1. Use NSSavePanel to get a URL for the location chosen by the user. For the sake of this discussion, let's assume the user chooses the Documents folder to save into.


2. You write a file to that URL.


That's it! This works whether your app is sandboxed or not. (Well, if sandboxed, you need to turn on the "User Selected File: Read/Write" capability, but you said you did that.) I just tried this is a new project, just to make sure that I wasn't missing anything, and it worked both sandboxed and unsandboxed.


There is no saving "in" or "into" the sandbox container in this scenario. In both cases, the URL will look like this:


file:///Users/username/Documents/filename


So, you've done something else, based on an incorrect assumption about what you "should" be doing. The following may help to get this sorted out:


— Please log the URL that you're getting from NSSavePanel.


— Please show us the code you're using to write the file. (Specifically, what API are you using to write the file?) The code you posted above isn't the site of the problem.


— Please log the NSError returned by your file-writing API if it fails.


— Copy everything that was logged (the url, the NSError description, and any other failure messages logged by the system) into a post here.


Final note: When dealing with user-chosen locations (via NSSavePanel), the sandbox container isn't involved at all. On the Mac, the interior of the container is not intended to be a user-visible location.

This is the save routine. They scale a Image and should write it to a User Selected or User Selected Folder that the User can create via the SavePanel.

- (void)saveImage:(NSImage *)sourceImage toPixelDimensions:(NSSize)newSize path:(NSURL*)myUrl filename:(NSString*)newFileName
{
    
    NSLog(@"Absoluter String from NSURL %@",[myUrl absoluteString]);
    NSLog(@"FileName %@",newFileName);
    
    
    NSInteger index = 0;
    for (NSString *line in sizeTable) {
        NSArray *sizeArray = [line componentsSeparatedByString:@"x"];
        NSUInteger sizex = [[sizeArray objectAtIndex:0] integerValue];
        NSUInteger sizey = [[sizeArray objectAtIndex:1] integerValue];
        
        //NSLog(@"%lu , %lu",sizex,sizey);
        
        NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
                                 initWithBitmapDataPlanes:NULL
                                 pixelsWide:sizex//newSize.width
                                 pixelsHigh:sizey//newSize.height
                                 bitsPerSample:8
                                 samplesPerPixel:4
                                 hasAlpha:YES
                                 isPlanar:NO
                                 colorSpaceName:NSCalibratedRGBColorSpace
                                 bytesPerRow:0
                                 bitsPerPixel:0];
        rep.size = newSize;
        
        [NSGraphicsContext saveGraphicsState];
        [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:rep]];
        [sourceImage drawInRect:NSMakeRect(0, 0, newSize.width, newSize.height) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
        [NSGraphicsContext restoreGraphicsState];
        
        NSImage *newImage = [[NSImage alloc] initWithSize:newSize];
        [newImage addRepresentation:rep];
        NSData* pngData = [rep representationUsingType:NSPNGFileType properties:@{}];
        
        NSString *newURLString = [[NSString alloc] initWithString:[myUrl absoluteString]];
        
        NSString *saveFileString = [[NSString alloc]initWithString:newURLString];
        NSString *saveFileName = [NSString stringWithFormat:@"%@%@.png",saveFileString,[nameTable objectAtIndex:index]];
        
        NSLog(@"%@",saveFileName);
        
        BOOL test = [pngData writeToURL:[NSURL URLWithString:saveFileName] atomically:YES];
        
        if(test == true){
            NSLog(@"Gespeichert");
            NSLog(@"Speichername%@",saveFileName);
        }else{
            NSLog(@"Error request: Failed to save Images");
        }
        index = index  + 1;
    }
}

I changed th saveroutin to:

- (void)saveImage:(NSImage *)sourceImage toPixelDimensions:(NSSize)newSize path:(NSURL*)myUrl filename:(NSString*)newFileName
{
    
    NSLog(@"Absoluter String from NSURL %@",[myUrl absoluteString]);
    NSLog(@"FileName %@",newFileName);
    
    
    NSInteger index = 0;
    for (NSString *line in sizeTable) {
        NSArray *sizeArray = [line componentsSeparatedByString:@"x"];
        NSUInteger sizex = [[sizeArray objectAtIndex:0] integerValue];
        NSUInteger sizey = [[sizeArray objectAtIndex:1] integerValue];
        
        //NSLog(@"%lu , %lu",sizex,sizey);
        
        NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
                                 initWithBitmapDataPlanes:NULL
                                 pixelsWide:sizex//newSize.width
                                 pixelsHigh:sizey//newSize.height
                                 bitsPerSample:8
                                 samplesPerPixel:4
                                 hasAlpha:YES
                                 isPlanar:NO
                                 colorSpaceName:NSCalibratedRGBColorSpace
                                 bytesPerRow:0
                                 bitsPerPixel:0];
        rep.size = newSize;
        
        [NSGraphicsContext saveGraphicsState];
        [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:rep]];
        [sourceImage drawInRect:NSMakeRect(0, 0, newSize.width, newSize.height) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
        [NSGraphicsContext restoreGraphicsState];
        
        NSImage *newImage = [[NSImage alloc] initWithSize:newSize];
        [newImage addRepresentation:rep];
        NSData* pngData = [rep representationUsingType:NSPNGFileType properties:@{}];
        
        NSString *newURLString = [[NSString alloc] initWithString:[myUrl absoluteString]];
        
        NSString *saveFileString = [[NSString alloc]initWithString:newURLString];
        NSString *saveFileName = [NSString stringWithFormat:@"%@%@.png",saveFileString,[nameTable objectAtIndex:index]];
        
        NSLog(@"%@",saveFileName);
        NSError *myError;
        BOOL test = [pngData writeToFile:saveFileName options:NSDataWritingAtomic error:&myError];
        NSLog(@"%@",myError);
        
        //BOOL test = [pngData writeToURL:[NSURL URLWithString:saveFileName] atomically:YES];
        
        if(test == true){
            NSLog(@"Gespeichert");
            NSLog(@"Speichername%@",saveFileName);
        }else{
            NSLog(@"Error request: Failed to save Images %@",myError);
        }
        index = index  + 1;
    }
}

exist." UserInfo={NSFilePath=file:///Volumes/UserDisk/users/sven/Desktop/New/Test/iPhone%20Xcode%20Asset20@2x.png, NSUnderlyingError=0x6080000492a0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

Now i got this in the Consoleoutput:

FileName iPhone Xcode Asset

2018-08-23 12:38:45.926 ImageToAsset[2353:284688] file:///Volumes/UserDisk/users/sven/Desktop/New/Test/iPhone%20Xcode%20Asset20@2x.png

2018-08-23 12:38:45.932 ImageToAsset[2353:284688] Error Domain=NSCocoaErrorDomain Code=4 "The file “iPhone%20Xcode%20Asset20@2x.png” doesn’t exist." UserInfo={NSFilePath=file:///Volumes/UserDisk/users/sven/Desktop/New/Test/iPhone%20Xcode%20Asset20@2x.png, NSUnderlyingError=0x6080000492a0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

If am using that:


BOOL test = [pngData writeToURL:[NSURL URLWithString:saveFileName] options:NSDataWritingAtomic error:&myError];
        NSLog(@"%@",myError);
        
        //BOOL test = [pngData writeToURL:[NSURL URLWithString:saveFileName] atomically:YES];
        
        if(test == true){
            //NSLog(@"Gespeichert");
            NSLog(@"Saved as %@",[saveFileName stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]);
        }else{
            NSLog(@"Error request: Failed to save Images %@",myError);
        }


i get this Error:

2018-08-23 16:01:00.016 ImageToAsset[779:43332] Absoluter String from NSURL file:///Volumes/UserDisk/users/sven/Desktop/New/Test/iPhone%20Xcode%20Asset

2018-08-23 16:01:00.016 ImageToAsset[779:43332] FileName iPhone Xcode Asset

2018-08-23 16:01:00.034 ImageToAsset[779:43332] file:///Volumes/UserDisk/users/sven/Desktop/New/Test/iPhone%20Xcode%20Asset20@2x.png

2018-08-23 16:01:00.073 ImageToAsset[779:43332] Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “iPhone Xcode Asset20@2x.png” in the folder “Test”." UserInfo={NSFilePath=/Volumes/UserDisk/users/sven/Desktop/New/Test/iPhone Xcode Asset20@2x.png, NSUnderlyingError=0x61000004bee0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

2018-08-23 16:01:00.073 ImageToAsset[779:43332] Error request: Failed to save Images Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “iPhone Xcode Asset20@2x.png” in the folder “Test”." UserInfo={NSFilePath=/Volumes/UserDisk/users/sven/Desktop/New/Test/iPhone Xcode Asset20@2x.png, NSUnderlyingError=0x61000004bee0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

2018-08-23 16:01:00.091 ImageToAsset[779:43332] file:///Volumes/UserDisk/users/sven/Desktop/New/Test/iPhone%20Xcode%20Asset20@3x.png

2018-08-23 16:01:00.096 ImageToAsset[779:43332] Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “iPhone Xcode Asset20@3x.png” in the folder “Test”." UserInfo={NSFilePath=/Volumes/UserDisk/users/sven/Desktop/New/Test/iPhone Xcode Asset20@3x.png, NSUnderlyingError=0x610000049b40 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

2018-08-23 16:01:00.096 ImageToAsset[779:43332] Error request: Failed to save Images Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “iPhone Xcode Asset20@3x.png” in the folder “Test”." UserInfo={NSFilePath=/Volumes/UserDisk/users/sven/Desktop/New/Test/iPhone Xcode Asset20@3x.png, NSUnderlyingError=0x610000049b40 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}


I Have enabled com.apple.security.files.user-selected.read-write to yes.

It (she) drives me crazy

I entered in the app entitlement the Following security option:


com.apple.security.temporary-exception.files.absolute-path.read-write set it as a string and the string content are /


That should work.