Lazy Copy Problem


#1

Hi There,

I am trying to implement lazy copying for the challenge and I have come up with the following:

-(void)writeToPasteboard:(NSPasteboard *)pb
{
    //copy data to the pasteboard
    [pb clearContents];
    //create an item to store the image representation
    NSPasteboardItem *item = [[NSPasteboardItem alloc] init];
    //allowed types for pasting
    NSArray *pastetypes = [NSArray arrayWithObjects:NSPasteboardTypePDF,NSPasteboardTypeString, nil];
    [item setDataProvider:self forTypes:pastetypes];
    [pb writeObjects:[NSArray arrayWithObject:item]];
}

-(void)pasteboard:(NSPasteboard *)item provideDataForType:(NSString *)type
{
    [item setData:[self dataWithPDFInsideRect:[self bounds]] forType:NSPasteboardTypePDF];
    [item setString:string forType:NSPasteboardTypeString];

    
}

However, I get the following warning on the setDataProvider:forTypes: method:

"sending ‘BigLetterView *const __strong’ to parameter of incompatible type ‘id’

self is used as the parameter here in the book so I am unsure what I am doing wrong?

Thanks for any assistance,

Adam.


#2

The warning indicates that the @interface for BigLetterView doesn’t say that it conforms to the NSPasteBoardItemDataProvider protocol. If you add that protocol it should work fine.

Adam


#3

[quote=“AdamPreble”]The warning indicates that the @interface for BigLetterView doesn’t say that it conforms to the NSPasteBoardItemDataProvider protocol. If you add that protocol it should work fine.

Adam[/quote]

Thanks for that, it is so obvious once it has been pointed out!

I have completed the challenge now and I am just wondering whether I could have completed it in a better way?

I ended up adding two ‘snapshot’ attributes to the BigLetterView.h interface:

[ul]- snapshot (for the pdf data)[/ul]
[ul]- snapshotString (for the string value)[/ul]

and having the following code in writeToPasteboard: and pasteboard:item:provideDataForType:

-(void)writeToPasteboard:(NSPasteboard *)pb
{
    //copy data to the pasteboard
    [pb clearContents];
    //create an item to store the image representation
    NSPasteboardItem *item = [[NSPasteboardItem alloc] init];
    //allowed types for pasting
    NSArray *pastetypes = [NSArray arrayWithObjects:NSPasteboardTypePDF,NSPasteboardTypeString, nil];
    //create snapshot values
    [self setSnapshot:[self dataWithPDFInsideRect:[self bounds]]];
    [self setSnapshotString:string];
    [item setDataProvider:self forTypes:pastetypes];
    [pb writeObjects:[NSArray arrayWithObject:item]];
    
}
-(void)pasteboard:(NSPasteboard *)pasteboard item:(NSPasteboardItem *)item provideDataForType:(NSString *)type
{
    [item setData:[self snapshot] forType:NSPasteboardTypePDF];
    [item setString:[self snapshotString] forType:NSPasteboardTypeString];   
}

I thought about creating an archive of the required information but I didn’t think it was really necessary or whether it would work?

Thanks again for any advice,

Kind Regards,

Adam.


#4

This looks like it would work fine. Did you intentionally go above and beyond the criteria, by saving the snapshot data? I want to be sure you don’t think that using the “promise” style pasteboard interaction is necessary with NSPasteboardItem.

Adam


#5

Hi Adam,

I’m not really sure what you mean? I was intentionally implementing Lazy Copy and at the top of page 305 it says:

“When implementing a lazy copy, most developers will take some sort of a snapshot of the information when declaring the types”

I thought this is what I was doing?

I realise that you can just implement it the standard way taught in the chapter and I have looked at the sample solution (which makes sense). What I was asking is whether I have implemented the lazy copy/snapshot correctly?

Thanks again,

Adam.


#6

A couple improvements come to mind:

  1. In pasteboard:item:provideDataForType: you should only be writing the data for the requested type, not all types of data.

  2. Also, it would be best to avoid storing the PDF data in a snapshot, since the goal of lazy copying is to avoid doing unnecessary work (and using memory) on the copy operation, postponing it until that actual type is needed. The most straightforward way would be to create a temporary BigLetterView with the snapshotted state and use it to generate the PDF data.

Adam


#7

Thanks for the suggestions for improvement. It is amazing just how obvious things become once you’ve been told! =) I think the version below does what you suggest:

-(void)writeToPasteboard:(NSPasteboard *)pb
{
    //copy data to the pasteboard
    [pb clearContents];
    //create an item to store the image representation
    NSPasteboardItem *item = [[NSPasteboardItem alloc] init];
    //allowed types for pasting
    NSArray *pastetypes = [NSArray arrayWithObjects:NSPasteboardTypePDF,NSPasteboardTypeString, nil];
    //create snapshot value
    [self setSnapshotString:string];
    [item setDataProvider:self forTypes:pastetypes];
    [pb writeObjects:[NSArray arrayWithObject:item]];
    
}

-(void)pasteboard:(NSPasteboard *)pasteboard item:(NSPasteboardItem *)item provideDataForType:(NSString *)type
{
    if ([type isEqualToString:NSPasteboardTypePDF]) {
        //create a temp big letter view
        BigLetterView *tempViewForPDF = [[BigLetterView alloc] initWithFrame:[self bounds]]; 
        //add the snapshot string to the temp view
        tempViewForPDF.string = snapshotString;
        //set the data for the pasteboard
        [item setData:[tempViewForPDF dataWithPDFInsideRect:[tempViewForPDF bounds]] forType:NSPasteboardTypePDF];       
    } else {
        [item setString:[self snapshotString] forType:NSPasteboardTypeString];   
    }
    
}

-(void)pasteboardFinishedWithDataProvider:(NSPasteboard *)pasteboard
{
    //this method is called when the snapshot is no longer required
    [self setSnapshotString:nil];
}

Thanks again,

Adam.