{"id":46730,"date":"2025-02-13T15:14:17","date_gmt":"2025-02-13T20:14:17","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=46730"},"modified":"2025-03-12T10:03:51","modified_gmt":"2025-03-12T14:03:51","slug":"nsdocument-auto-saving-and-file-types","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2025\/02\/13\/nsdocument-auto-saving-and-file-types\/","title":{"rendered":"NSDocument Auto Saving and File Types"},"content":{"rendered":"<p><a href=\"https:\/\/mastodon.social\/@ccgus\/113946895593869933\">Gus Mueller<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@ccgus\/113946895593869933\"><p>Has anyone successfully come up with strategies for opting into <code>NSDocument<\/code>&rsquo;s <code>autosavesInPlace<\/code>, but only for certain file types? I&rsquo;ve looked into overriding <code>scheduleAutosaving<\/code> and friends, but nothing really works. TextEdit just throws up an alert saying &ldquo;hey, lossy file format&rdquo;. Is this the best I can do?<\/p><\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.social\/@bwebster\/113947338916747768\">Brian Webster<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@bwebster\/113947338916747768\">\n<p>The issue is if you Save As where the original file type supports auto save but the new one doesn&rsquo;t (or vice versa). The override is a class method and not an instance method, so there&rsquo;s no way for the existing instance to flip its auto save boolean to reflect the new file type.<\/p>\n<\/blockquote>\n\n<p>This is an interesting API problem. The core issue is that <a href=\"https:\/\/developer.apple.com\/documentation\/appkit\/nsdocument\">NSDocument<\/a> wants you to have a single <a href=\"https:\/\/developer.apple.com\/library\/archive\/documentation\/DataManagement\/Conceptual\/DocBasedAppProgrammingGuideForOSX\/ManagingLifecycle\/ManagingLifecycle.html#\/\/apple_ref\/doc\/uid\/TP40011179-CH4-SW1\">subclass<\/a> for each family of file types that can be mutually converted via <strong>Save As<\/strong>. The configuration is done at the class level, so it assumes that each file type is just a different flavor that works in the same way.<\/p>\n\n<p>One could argue that the Cocoa document architecture is missing several abstractions that would be needed for a proper general solution. The basic stuff both easy and quite configurable, with a small API surface, but to go beyond that you need to reimplement a lot yourself or try to hack it into the desired shape.<\/p>\n\n<p><a href=\"https:\/\/mastodon.social\/@davedelong\/113948093699974151\">Dave DeLong<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@davedelong\/113948093699974151\">\n<p>Override <code>NSDocumentController<\/code> to provide unique <code>NSDocument<\/code> subclasses <em>for each document<\/em> so that each one can swap its own <code>+autosavesInPlace<\/code> method <code>IMP<\/code> without fear of messing up other documents, while also still preserving KVO behavior?<\/p>\n<\/blockquote>\n\n<p id=\"nsdocument-auto-saving-and-file-types-update-2025-03-12\">Update (2025-03-12): <a href=\"https:\/\/shapeof.com\/archives\/2025\/3\/acorn_8.1_is_out.html\">Gus Mueller<\/a>:<\/p>\n<blockquote cite=\"https:\/\/shapeof.com\/archives\/2025\/3\/acorn_8.1_is_out.html\"><p>Autosave has also had a revamp. There are three options now: &ldquo;Off&rdquo;, &ldquo;Native Acorn Images&rdquo;, and &ldquo;All Images&rdquo;. The default is set to saving native images (<code>.acorn<\/code>).<\/p><p>In Acorn 8.0 (and previous versions), when autosave was enabled, non-native files (<code>.jpeg<\/code>, <code>.png<\/code>) would open without a reference to the original file on disk. This is no longer the case in Acorn 8.1, where non-native files open with a reference to the original file, and pressing &#x2318;S will save back to the original, regardless of the autosave setting.<\/p><p>Why the change? I found myself wanting autosaving of files where full fidelity would always be preserved (which is what happens when you save <code>.acorn<\/code> files), but that behavior didn&rsquo;t always make sense when opening a <code>.jpeg<\/code> file. JPEG files are lossy, so opening and saving the image multiple times would degrade the quality of the image. That&rsquo;s not awesome. And you would also lose the edibility of text and layers.<\/p><\/blockquote>","protected":false},"excerpt":{"rendered":"<p>Gus Mueller: Has anyone successfully come up with strategies for opting into NSDocument&rsquo;s autosavesInPlace, but only for certain file types? I&rsquo;ve looked into overriding scheduleAutosaving and friends, but nothing really works. TextEdit just throws up an alert saying &ldquo;hey, lossy file format&rdquo;. Is this the best I can do? Brian Webster: The issue is if [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2025-02-13T20:14:20Z","apple_news_api_id":"8a6c8d18-4bf1-4d25-9855-7551c202274a","apple_news_api_modified_at":"2025-03-12T14:03:53Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAA==","apple_news_api_share_url":"https:\/\/apple.news\/AimyNGEvxTSWYVXVRwgInSg","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[76,69,275,30,2598,760,71,1050],"class_list":["post-46730","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-acorn","tag-cocoa","tag-keyvalueobserving","tag-mac","tag-macos-15-sequoia","tag-objective-c-runtime","tag-programming","tag-textedit"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/46730","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=46730"}],"version-history":[{"count":2,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/46730\/revisions"}],"predecessor-version":[{"id":47029,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/46730\/revisions\/47029"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=46730"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=46730"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=46730"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}