尽管 "hasStrings" 为真,但 UIPasteBoard "string" 属性 返回 nil

UIPasteBoard "string" property returning nil despite "hasStrings" being true

我使用以下代码来抓取用户从应用程序外部复制到剪贴板的文本,以便他们可以将其粘贴到应用程序中:

UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];

if ([pasteboard hasStrings])
{
    NSString *text = pasteboard.string;
}

这一直运行良好,直到 iOS14 我注意到我一直在崩溃,因为 pasteboard.stringnil,尽管 hasStrings 是真的。

我查看了文档,发现 pasteboard.string 确实有可能是 nil:

The value stored in this property is an NSString object. The associated array of representation types is UIPasteboardTypeListString, which includes type kUTTypeUTF8PlainText. Setting this property replaces all current items in the pasteboard with the new item. If the first item has no value of the indicated type, nil is returned.

我的意思是剪贴板中有某种不是 kUTTypeUTF8PlainText 的字符串,这就是为什么 pasteboard.stringnil,但这是正确的解释吗?

我只是对这里到底发生了什么感到困惑,并且不确定如果我遇到 pasteboard.stringnil 的情况应该告诉我的用户什么?

-[UIPasteboard hasStrings] == YES 仅表示粘贴板中的项目具有 public.utf8-plain-text 类型或表明它是字符串的任何其他类型。

但是 -[UIPasteboard string] 仍然可以 return nil 如果 class NSString 的对象不能从 itemProviders 提供的任何数据构造。

这是一个重现您所处情况的示例:

首先实现一个符合NSItemProviderWriting

的测试class
#import <Foundation/Foundation.h>

static NSString *const UTTypeUTF8PlainText = @"public.utf8-plain-text";

@interface TestObject : NSObject <NSItemProviderWriting>

@end

@implementation TestObject

- (NSData *)randomDataWithLength:(NSUInteger)length {
    NSMutableData *data = [NSMutableData dataWithLength:length];
    SecRandomCopyBytes(kSecRandomDefault, length, data.mutableBytes);
    return data;
}

#pragma mark - NSItemProviderWriting

+ (NSArray<NSString *> *)writableTypeIdentifiersForItemProvider {
    return @[UTTypeUTF8PlainText];
}

- (nullable NSProgress *)loadDataWithTypeIdentifier:(nonnull NSString *)typeIdentifier forItemProviderCompletionHandler:(nonnull void (^)(NSData * _Nullable, NSError * _Nullable))completionHandler {
    // random data that an utf8 string may not be constructed from
    NSData *randomData = [self randomDataWithLength:1];
    completionHandler(randomData, nil);
    return nil;
}

@end

然后将测试对象放入粘贴板

if (@available(iOS 11.0, *)) {
    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
    TestObject *item = [TestObject new];
    [pasteboard setObjects:@[item]];
    
    if ([pasteboard hasStrings]) {
        // text may be nil
        NSString *text = pasteboard.string;
    }
}