最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

objective c - Cocoa app refuses to save document in user selected file format (export) - Stack Overflow

programmeradmin3浏览0评论

I'm trying to modernize a 20+ year old cocoa/objective-c application. It is document-based and it can read/write its own data to file, but the user can also choose saveAs… to export the document in standard formats (not read by the app).

From the (somewhat confusing) documentation I got the impression that an accessory panel shouldn't be needed to achieve this, given the correct information in Info.plist.

I was expecting the user to pick a file format in the save panel and that that selection would be passed as the type when -dataOfType:error: is invoked. However, type is always the document's native type, regardless of the choice in the save panel.

I'm trying this out on a toy project with a vanilla document based project with the following changes:

Info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ".0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDocumentTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>LSHandlerRank</key>
            <string>Default</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>net.sourcefe.foo</string>
            </array>
            <key>NSDocumentClass</key>
            <string>Document</string>
        </dict>
    </array>
    <key>UTExportedTypeDeclarations</key>
    <array>
        <dict>
            <key>UTTypeConformsTo</key>
            <array>
                <string>public.data</string>
            </array>
            <key>UTTypeIcons</key>
            <dict/>
            <key>UTTypeIdentifier</key>
            <string>net.sourcefe.foo</string>
            <key>UTTypeTagSpecification</key>
            <dict>
                <key>public.filename-extension</key>
                <array>
                    <string>foo</string>
                </array>
            </dict>
        </dict>
    </array>
    <key>UTImportedTypeDeclarations</key>
    <array>
        <dict>
            <key>UTTypeConformsTo</key>
            <array>
                <string>public.plain-text</string>
            </array>
            <key>UTTypeDescription</key>
            <string>Example Text</string>
            <key>UTTypeIdentifier</key>
            <string>com.example.plain-text</string>
            <key>UTTypeTagSpecification</key>
            <dict>
                <key>public.filename-extension</key>
                <array>
                    <string>exampletext</string>
                </array>
            </dict>
        </dict>
        <dict>
            <key>UTTypeConformsTo</key>
            <array>
                <string>net.daringfireball.markdown</string>
            </array>
            <key>UTTypeIcons</key>
            <dict/>
            <key>UTTypeIdentifier</key>
            <string>com.example.mrkdwn</string>
            <key>UTTypeTagSpecification</key>
            <dict>
                <key>public.filename-extension</key>
                <array>
                    <string>mrkdwn</string>
                </array>
            </dict>
        </dict>
    </array>
</dict>
</plist>

Document.m

+ (BOOL)autosavesInPlace {
    return NO;
}

+ (NSArray *)writableTypes {
    return @[
        @"net.sourcefe.foo",
        @"com.example.plain-text",
        @"com.example.mrkdwn",
        @"net.daringfireball.markdown"
    ];
}

- (BOOL) prepareSavePanel:(NSSavePanel *) savePanel {
    savePanel.allowedContentTypes = @[
        [UTType typeWithIdentifier:@"com.example.plain-text"],
        [UTType typeWithIdentifier:@"net.sourcefe.foo"],
        [UTType typeWithIdentifier:@"com.example.mrkdwn"],
    ];
    savePanel.showsContentTypes = YES;
    return true;
}

- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
    NSLog(@"typeName: %@", typeName);
    return nil;
}

Obviously I'm doing something wrong. Either I´m interpreting the docs wrong (and this approach is totally insane) or there is something not quite right in the Info.plist and/or the code. Any hints to what is going on here would be much appreciated.

I'm trying to modernize a 20+ year old cocoa/objective-c application. It is document-based and it can read/write its own data to file, but the user can also choose saveAs… to export the document in standard formats (not read by the app).

From the (somewhat confusing) documentation I got the impression that an accessory panel shouldn't be needed to achieve this, given the correct information in Info.plist.

I was expecting the user to pick a file format in the save panel and that that selection would be passed as the type when -dataOfType:error: is invoked. However, type is always the document's native type, regardless of the choice in the save panel.

I'm trying this out on a toy project with a vanilla document based project with the following changes:

Info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleDocumentTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>LSHandlerRank</key>
            <string>Default</string>
            <key>LSItemContentTypes</key>
            <array>
                <string>net.sourcefe.foo</string>
            </array>
            <key>NSDocumentClass</key>
            <string>Document</string>
        </dict>
    </array>
    <key>UTExportedTypeDeclarations</key>
    <array>
        <dict>
            <key>UTTypeConformsTo</key>
            <array>
                <string>public.data</string>
            </array>
            <key>UTTypeIcons</key>
            <dict/>
            <key>UTTypeIdentifier</key>
            <string>net.sourcefe.foo</string>
            <key>UTTypeTagSpecification</key>
            <dict>
                <key>public.filename-extension</key>
                <array>
                    <string>foo</string>
                </array>
            </dict>
        </dict>
    </array>
    <key>UTImportedTypeDeclarations</key>
    <array>
        <dict>
            <key>UTTypeConformsTo</key>
            <array>
                <string>public.plain-text</string>
            </array>
            <key>UTTypeDescription</key>
            <string>Example Text</string>
            <key>UTTypeIdentifier</key>
            <string>com.example.plain-text</string>
            <key>UTTypeTagSpecification</key>
            <dict>
                <key>public.filename-extension</key>
                <array>
                    <string>exampletext</string>
                </array>
            </dict>
        </dict>
        <dict>
            <key>UTTypeConformsTo</key>
            <array>
                <string>net.daringfireball.markdown</string>
            </array>
            <key>UTTypeIcons</key>
            <dict/>
            <key>UTTypeIdentifier</key>
            <string>com.example.mrkdwn</string>
            <key>UTTypeTagSpecification</key>
            <dict>
                <key>public.filename-extension</key>
                <array>
                    <string>mrkdwn</string>
                </array>
            </dict>
        </dict>
    </array>
</dict>
</plist>

Document.m

+ (BOOL)autosavesInPlace {
    return NO;
}

+ (NSArray *)writableTypes {
    return @[
        @"net.sourcefe.foo",
        @"com.example.plain-text",
        @"com.example.mrkdwn",
        @"net.daringfireball.markdown"
    ];
}

- (BOOL) prepareSavePanel:(NSSavePanel *) savePanel {
    savePanel.allowedContentTypes = @[
        [UTType typeWithIdentifier:@"com.example.plain-text"],
        [UTType typeWithIdentifier:@"net.sourcefe.foo"],
        [UTType typeWithIdentifier:@"com.example.mrkdwn"],
    ];
    savePanel.showsContentTypes = YES;
    return true;
}

- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
    NSLog(@"typeName: %@", typeName);
    return nil;
}

Obviously I'm doing something wrong. Either I´m interpreting the docs wrong (and this approach is totally insane) or there is something not quite right in the Info.plist and/or the code. Any hints to what is going on here would be much appreciated.

Share Improve this question asked Mar 20 at 20:41 user1007047user1007047 506 bronze badges 3
  • Which method does "Save As…" call? – Willeke Commented Mar 20 at 22:42
  • It calls -saveDocumentAs:, the full call sequence is saveDocumentAs: -> writableTypes -> prepareSavePanel: -> dataOfType: with type showing up as net.sourcefe.foo regardless of selection. – user1007047 Commented Mar 21 at 6:49
  • Hmm. I think I found the problem, overriding +isNativeType: to return true works. I was assuming (and still suspect) that this property should be obtained from Info.plist, but that is a problem for later. – user1007047 Commented Mar 21 at 8:08
Add a comment  | 

1 Answer 1

Reset to default 1

Here's how to implement Export in the vanilla document based project:

  1. Add the imported file types (with a description) to info.plist

  2. Implement writableTypes

  3. Add a menu item "Export…" and connect it to the First Responder and action saveDocumentTo:

I vaguely remember reading documentation about this somewhere, but I can't find it anymore.

发布评论

评论列表(0)

  1. 暂无评论