I have an object that belongs to this class that contains the following declarations:
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
holds other objects of this class, node
holds objects that can be NSView
or NSImageView
.
I would like to be able to copy and paste objects of this type to/from NSPasteboard
.
I have google around but the explanations are vague.
What should I do to make this class copiable/readable to NSPasteboard or in other words, make it conform to NSPasteboardWriting
and NSPasteboardReading
protocols?
I don't have the slightest clue on how this is done and as usual, Apple documetation and nothing is the same thing.
This is the complete solution.
First thing is to make the class conforming to NSCoding
too. In that case the class declaration will be
@interface MyClassObject : NSObject <NSCopying, NSPasteboardWriting, NSPasteboardReading, NSCoding>
To make it compatible with NSCoding
you have to implement encodeWithCoder:
and initWithCoder:
... in my case:
- (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
}
To make the class work with NSPasteboard you have to add these 4 methods:
-(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];
}
Then, on the class you implement the copy and paste you add:
- (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.
}
}