Frage

Ich lerne Cocoa Programmierung, und ich bin nicht in der Lage, herauszufinden, wie zu Archiv und unarchive eine benutzerdefinierte NSView Unterklasse

Ich habe ein Spielzeug Antrag gestellt, die ein Fenster präsentiert. Dieses Fenster eine Instanz meiner benutzerdefinierten BackgroundView Klasse enthält (archiviert die xib-Datei). Ein Klick überall in diesem BackgroundView erstellt und zeigt ein blaues Quadrat, dessen Ursprung der Klickpunkt. Dieser Platz ist eine Instanz meiner Klasse Square. All dies funktioniert, wie ich erwartet.

The Square-Klasse implementiert das NSCoding Protokoll. Ich habe hinzugefügt dataOfType: typename: Fehler: und readfromData: ofType: Fehler: Methoden zur MyDocument Klasse. Soweit ich aus den Log-Anweisungen sagen kann, die Quadrate werden in die Datei archiviert und aus dem Archiv entfernt, wenn die Datei geladen ist. Aber ich bin nicht in der Lage die Plätze selbst machen Anzeige auf das Fenster. The Square Klasse drawWithRect: Methode nie aufgerufen wird, obwohl ich setNeedsDisplay genannt. JA auf jedem Quadrat

Der Code lautet wie folgt:

Square.h
#import <Cocoa/Cocoa.h>
@interface Square : NSView <NSCoding> {
}
@end

Square.m
#import "Square.h"
@implementation Square

- (id)initWithFrame:(NSRect)frame {
   self = [super initWithFrame:frame];
   return self;
}

- (void)drawRect:(NSRect)rect {
       [[NSColor blueColor] set];
       NSBezierPath *newPath = [NSBezierPath bezierPathWithRect:[self bounds]];
       [newPath fill];
}

-(void)encodeWithCoder:(NSCoder *)coder
{
       [coder encodeRect:[self frame] forKey:@"frame"];
}

-(id)initWithCoder:(NSCoder *)coder
{
       NSRect theRect = [coder decodeRectForKey:@"frame"];
       self = [super initWithFrame:theRect];
       return self;
}
@end
-----
BackgroundView.h
#import <Cocoa/Cocoa.h>
@interface BackgroundView : NSView {
}
@end

BackgroundView.m
#import "BackgroundView.h"
#import "Square.h"
@implementation BackgroundView

- (id)initWithFrame:(NSRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
       // Initialization code here.
   }
   return self;
}

- (void)drawRect:(NSRect)rect {
       for (Square *subview in self.subviews)
               [subview setNeedsDisplay:YES];
}

-(void)mouseDown:(NSEvent *)theEvent {
       NSPoint unsetClick = [theEvent locationInWindow];
       NSPoint theClick = [self convertPoint:unsetClick fromView:nil];
       NSRect theRect;
       theRect.origin = theClick;
       theRect.size.width = 100.00;
       theRect.size.height = 100.00;
       Square *newSquare = [[Square alloc] initWithFrame:theRect];
       [self addSubview:newSquare];
       [newSquare setNeedsDisplay:YES];
}
@end
------
MyDocument.h
#import <Cocoa/Cocoa.h>
@class BackgroundView;

@interface MyDocument : NSDocument
{
       IBOutlet BackgroundView *theBackgroundView;
}
@end

MyDocument.m
#import "MyDocument.h"

@implementation MyDocument

- (id)init
{
   self = [super init];
   return self;
}

- (NSString *)windowNibName
{
   return @"MyDocument";
}

- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
   [super windowControllerDidLoadNib:aController];
}

- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
   return [NSKeyedArchiver
archivedDataWithRootObject:[theBackgroundView subviews]];
   if ( outError != NULL ) {
               *outError = [NSError errorWithDomain:NSOSStatusErrorDomain
code:unimpErr userInfo:NULL];
       }
       return nil;
}

- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName
error:(NSError **)outError
{
   [theBackgroundView setSubviews:[NSKeyedUnarchiver
unarchiveObjectWithData:data]];
   [theBackgroundView setNeedsDisplay:YES];
   if ( outError != NULL ) {
               *outError = [NSError errorWithDomain:NSOSStatusErrorDomain
code:unimpErr userInfo:NULL];
       }
   return YES;
}

@end
War es hilfreich?

Lösung

Da-Platz eine Unterklasse von NSView ist, und NSView implementiert auch NSCoding, müssen Sie Super-Implementierung von sowohl encodeWithCoder aufzurufen: und initWithCoder:.

@implementation Square
- (id)initWithFrame:(NSRect)frame
{
    return [super initWithFrame:frame];
}

-(id)initWithCoder:(NSCoder *)coder
{
    if ((self = [super initWithCoder:coder]))
    {
        NSRect theRect = [coder decodeRectForKey:@"frame"];
        self = [super initWithFrame:theRect];
        return self;
    }
}

- (void)encodeWithCoder:(NSCoder *)coder
{
    [super encodeWithCoder:coder];
    [coder encodeRect:[self frame] forKey:@"frame"];
}

- (void)drawRect:(NSRect)rect
{
    [[NSColor blueColor] set];
    [[NSBezierPath bezierPathWithRect:[self bounds]] fill];
}
@end

Andere Tipps

Wie ich sehe, dass Sie nicht hinzufügen, eine der initWithXXX und encodeWithXXX Methoden, da Sie keine benutzerdefinierten Elementvariablen verfügen.

Ich schlage vor, Apples Sketch Beispiel .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top