从 NSPasteBoard 存储和检索自定义 object

Storing and retrieving a custom object from NSPasteBoard

我有一个属于这个 class 的 object,其中包含以下声明:

HEADER

@interface MyClassObject : NSObject <NSCopying, NSPasteboardWriting, NSPasteboardReading>

@property (nonatomic, strong) NSArray *children;
@property (nonatomic, assign) NSInteger type;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) id node;

children 包含此 class 的其他 object,node 包含可以是 NSView 或 [=15 的 object =].

我希望能够复制并粘贴 object 这种类型 to/from NSPasteboard

我身边有 google 但解释很模糊。

我应该怎么做才能使这个 class copiable/readable 成为 NSPasteboard 或者换句话说,使其符合 NSPasteboardWritingNSPasteboardReading 协议?

我完全不知道这是如何完成的,而且和往常一样,Apple 文档和任何东西都不是一回事。

我只讨论写作。阅读基本上是一样的(但当然是相反的;))

  1. 声明你写的类型

    - (NSArray *)writableTypesForPasteboard:(NSPasteboard *)pasteboard {
        return @[@"com.mycompany.mytype"];
    }
    
  2. 写入数据

    - (id)pasteboardPropertyListForType:(NSString *)type {
        //check the type we are asked to write
        if(![type isEqualToString:@"com.mycompany.mytype"]) return nil;    
    
        //create a _plist_ object
        // :: ONLY PLIST TYPES
        NSMutableDictionary *plist = [[NSMutableDictionary alloc] init];
    
        ...
    
        return plist;
    }
    

这是完整的解决方案。

首先是让 class 也符合 NSCoding。在这种情况下,class 声明将是

@interface MyClassObject : NSObject <NSCopying, NSPasteboardWriting, NSPasteboardReading, NSCoding>

要使其与 NSCoding 兼容,您必须实施 encodeWithCoder:initWithCoder:... 在我的例子中:

- (void)encodeWithCoder:(NSCoder *)coder {

  [coder encodeObject:@(self.type) forKey:@"type"];
  [coder encodeObject:self.name forKey:@"name"];
  // converting the node to NSData... 
  // the object contained in node must be compatible with NSCoding
  NSData *nodeData = [NSKeyedArchiver archivedDataWithRootObject:self.node];
  [coder encodeObject:nodeData forKey:@"node"];

  NSData *childrenData = [NSKeyedArchiver archivedDataWithRootObject:self.children];
  [coder encodeObject:childrenData forKey:@"children"];

}

- (id)initWithCoder:(NSCoder *)coder {

  self = [super init];

  if (self) {

    _type = [[coder decodeObjectForKey:@"type"] integerValue];
    _name = [coder decodeObjectForKey:@"name"];

    NSData *nodeData = [coder decodeObjectForKey:@"node"];
    _efeito = [NSKeyedUnarchiver unarchiveObjectWithData:nodeData];

    NSData *childrenData = [coder decodeObjectForKey:@"children"];
    _children = [NSKeyedUnarchiver unarchiveObjectWithData:childrenData];
    _parent = nil;  // I want this to be nil when the object is recreated
  }

要使 class 与 NSPasteboard 一起工作,您必须添加这 4 个方法:

-(id)initWithPasteboardPropertyList:(id)propertyList ofType:(NSString *)type {
  return [NSKeyedUnarchiver unarchiveObjectWithData:propertyList];
}


+(NSArray *)readableTypesForPasteboard:(NSPasteboard *)pasteboard {
    // I am using the bundleID as a type  
    return @[[[NSBundle mainBundle] bundleIdentifier]];
}

- (NSArray *)writableTypesForPasteboard:(NSPasteboard *)pasteboard {
  // I am using the bundleID as a type  
  return @[[[NSBundle mainBundle] bundleIdentifier]];
}


- (id)pasteboardPropertyListForType:(NSString *)type {
  // I am using the bundleID as a type  
  if(![type isEqualToString:[[NSBundle mainBundle] bundleIdentifier]]) {
    return nil;
  }

  return [NSKeyedArchiver archivedDataWithRootObject:self];
}

然后,在 class 上执行您添加的复制和粘贴:

- (void)copy:(id)sender {

  NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
  [pasteBoard clearContents];

  NSArray *copiedObjects = @[theObjectYouWantToCopyToThePasteboard];
  [pasteBoard writeObjects:copiedObjects];

}

- (void)paste:sender {

  NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
  NSArray *classArray = @[[LayerObject class]];
  NSDictionary *options = [NSDictionary dictionary];

  BOOL ok = [pasteboard canReadItemWithDataConformingToTypes:@[[[NSBundle mainBundle] bundleIdentifier]]];

  if (ok) {
    NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options];
    MyObjectClass *object = [objectsToPaste objectAtIndex:0];

    // object is the one you have copied to the pasteboard
    // now you can do whatever you want with it.
    // add the code here.    
  }
}