Re: Managing image loading
Ok Jens, my method turned so complicated due to hundreds of relationships, undo, fileWrappers, copy/paste, new object IDs... That I'm going to do as you say. I am going to load the image and leave it within the NSView object. When I delete an NSView containing the image, I put its pointer within the undo stack, then I release the NSView (which doesn't get deallocated therefore). Thin way when invoking the undo, I get back all the relashionships that object had with other objects. When saving, I write the image's NSData within the filePackage. When re-loading a file, I read that NSData and create the image. It sounds linear and clean. Good luck to myself. I'll let you know. Regards -- Leonardo > Da: Jens Alfke > Data: Sat, 8 Feb 2014 16:37:01 -0800 > A: Leonardo > Cc: > Oggetto: Re: Managing image loading > > > On Feb 8, 2014, at 3:58 AM, Leonardo wrote: > >> When the user imports a new image, I quickly copy the image to a temporary >> folder, then I add this latest file reference to the document¹s >> NSFileWrapper. >> I just create the file¹s fileWrapper using its URL, so I do not read its >> content and create the fileWrapper by the NSData. > > This seems like a hacky workaround for the kind of temporary storage that > you'd already get from virtual memory. See below. > >> Why don¹t I add the file¹s NSData to the fileWrapper but I add just its URL >> reference? Because I don¹t really know whether the fileWrapper uses the disk >> or keeps the NSData in memory. So in case of a 1GB file I do not engulf the >> app. > > It's a 64-bit app, presumably, so you have no worries about running out of > address space. If physical RAM is running low, then the OS will just write > part of your address space to disk to make room; when you access that address > space again, it'll read it back in. > > Basically the virtual memory system is going to do what your > temporary-file-copying solution would have done, only it's doing it more > efficiently because (a) it only writes it to disk if there's not enough RAM; > (b) it only copies as much of the data as needed; and (c) it'll free up that > disk space automatically later on. > > I think I asked this before, but: Do you already have a running app that is > having performance problems working with large or lots of images? Or are you > simply imagining that your app might run into these problems, without knowing > whether that's true? In the latter case, _especially_ if you're a novice > developer or new to the platform, please put off worrying about performance > until later. > > Jens ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Managing image loading
On Feb 8, 2014, at 3:58 AM, Leonardo wrote: > When the user imports a new image, I quickly copy the image to a temporary > folder, then I add this latest file reference to the document’s NSFileWrapper. > I just create the file’s fileWrapper using its URL, so I do not read its > content and create the fileWrapper by the NSData. This seems like a hacky workaround for the kind of temporary storage that you'd already get from virtual memory. See below. > Why don’t I add the file’s NSData to the fileWrapper but I add just its URL > reference? Because I don’t really know whether the fileWrapper uses the disk > or keeps the NSData in memory. So in case of a 1GB file I do not engulf the > app. It's a 64-bit app, presumably, so you have no worries about running out of address space. If physical RAM is running low, then the OS will just write part of your address space to disk to make room; when you access that address space again, it'll read it back in. Basically the virtual memory system is going to do what your temporary-file-copying solution would have done, only it's doing it more efficiently because (a) it only writes it to disk if there's not enough RAM; (b) it only copies as much of the data as needed; and (c) it'll free up that disk space automatically later on. I think I asked this before, but: Do you already have a running app that is having performance problems working with large or lots of images? Or are you simply imagining that your app might run into these problems, without knowing whether that's true? In the latter case, _especially_ if you're a novice developer or new to the platform, please put off worrying about performance until later. —Jens ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Managing image loading
On Feb 8, 2014, at 3:58 AM, Leonardo wrote: > > I had to scratch my head at managing the undo, but I found a solution here > too. > When the user undo the import of an image, if the images has been never > saved, so it is still within the temporary folder, I just remove the image > file reference from the fileWrapper. Instead, if the image has already been > saved, so it is within the file package, I copy its file to the temporary > folder and remove its reference from the fileWrapper. So when the user saves > the doc, the image file get removed from the doc filePackage. And if the > user invokes the undo, I add the temp image file to the fileWrapper. > It sounds complicated but it works well. This will break. > > Why do I use a temporary folder? Because if the user imports an image file > then he tries to delete the original image file, the OS tells him that he > can¹t delete that file in use. That could be annoying. Except the file *is* in use—a reference to it lives on your undo stack. You seem not to care about data corruption. But it turns out this doesn’t matter, because your NSData will have an open file descriptor on the image file, so deleting it via Finder won’t actually delete the file from disk until the NSData instance is reallocated or your app quits. The only thing that would be problematic would be ejecting the volume the file lives on—the OS should warn about that. So you need to handle the case that the file gets deleted while its data is still on the undo stack. You won't be able to swap the file back into place. See below for how to address that: > Why don¹t I add the file¹s NSData to the fileWrapper but I add just its URL > reference? Because I don¹t really know whether the fileWrapper uses the disk > or keeps the NSData in memory. So in case of a 1GB file I do not engulf the > app. 1. Look up “memory mapping.” You can pass arguments to NSData that control whether it maps the image file. 2. The wonderful thing about virtual memory is that it gets paged out to disk. 3. 64-bit apps have oodles of address space (256TB under the current scheme); dedicating 1GB of that to a memory-mapped image file is not going to be a problem. --Kyle Sluder ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Managing image loading
Thank you Jens. I have found the proper way to manage that. When the user imports a new image, I quickly copy the image to a temporary folder, then I add this latest file reference to the document¹s NSFileWrapper. I just create the file¹s fileWrapper using its URL, so I do not read its content and create the fileWrapper by the NSData. When the users saves the document, automatically the filesWrappers get written to the disk, within the document filePackage. And when I close the document, I remove the temp folder. That¹s fine. I had to scratch my head at managing the undo, but I found a solution here too. When the user undo the import of an image, if the images has been never saved, so it is still within the temporary folder, I just remove the image file reference from the fileWrapper. Instead, if the image has already been saved, so it is within the file package, I copy its file to the temporary folder and remove its reference from the fileWrapper. So when the user saves the doc, the image file get removed from the doc filePackage. And if the user invokes the undo, I add the temp image file to the fileWrapper. It sounds complicated but it works well. Why do I use a temporary folder? Because if the user imports an image file then he tries to delete the original image file, the OS tells him that he can¹t delete that file in use. That could be annoying. Why don¹t I add the file¹s NSData to the fileWrapper but I add just its URL reference? Because I don¹t really know whether the fileWrapper uses the disk or keeps the NSData in memory. So in case of a 1GB file I do not engulf the app. I hope I have designed a good architecture. Regards -- Leonardo Da: Jens Alfke Data: Tue, 4 Feb 2014 11:47:35 -0800 A: Leonardo Cc: Oggetto: Re: Managing image loading On Feb 4, 2014, at 9:03 AM, Leonardo wrote: > - When the user imports a new image, I add its NSData to the NSFileWrapper >[docFileWrapper addRegularFileWithContents:imgData >preferredFilename:@"image.png"]; > and retain the NSImage. So I can draw the NSImage at any time. You don't need an NSFileWrapper for that. I would just use NSFileManager to copy the file, and NSData methods to read/write the file. I have no idea whether NSFileWrapper caches the file contents in memory or not. Jens ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Managing image loading
On Feb 4, 2014, at 9:03 AM, Leonardo wrote: > - When the user imports a new image, I add its NSData to the NSFileWrapper >[docFileWrapper addRegularFileWithContents:imgData >preferredFilename:@"image.png"]; > and retain the NSImage. So I can draw the NSImage at any time. You don't need an NSFileWrapper for that. I would just use NSFileManager to copy the file, and NSData methods to read/write the file. I have no idea whether NSFileWrapper caches the file contents in memory or not. —Jens ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Managing image loading
The images could be of any size and could be thousands. The user decides. If I understood well, since NSImage does caching, I could: - When the user imports a new image, I add its NSData to the NSFileWrapper [docFileWrapper addRegularFileWithContents:imgData preferredFilename:@"image.png"]; and retain the NSImage. So I can draw the NSImage at any time. If the user deletes the image, I release the NSImage and remove its NSData from the fileWrapper. If the user saves the document, NSDocument invokes - (NSFileWrapper*)fileWrapperOfType:(NSString*)typeName error:(NSError**)outError and saves the filePackage (saving the images' NSData previously added to the wrapper). If the user doesn¹t save the document, the filePackage will be left untouched. I strongly hope that the NSFileWrapper does caching too, otherwise I could even end with a fileWrapper large GBs. Does all of that sound good? Regards -- Leonardo Da: Jens Alfke Data: Tue, 4 Feb 2014 07:41:41 -0800 A: Leonardo Cc: Oggetto: Re: Managing image loading On Feb 4, 2014, at 3:05 AM, Leonardo wrote: > My app displays several images on several pages. > Since the app displays one page per time, I would like to optimize the > memory management at loading and displaying the images. It'd be best to explicitly release/free the images for a page when that page stops being displayed. > to reference all the images when opening a document. So, I thought, the > images get really loaded and displayed at the time I select a given page, > and discarded (in the cache) when I change page. Does it really work that > way? I don't know. NSImage is a very high-level API that does a lot of caching behind the scenes, and the AppKit team tends to make subtle changes to its behavior from one release to another. I don't remember seeing anything in the docs that states that an image's pixmap can be purged to make room. (And the image itself doesn't know when the app changes pages, so changing pages won't itself trigger any cleanup.) If you're concerned about memory usage, NSImage is not the best API to use. You can get more control by using NSImageRepresentation directly, and even more by using CGImage. On the other hand, how large are these images? (Do the math: byte usage = pixel height x pixel width x 4.) How many pages do you expect documents to have? Is memory really a concern when people's computers have gigabytes of RAM and (often) very fast SSDs? Remember, "Premature optimization is the root of all evil." > Second question. In case the user imports a new image, I presume I should > immediately copy the image file within the filePackage then call > initByReferencingFile. No, you wait until told to save changes to the document. Consider what happens if the user decides to close without saving, or revert, or to Save As to a different file. I'm not sure of the answer to your file-wrapper question; that's not an API I've used much. Jens ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Managing image loading
On Feb 4, 2014, at 3:05 AM, Leonardo wrote: > My app displays several images on several pages. > Since the app displays one page per time, I would like to optimize the > memory management at loading and displaying the images. It'd be best to explicitly release/free the images for a page when that page stops being displayed. > to reference all the images when opening a document. So, I thought, the > images get really loaded and displayed at the time I select a given page, > and discarded (in the cache) when I change page. Does it really work that > way? I don't know. NSImage is a very high-level API that does a lot of caching behind the scenes, and the AppKit team tends to make subtle changes to its behavior from one release to another. I don't remember seeing anything in the docs that states that an image's pixmap can be purged to make room. (And the image itself doesn't know when the app changes pages, so changing pages won't itself trigger any cleanup.) If you're concerned about memory usage, NSImage is not the best API to use. You can get more control by using NSImageRepresentation directly, and even more by using CGImage. On the other hand, how large are these images? (Do the math: byte usage = pixel height x pixel width x 4.) How many pages do you expect documents to have? Is memory really a concern when people's computers have gigabytes of RAM and (often) very fast SSDs? Remember, "Premature optimization is the root of all evil." > Second question. In case the user imports a new image, I presume I should > immediately copy the image file within the filePackage then call > initByReferencingFile. No, you wait until told to save changes to the document. Consider what happens if the user decides to close without saving, or revert, or to Save As to a different file. I'm not sure of the answer to your file-wrapper question; that's not an API I've used much. —Jens ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Managing image loading
My app displays several images on several pages. Since the app displays one page per time, I would like to optimize the memory management at loading and displaying the images. I thought to save my document as filePackage, put the image files within the package and use the lazy image = [[NSImage alloc] initByReferencingFile:path]; to reference all the images when opening a document. So, I thought, the images get really loaded and displayed at the time I select a given page, and discarded (in the cache) when I change page. Does it really work that way? Second question. In case the user imports a new image, I presume I should immediately copy the image file within the filePackage then call initByReferencingFile. Should I use imgFileWrap = [[NSFileWrapper alloc] initWithURL:url options: NSFileWrapperReadingWithoutMapping error:&err]; [documentFileWrapper addFileWrapper: imgFileWrap]; or should I simply copy the file image within the filePackage with the following? [[NSFileManager defaultManager] copyItemAtPath:src toPath:dst error:nil]; Regards -- Leonardo ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com