Как отобразить неархивированные пользовательские объекты NSView - PullRequest
1 голос
/ 27 мая 2009

Я изучаю программирование на Какао и не могу понять, как архивировать и разархивировать пользовательский подкласс NSView

Я сделал игрушечное приложение, которое представляет окно. Это окно содержит экземпляр моего пользовательского класса BackgroundView (архивируется в XIB-файл). Щелчок в любом месте этого BackgroundView создает и отображает синий квадрат, источником которого является точка щелчка. Этот квадрат экземпляр моего квадратного класса. Все это работает, как я ожидаю.

Класс Square реализует протокол NSCoding. Я добавил dataOfType: typeName: ошибка: и readfromData: ofType: ошибка: методы в класс MyDocument. Насколько я могу судить по операторам журнала, Квадраты архивируются в файл и разархивируются, когда файл загружен. Но я не могу заставить квадратики отображаться на окно. DrawWithRect: метод класса Square никогда не вызывается, хотя я вызывал setNeedsDisplay: YES на каждом квадрате.

Код выглядит следующим образом:

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

Ответы [ 2 ]

4 голосов
/ 13 апреля 2011

Поскольку Square является подклассом NSView, а NSView также реализует NSCoding, вам необходимо вызвать реализацию super для обоих encodeWithCoder: и 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
0 голосов
/ 27 мая 2009

Как я вижу, вы не добавляете ни один из методов initWithXXX и encodeWithXXX, поскольку у вас нет пользовательских переменных-членов.

Предлагаю проверить Пример эскиза Apple .

...